基于PEGASUS(Trident三叉戟)的OS X 10.11.6本地提权
0x00 序
这段时间最火的当属阿联酋的*活动人士被apt攻击所使用的ios pegasus(又称trident三叉戟)0day漏洞了。为了修复该漏洞,苹果专门发布了一个ios 9.3.5版本。这个漏洞的厉害之处在于可以直接从沙盒内对内核进行攻击(无需沙盒逃逸),并且同时影响ios(9.3.4)和os x (10.11.6)。因此,本篇文章将会从pegasus漏洞形成的原因开始分析,然后一步一步教大家写出os x上利用pegasus提权的攻击代码。
《ios冰与火之歌》这一系列文章的目录如下:
objective-c pwn and ios arm64 rop
在非越狱的ios上进行app hook(番外篇)
app hook答疑以及ios 9砸壳(番外篇)
利用xpc过app沙盒
uaf and kernel pwn
基于pegasus(三叉戟)的os x 10.11.6本地提权 (番外篇)
另外文中涉及代码可在我的github下载: https://github.com/zhengmin1989/ios_ice_and_fire
0x01 漏洞分析
pegasus(三叉戟)实际上是由三个漏洞组成,分别是:
cve-2016-4657:safari的webkit内核上的内存破坏漏洞。
cve-2016-4655:内核信息泄露漏洞,可用于绕过kaslr。
cve-2016-4656:内核uaf漏洞,可用于控制内核并执行任意代码。
关于cve-2016-4657目前还没有公开的资料,但stefan esser和pangu分别爆出了另外两个漏洞cve-2016-4655和cve-2016-4656的细节。利用已经曝光的这两个漏洞,其实已经可以做到ios非完美越狱和os x本地提权了。下面我们就来讲解一下这两个漏洞形成的原因以及如何利用。
0x02 cve-2016-4655 内核信息泄露
cve-2016-4655这个漏洞形成的原因是内核在序列化和反序列化osnumber的时候没有验证长度的正确性。因此,如果我们将number的长度设置的非常长,并用io_registry_entry_get_property()去获取number数据的话,就会造成内核的信息泄露。
我们知道内核栈中会保存函数的返回地址,因此我们可以利用这个返回地址去计算出内核的kslide,从而攻破kaslr的保护。
那么如何编写利用代码呢?我们先创建一个序列化后的dictionary。对内核来说,这个dictionary应该是这样的:喎? f/ware/vc/"="" target="_blank" class="keylink">vcd4ncjxwcmugy2xhc3m9"brush:java;">
但是我们对osnumber的长度进行了修改,变成了0x200:
uint32_t data[] = { 0x000000d3, 0x81000001, 0x08000004, 0x006e696d, 0x84000200, //change the length of osnumber 0x41414141, 0x41414141 };
发送这个给内核后,内核在反序列化的时候就会出现错误。随后我们使用io_registry_entry_get_property_bytes()这个用户态函数就可以获取到内核返回的数据了。
因为我们修改了os number的长度,所以返回的数据不光有我们发送给内核的number,还有栈上数据,比如函数ret时候的返回地址-0xffffff80003934bf。
通过这个地址我们就可以计算出来kslide了。
0x03 cve-2016-4656 内核代码执行
cve-2016-4656这个漏洞其实有两种触发uaf的方法,我们这里先讲比较简单的那一种(两种方法在stefan esser的文章中都有介绍)。简单uaf漏洞形成的原因是osunserializebinary支持用osstring和ossymbol来作为key,并且支持用osobject去引用之前的key。但是osstring和ossymbol不一样的地方在于,osstring key转换为ossymbol的过程中osstring已经被free掉了,但这个osstring却被加入了对象列表里。
因此当我们osobject类型去引用一个已经被释放了的osstring的时候,就会产生uaf崩溃:
通过汇编崩溃的位置我们可以找到源码对应的位置是在341行创建osobject对象的时候:
因此,如果我们能够在osstring被free的时候,立刻申请一段和osstring一样大小的内存并且构造好对应的vtable数据,当程序执行到osobject创建的时候,内核就能成功的被我们控制。
那么如何编写利用代码呢?我们还是先创建一个序列化后的dictionary。对内核来说,这个dictionary应该是这样的:
a true b vtable data...1
内核随后会解析这个dictionary,正如我们之前分析的,osstring-”a”在创建完后就被free掉了,这时候,我们立刻创建ossymbol-”b”以及和osstring-”a”大小相同的osdata,就可以在osstring-”a” free后重新控制这块内存,随后当内核使用osobject引用osstring-”a”,并调用retain()函数的时候,其实就是在调用我们已经控制的vtable了。
0x04 利用rop提权
首先我们先申请一块内存来放vtable和rop chain,在os x上有一种取巧的方法,如果我们是32位的程序的话,可以使用null page。因此,我们先用vm_allocate()申请到null page,然后将vtable和rop chain都保存在null page里:
随后在os x上用rop提权的代码我们可以直接使用tpwn的:首先获得当前进程的ucred,然后将cr_svuid设置为0,最后用thread_exception_return退出进程。
0x05 测试exp
编写完代码后,我们来尝试执行一下我们的exp。
首先说一下测试环境:mac os x ei capitan 10.11.6 (15g31),在没有安装2016-01的security update的情况下(这时候内核相当于ios 9.3.4,如果安装完2016-01 update就相当于ios 9.3.5)。
接下来我们编译一下我们的exp:
clang -framework iokit -framework foundation -framework corefoundation -m32 -wl,-pagezero_size,0 -o3 exp.m lsym.m -o exp
然后运行:
可以看到我们已经成功的获取了root权限。
0x06 总结
这篇文章介绍了如何利用pegasus(trident三叉戟)做到内核信息泄露以及内核代码执行,然后利用rop获取root权限。另外,因为pegasus(trident三叉戟)同时存在于ios和os x,有兴趣的同学可以在我们发布的攻击代码的基础上,尝试一下ios攻击代码的编写。
基于pegasus(trident三叉戟)的os x 10.11.6本地提权exp的下载地址:https://github.com/zhengmin1989/os-x-10.11.6-exp-via-pegasus
喎?>上一篇: Windows10系统下查看mysql的端口号并修改
下一篇: 严谨的理科生是不会相信一见钟情