2017年1月6日

mach portal漏洞利用的一些细节

前不久GP0的研究员Ian Beer公布了针对iOS 10.1.1的漏洞细节及利用代码,通过结合三个漏洞获取设备的root shell。之后意大利研究员@qwertyoruiopz在此基础上加入绕过KPP保护的漏洞利用并发布了完整的iOS10越狱

Ian Beer已经对漏洞的成因和利用做了相关描述,这里将不再阐述,而是介绍一些利用的细节以及可能的改进建议。

整个exploit chain包含了三个漏洞:

  • CVE-2016-7637 用于替换了launchd进程中往com.apple.iohideventsystem发消息的port
  • CVE-2016-7661 造成powerd崩溃重启,从而在接管com.apple.iohideventsystem后获取powerd的task port,进而获取host_priv
  • CVE-2016-7644 导致内核port的UAF,进一步获取kernel_task

替换launchd中的port

内核中的ipc_object对象对应到用户态下是一个name(int类型),每个进程的ipc_space_t中保存了name与object之间的映射关系。相关代码可以在ipc_entry.c中查看,ipc_entry_lookup函数将返回name对应的ipc_entry_t结构,其中保存了对应的object。name的高24位是table中的索引,而低8位是generation number(初始值是-1,增加步长是4,因此一共有64个值)

#define    MACH_PORT_INDEX(name)       ((name) >> 8)
#define    MACH_PORT_GEN(name)     (((name) & 0xff) << 24)
#define    MACH_PORT_MAKE(index, gen)  \
        (((index) << 8) | (gen) >> 24)

被释放的name会被标记到freelist的起始位置,当再创建的时候会有相同的索引号,但是generation number会增加4,因此当被重复释放和分配64次后会返回给用户态完全相同的name,从而可以完成劫持。

#define    IE_BITS_GEN_MASK    0xff000000  /* 8 bits for generation */
#define    IE_BITS_GEN(bits)   ((bits) & IE_BITS_GEN_MASK)
#define    IE_BITS_GEN_ONE     0x04000000  /* low bit of generation */
#define IE_BITS_NEW_GEN(old)   (((old) + IE_BITS_GEN_ONE) & IE_BITS_GEN_MASK)

简单的测试代码

    for (int i=0; i<65; i++)
    {
        mach_port_t port = 0;
        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
        printf("port index:0x%x gen:0x%x\n", (port >> 8), (port & 0xff));
        mach_port_destroy(mach_task_self(), port);
    }

(更多…)