回归最本质的信息安全

PEGASUS iOS内核漏洞分析(第二部分)

2016年9月12日发布

2,034
0
0

导语:Apple公司早在今年5月份就为了UAF漏洞修补过一次OSUnserializeBinary(),但是这个补丁是用来修补CVE-2016-1828漏洞的。

背景

上次介绍了PEGASUS IOS内核漏洞之后,又发现了几个新的问题:

1. Apple公司早在今年5月份就为了UAF漏洞修补过一次OSUnserializeBinary(),但是这个补丁是用来修补CVE-2016-1828漏洞的。
2. 我们描述的UAF触发方法在iOS9和 OSX 10.11之前版本的代码中并不存在。

获知这两个细节后,我们决定对我们的分析做一个小的更新。

The old code

退后一步看看iOS 9和OS X 10.11之前版本的OSUnserializeBinary()代码。

从上述代码中可以看出,iOS 9.0 和OS 10.11之前版本的字典键必须是OSSymbol对象。并且OSString代码路径还没有添加。这意味着我们分析中提到的UAF方法在老版本的代码中无法实现。此外,仔细查看这段代码并与我们的分析比较后,可以发现老版本中调用setObject()时只有2个参数,而不是3个。这是因为上述代码在CVE-2016-1828的补丁之前就存在。

现在仔细地看一下上述代码,并找出触发UAF的代码路径。

Trigger 1

在这段代码中,触发UAF的第一种方法就是利用CVE-2016-1828:

1. 398行代码会设置字典键k1为对象o1
2. 这会使o1和k1的引用计数器加1(变成2)
3. 399行处对象o1被释放,它的引用计数器减小到1
4. 400行处对象k1(sym)被释放,它的引用计数器减小到1
5. 此时由于字典保持了对两个对象的引用,没有任何问题
6. 当下一个对象o2被逆序列化并插入字典后,重用相同的键k1时,398行的setObject()方法会在字典中用o2替换o1。在替换的时候o1的引用计数器从0减少到1
7. 此时o1被从内存中释放。如果此时逆序列器重新尝试产生一个指向这个对象的引用,就会造成UAF。

Trigger 2

在这段代码中,触发UAF的第二种方法可能就是PEGASUS(CVE-2016-4656)真正用到的方法:

1. 如果我们正在插入的对象o是对dict本身的一个引用,389行代码则不会调用setObject()
2. 如果setObject()没有被执行,o和sym的引用计数器永远不会增加
3. 399行代码将会减小o的引用计数器到大于或等于1的值(因为它是对dict的引用)
4. 400行代码最多将会减小sym的引用计数器到0(如果symbol是奇怪的字符串)
5. 此时,OSSymbol对象sym被销毁
6. 此后创建任何指向对象sym的引用都是UAF

可以看到,在iOS 9 和 OS X 10.11之前版本的代码中早已存在两个单独但又相关的UAF触发代码路径。这意味着加上Part1中描述的,在仅仅20行代码中就已经有3个UAF触发代码路径。

The fixes

Apple公司5月份发布的CVE-2016-1828漏洞补丁中对这段代码唯一的改变是增加了调用setObject()时的第3个参数ture

if (o != dict) ok = dict->setObject(sym, o, true);

当代码中出现错误时,就会重写已经设定的字典键,因此Brandon Azad提到的UAF情形便不能再被触发。不幸的是Apple公司认为这样已经足够好了,所以他们没有及时对OSUnserializeBinary()进行代码安全检查。不然的话,一个熟练的代码审计员一定会意识到代码中有大量对release()的直接调用。这可以被用来从objsArray中释放对象,从而触发UAF。这种仅仅给setObject添加第三个参数ture不是一个完美的修复方法。

Apple没有对他们的安全补丁进行安全审计,又或者说相关责任人没有查看函数中的其它release()调用。因此这20行代码中的其它两种UAF触发方法仍然存在,并能控制内核执行渗透系统的操作。PEGASUS被发现后,Apple花了很多精力去修复这20行代码。他们废除CVE-2016-1828的补丁,并重写函数使其不再调用任何release()(除了对错误和临时变量的清理),从而在函数的最后、返回结果之前,所有的对象从objsArray中得到释放。这样反序列化时引用计数器永远不会下降到0。

Conclusion

在过去的两周内,许多安全专家都称赞苹果对PEGASUS的快速反应。这一赞扬是因为有关方面不对独立的第三方研究人员开放样本,并且没有透露该内核漏洞的详细信息给公众。没有这些信息,公众只是简单地认为PEGASUS使用的是全新的内核漏洞来控制iOS设备。然而逆向PEGASUS使用的内核漏洞后,发现了一个完全不同的画面:

仅仅因为2016年5月Apple修复CVE-2016-1828漏洞时没有对问题代码进行安全审计,导致CVE-2016-4656内核漏洞仍然存在。仅仅20行代码中就存在3条代码路径可以触发UAF。尽管这些release()方法离得很近,但是Apple只修复了其中一条路径。此外,从对PEGASUS补丁的分析可以看出,只需要稍微修改一下代码就能够同时修复这3个问题。这可以被认为是一个非常严重的疏忽:修补工作并有在BrandonAzad提出UAF后就立刻展开。如果Apple公司用不同于之前的方式修补CVE-2016-4656漏洞,那么CVE-2016-1828漏洞将不会被滥用。

​本文翻译于sektioneins,如若转载,请注明来源于嘶吼: http://www.4hou.com/technology/2086.html

点赞 0
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

Change

Change

嘶吼编辑

发私信

发表评论