Retme的未来道具研究所

世界線の収束には、逆らえない

漏洞介绍: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-2094

http://wangcong.org/blog/archives/2274

漏洞补丁:

static int perf_swevent_init(struct perf_event *event)

{
-  int event_id = event->attr.config;
+ u64 event_id = event->attr.config;

   if (event->attr.type != PERF_TYPE_SOFTWARE)

          return -ENOENT; 

patch就这一句,乍一看很难看出有什么利用点。但是其实int 换 uint是很敏感的,很有可能是一个整数溢出,还得往下看。以下分析来源于不爱补漏洞的mtk 源码

static int perf_swevent_init(struct perf_event *event)
{
    int event_id = event->attr.config;

......
    if (event_id >= PERF_COUNT_SW_MAX)
        return -ENOENT;

    if (!event->parent) {
        int err;

        err = swevent_hlist_get(event);
        if (err)
            return err;

        static_key_slow_inc(&perf_swevent_enabled[event_id]);
        event->destroy = sw_perf_event_destroy;
    }

    return 0;
}

这里面,event_id是一个int,但是仅仅校验id是否超过最大值,如果传入一个负值,将造成 perf_swevent_enabled这个全局数组越界

但是即使越界也不一定能使用,还要看是否对越界部分的内存做了修改,但是看这个static_key_slow_inc的名字,显然是做了加法,但是还要看是怎么加的,有没有什么限制。

perf_swevent_enabled这个全局数组的成员结构,就一个4字节的结构,这个api就是单纯的+1.那么就是说,只要我们使用sys_perf_event_open这个系统调用,就能将这个值加1

struct static_key {
atomic_t enabled;
};

static inline void static_key_slow_inc(struct static_key *key)
{
    atomic_inc(&key->enabled);
}

但是要想把它利用成“任意地址写”,还要解决几个问题:

  1. 利用地址范围问题:
    对于写入小于perf_swevent_enabled的地址,可以随意构造,event_id 就是(addr - perf_swevent_enabled)/4
    对于大于perf_swevent_enabled的地址,需要加一个负数位,来绕开PERF_COUNT_SW_MAX的限制,也就是【(addr - perf_swevent_enabled)/4】 | 0x80000000

2.每个进程调用sys_perf_event_open次数的限制
因为每一次调用sys_perf_event_open,都会开一个fd,fd最大就到1000,所以要分子进程调用sys_perf_event_open,每个调用980次
另外,当fd关闭或者进程推出时,会自动调用sw_perf_event_destroy()进行释放,
这里的event_id是个u64,所以释放的时候还就没这个问题了,那么用户态的某个内存值会遭殃,这也是使用子进程的原因。

static void sw_perf_event_destroy(struct perf_event *event)
{
    u64 event_id = event->attr.config;  
    WARN_ON(event->parent);
    static_key_slow_dec(&perf_swevent_enabled[event_id]);
    swevent_hlist_put(event);
}

3.我们要修改的地方,原始地址必须是0,因为我们只能作加法,不知道修改位置的原始值,所以

可以考虑替换ptmx_fops_fsync 这个指针,这个指针为空,替换后再对ptmx调用fsync

poc实现代码可以参考 https://github.com/android-rooting-tools/android_run_root_shell 的perf_event部分


评论已关闭