这是ZDI评选的2018年五大漏洞的第四个案例,这些评选出来的bug具有一些独特的元素,使得其与今年发布的大约1400条其他报告不同。今天我们来看另一个Pwn2Own上的赢家,这次攻击的对象的是macOS。
在2018年Pwn2Own大赛上,MWR实验室成功地攻破了苹果Safari浏览器。漏洞利用首先利用了SVG对象处理中的堆溢出漏洞,然后利用Dock中的未初始化指针达到沙箱逃逸的目的。由于未初始化数据是我最喜欢的一种漏洞,所以由我来向大家介绍这个在沙箱逃逸过程中用到的漏洞。该漏洞的编号是ZDI-18-781/CVE-2018-4196。
在mac操作系统中,可以通过名为“com.apple.dock.server”的Mach服务来访问Dock,这些函数大量使用HIServices框架提供的序列化功能。该漏洞是在DSSetDesktopForDisplayAndSpace函数中,当以96548为ID发送一个Mach消息时触发的。
我们先来看看DSSetDesktopForDisplayAndSpace函数是什么样子的:
这只是函数的开始部分,但是我们可以看到在调用 _UnserializeCFType 之前,堆栈上已经初始化了一些变量。这个函数存在于HIServices中,我们也来看看它:
这看起来并不是很有趣,但我们还是来深入探讨一下,这是AXUnserializeCFType函数:
该函数首先检查了第四个参数是否大于等于8,如果是,它将初始化第五个参数,使其指向NULL,然后尝试基于数据的类型进行反序列化操作。如果反序列化过程没有出现错误,则指向新创建对象的指针将存储在第五个参数中。
你发现什么了吗?我们换种方式来看看DSSetDesktopForDisplayAndSpace函数的开头,可能看起来能更加明显:
这和我们刚开始看的汇编代码是一样的,包括所有变量的初始化。现在你能看到问题了吗?作为UnserializeCFType函数参数的栈上变量从未被初始化,只有当UnserializeCFType的第二个参数大于等于8时,才初始化该指针将其转换为AXUnserializeCFType类型。紧接着,对这个栈变量调用objc_autorelease函数,这个函数和使用autorelease选择器有相同的效果。因此,如果我们可以控制栈上的变量,我们就可以控制执行代码。
MWR团队通过使用了一个包含push rbx指令的函数利用了这一点,该指令可以和未初始化的栈变量的偏移量对齐,当该指令执行时,rbx寄存器会指向Mach消息中的40个字节,这非常适合我们用来控制objhttps://www.zerodayinitiative.com/advisories/ZDI-17-237/c_autorelease最终将操作的指针对象。
总共有8个函数包括了易受攻击的代码逻辑,它们也在未初始化第4个参数或未检查返回值的情况下调用了_UnserializeCFType函数。不过也有几个函数中使用了正确的代码,在正确的案例中,它们检查了_UnserializeCFType函数的返回值以确保函数执行成功,并且作为参数传递的堆栈变量被初始化为NULL。
在2016年,lokihardt公布了ZDI-16-282作为他的攻击微软Edge浏览器利用链的一部分,其中利用了在处理‘Array.concat’函数时的一个未初始化堆栈变量。2017年,360安全团队公布了ZDI-17-237作为VMware Workstation中从客户机逃逸到宿主机操作系统漏洞的一部分。有关该漏洞的详细信息,可以查看Abdul-Aziz Hariri的博客。
希望你对这个在Pwn2Own中常出现的漏洞类型感兴趣,由未初始化数据造成的漏洞是我最喜欢的漏洞种类之一,看到其他人利用它们来实现代码执行是十分有趣的。
你可以关注我的Twitter@WanderingGlitch,或者关注我们的团队以了解最新的漏洞利用技术和安全补丁。请继续关注将于明天发布的最后一篇年度五大漏洞相关博客。