ZDI年度五大漏洞第四弹——让指针指向你想要的对象
字数 1399 2025-08-29 08:31:35
macOS Dock 服务未初始化指针漏洞分析 (ZDI-18-781/CVE-2018-4196)
漏洞概述
本漏洞是2018年Pwn2Own大赛中MWR实验室攻破苹果Safari浏览器的沙箱逃逸漏洞,编号为ZDI-18-781/CVE-2018-4196。该漏洞存在于macOS Dock服务中,涉及未初始化指针的使用,最终导致任意代码执行。
漏洞背景
- 漏洞类型:未初始化指针漏洞
- 影响组件:macOS Dock服务
- 利用场景:Safari浏览器沙箱逃逸
- 发现者:MWR实验室
- 相关CVE:CVE-2018-4196
- 漏洞价值:Pwn2Own大赛获胜漏洞
技术细节
1. 攻击面分析
macOS中的Dock服务通过Mach服务"com.apple.dock.server"提供接口,这些函数大量使用HIServices框架提供的序列化功能。
2. 漏洞触发点
漏洞在DSSetDesktopForDisplayAndSpace函数中触发,当发送ID为96548的Mach消息时:
; 函数开始部分
; 在调用_UnserializeCFType之前,堆栈上已经初始化了一些变量
3. 关键函数分析
_UnserializeCFType函数
该函数存在于HIServices框架中,其伪代码如下:
if (第四个参数 >= 8) {
初始化第五个参数为NULL;
尝试基于数据类型进行反序列化;
if (反序列化成功) {
将新创建对象的指针存储在第五个参数中;
}
}
DSSetDesktopForDisplayAndSpace函数
该函数的关键问题在于:
- 传递给
UnserializeCFType函数的栈上变量未被初始化 - 只有当
UnserializeCFType的第二个参数≥8时,才会初始化指针 - 随后对该栈变量调用
objc_autorelease函数
4. 漏洞原理
漏洞的根本原因是:
- 未初始化的栈变量被直接传递给
objc_autorelease - 攻击者可以控制栈上的内容,从而控制被释放的指针
- 通过精心构造的Mach消息,可以控制代码执行流程
5. 利用技术
MWR团队通过以下方式利用该漏洞:
- 使用包含
push rbx指令的函数进行利用 - 该指令与未初始化栈变量的偏移量对齐
- 执行时,
rbx寄存器指向Mach消息中的40个字节 - 控制
objc_autorelease最终操作的指针对象
6. 相关函数
共有8个函数包含类似的易受攻击代码逻辑:
- 未初始化第4个参数
- 或未检查返回值的情况下调用
_UnserializeCFType函数
正确的实现应:
- 检查
_UnserializeCFType函数的返回值 - 确保函数执行成功
- 将作为参数传递的堆栈变量初始化为NULL
历史相关漏洞
-
ZDI-16-282 (2016年)
- 发现者:lokihardt
- 影响:Microsoft Edge浏览器
- 利用链:处理'Array.concat'函数时的未初始化堆栈变量
-
ZDI-17-237 (2017年)
- 发现者:360安全团队
- 影响:VMware Workstation
- 效果:客户机逃逸到宿主机操作系统
漏洞防护建议
- 对所有指针变量进行初始化
- 严格检查函数返回值
- 对Mach消息进行严格的边界检查
- 使用安全的序列化/反序列化实践
- 启用现代编译器的安全特性(如自动初始化)
总结
该漏洞展示了未初始化指针在macOS系统服务中的危险性,特别是在Mach服务交互场景下。通过精心构造的Mach消息,攻击者可以控制程序执行流程,最终实现沙箱逃逸。这类漏洞在Pwn2Own等高级攻击场景中经常出现,需要开发者特别注意内存安全编程实践。