# iOS冰与火之歌 – UAF and Kernel Pwn
**作者:耀刺,蒸米,黑雪 @阿里移动安全**
英文版:[http://translate.wooyun.io/2016/06/12/54.html](http://translate.wooyun.io/2016/06/12/54.html)
0x00 序
======
* * *
冰指的是用户态,火指的是内核态。如何突破像冰箱一样的用户态沙盒最终到达并控制如火焰一般燃烧的内核就是《iOS冰与火之歌》这一系列文章将要讲述的内容。这次给大家带来的是 Use After Free 的漏洞利用方式以及iOS 9.0上如何利用UAF攻击iOS内核的技术。除此以外我们还公布了一个在iOS9.3.2中刚刚被修复的内核堆溢出漏洞,可以用来攻击iOS 9.3.2以下版本的iOS内核并实现iOS Pwn的终极目标 – 越狱。
《iOS冰与火之歌》系列的目录如下:
1. Objective-C Pwn and iOS arm64 ROP
2. 在非越狱的iOS上进行App Hook(番外篇)
3. App Hook答疑以及iOS 9砸壳(番外篇)
4. 利用XPC过App沙盒
5. UAF and Kernel Pwn
另外文中涉及代码可在我的github下载:
[https://github.com/zhengmin1989/iOS_ICE_AND_FIRE](https://github.com/zhengmin1989/iOS_ICE_AND_FIRE)
0x01 Use After Free
===================
* * *
Use After Free简称UAF,是一种常见的堆漏洞利用方式。在Pangu9的越狱中,就是利用了iOS 9内核中的一处UAF漏洞获取了iOS最高权限并完成了越狱。在我们讲这个漏洞之前,可能有很多同学对UAF并不是很了解,所以我们先简单介绍一下什么是UAF以及如何利用UAF漏洞(老鸟的话可以直接跳过这一节)。
我们先来看一段程序(全部源码在github):
“`
class Human
{
public:
virtual void setValue(int value)=0;
virtual int getValue()=0;
protected:
int mValue;
};
class Talker : public Human
{
public:
void setValue(int value){
mValue = value;
}
int getValue(){
mValue += 1;
cout<<"This is Talker's getValue"<
cout<
利用这个思路,我们成功的写出了利用程序,运行程序后,手机会重启,随后在`~/Library/Logs/CrashReporter/MobileDevice/`目录下的panic log中可以看到,我们已经成功的控制了pc指针并指向了0xdeadbeefdeadbeef:
![](http://drops.javaweb.org/uploads/images/fb8fb7fbdefee4d36dc42a3fe264ad391352e5f0.jpg)
对越狱来说,控制了内核的PC指针还只是一个开始,随后还要获取KASLR,利用ROP对内核进行读写,然后对内核进行patch,将签名校验disable等等,因为篇幅原因,这里就不一一介绍了,欢迎继续关注我们以后的文章。
0x03 inpuTbag – 一个影响了苹果设备15年的内核堆溢出漏洞
====================================
* * *
苹果在不久前发布的9.3.2中,修补一个非常典型的内核堆溢出漏洞,该漏洞存在于IOHIDFamily中。配合用户态漏洞触发,该漏洞能绕过内核所有安全机制,转化成内核任意读写,从而完成越狱。有该漏洞的代码最早是在2002年发布的mac os 10.2中引入,几乎影响了Apple全系设备15年之久。
出现漏洞的内核代码如下 ([http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-701.20.10/IOHIDFamily/IOHIDDevice.cpp](http://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-701.20.10/IOHIDFamily/IOHIDDevice.cpp)):
“`
IOHIDDevice::postElementValues(…) {
…
maxReportLength = max(_maxOutputReportSize, _maxFeatureReportSize); – – – – – – – a
report = IOBufferMemoryDescriptor::withCapacity(maxReportLength, kIODirectionNone); – – – – – – – b
…
reportData = (UInt8 *)report->getBytesNoCopy() – – – – – – – c
…
element->createReport(reportID, reportData, &reportLength, &element);//IOHIDElementPrivate::createReport – – – – – – – d
…
}
IOHIDElementPrivate::createReport(…) {
…
writeReportBits( _elementValue->value, /* source buffer */ – – – – – – – e
(UInt8 *) reportData, /* destination buffer */
(_reportBits * _reportCount),/* bits to copy */
_reportStartBit); /* dst start bit */
…
}
“`
代码行-a是漏洞的关键,IOHIDDevice的Report总共有三种类型:Output,Feature,Input;这些Report的Size是在创建IOHIDDevice时用户输入指定。这里只是根据Output,Feature来判断可能最大的Report Size是错误的,因为Input的size可能比OutPut和Feature都大。
代码行-b根据maxReportLength创建内核堆buffer。
代码行-c用来拿到创建的内核堆的buffer指针。
代码行-d是将Report内容保存到代码行-b创建的buffer,那么只要Post的Report类型是Input而且Size >`max(_maxOutputReportSize, _maxFeatureReportSize)`便能成功溢出。
代码行-e 是`createReport ()`的一部分。`writeReportBits()`在report count等于1的情况下等同于memmove操作,将clientMemoryForType中设定的Report内容拷贝到代码行-b创建的Buffer。
因此该漏洞可以从任意kalloc zone,达成任意长度的堆溢出。因为该漏洞是利用inpuT report来攻击iOS内核,再加上Tbag是《越狱》中一个非常有名的角色,所以我们将这个漏洞命名为inpuTbag。
![](http://drops.javaweb.org/uploads/images/850a02eee6c77bdcbbbd4b01f6dd5ae43747c21c.jpg)
0x04 One More Thing – iOS 9.2.1越狱
=================================
* * *
我们已经成功的利用inpuTbag堆溢出漏洞完成了iOS 9.2.1的越狱,如下是越狱的视频和截图 (因为Cydia的安装不太稳定,容易造成白苹果,所以我们的demo改成安装一个未签名的terminal app,并且可以用root权限执行任意指令,并且可以在系统的根目录下创建任意文件):
![null](http://drops.javaweb.org/uploads/images/09a51ac0ec79b505473b160e8f62c6e811764004.jpg)
![null](http://drops.javaweb.org/uploads/images/124bed6fc29ac34964fe9f19291a867d51d5e09b.jpg)
0x05 总结
=======
* * *
这篇文章介绍了Use After Free的漏洞利用方式以及iOS 9.0上如何利用UAF攻击iOS内核的技术。除此以外我们还公布了一个在iOS9.3.2中刚刚被修复的内核堆溢出漏洞,并展示了iOS 9.2.1的越狱。另外文中涉及代码可在我的github下载:
[https://github.com/zhengmin1989/iOS_ICE_AND_FIRE](https://github.com/zhengmin1989/iOS_ICE_AND_FIRE)
0x06 参考资料
=========
* * *
1. Hacking from iOS 8 to iOS 9, POC 2015
请登录后查看评论内容