voucher_swap:利用iOS 12中的MIG引用计数
字数 1803 2025-08-27 12:33:31
iOS MIG引用计数漏洞分析与利用:CVE-2019-6225
漏洞概述
CVE-2019-6225是XNU内核中task_swap_mach_voucher()函数存在的MIG引用计数漏洞,允许攻击者在iOS 12.1.2上构建虚假内核任务端口,实现任意内核内存读写。该漏洞由Brandon Azad和Qihoo 360 Vulcan Team的Qixun Zhao(@S0rryMybad)独立发现。
MIG语义背景
MIG(Mach Interface Generator)是生成Mach消息解析代码的工具,其语义规则如下:
- 成功情况:MIG服务例程获取所有传入资源的所有权
- 失败情况:MIG服务例程不获取传入资源的所有权
然而,实际实现中存在更复杂的场景,如semaphore_destroy()总是消耗信号量引用,无论成功与否,这表明MIG语义比传统描述更为复杂。
漏洞分析
task_swap_mach_voucher()实现
kern_return_t task_swap_mach_voucher(
task_t task,
ipc_voucher_t new_voucher,
ipc_voucher_t *in_out_old_voucher)
{
if (TASK_NULL == task)
return KERN_INVALID_TASK;
*in_out_old_voucher = new_voucher;
return KERN_SUCCESS;
}
该实现存在两个引用计数问题:
- 引用泄漏:
in_out_old_voucher的输入值是task_swap_mach_voucher拥有的凭证引用,但被无条件覆盖而没有先调用ipc_voucher_release() - 引用消耗:
new_voucher不归task_swap_mach_voucher()所有,但它在in_out_old_voucher的输出值中返回
漏洞利用原语
- 引用计数泄漏:使用凭证作为第三个参数调用
task_swap_mach_voucher()可泄漏凭证对象的引用计数 - 引用计数减少:将凭证作为第二个参数可减少凭证对象的引用计数
Mach凭证结构
struct ipc_voucher {
iv_index_t iv_hash; /* checksum hash */
iv_index_t iv_sum; /* checksum of values */
os_refcnt_t iv_refs; /* reference count (1-0x0fffffff) */
iv_index_t iv_table_size; /* size of the voucher table */
iv_index_t iv_inline_table[IV_ENTRIES_INLINE];
iv_entry_t iv_table; /* table of voucher attr entries */
ipc_port_t iv_port; /* port representing the voucher */
queue_chain_t iv_hash_link; /* link on hash chain */
};
关键字段:
iv_refs:32位引用计数,范围1-0x0fffffffiv_port:指向表示该凭证的ipc_port对象
漏洞利用步骤
1. 存储凭证指针
- 调用
thread_set_mach_voucher()存储凭证引用 - 使用漏洞删除添加的引用
- 在用户空间取消分配凭证端口以释放凭证
2. 重新分配已释放凭证
- 强制区域GC
- 使用外线端口描述符重新分配:
- 发送包含外线端口描述符的Mach消息
- 确保
iv_port字段被NULL覆盖 iv_refs与真实Mach端口的低32位重叠
3. 获取凭证端口
- 调用
thread_get_mach_voucher():- 如果
iv_port非NULL,直接返回该端口 - 如果
iv_port为NULL,分配新凭证端口
- 如果
4. 修改引用计数
- 再次使用漏洞修改
iv_refs字段 - 改变外线基本端口指针,使其指向其他位置
5. 获取任意内存发送权
- 接收包含外线端口的Mach消息
- 获得解释为
ipc_port的任意内存发送权
完整利用技术
管道缓冲区技术
- 使基本端口位于内核内存中的管道缓冲区前
- 泄漏凭证引用以增加外线端口数组中的基本端口指针
- 使其指向管道缓冲区
- 通过读取/写入重叠管道的文件描述符直接操作伪
ipc_port内存
获取内核读/写
-
初始读取原语:
- 将端口转换为伪任务端口
- 使伪任务的
bsd_info指向目标内存 - 调用
pid_for_task()读取bsd_info->p_pid
-
定位管道缓冲区:
- 在虚假端口上调用
mach_port_request_notification() - 读取基本端口地址并计算管道缓冲区地址
- 在虚假端口上调用
-
完整内核任务:
- 在管道缓冲区内构建伪内核任务
- 使用
mach_vm_allocate()分配内核内存 - 编写新的伪内核任务
- 修改进程的
ipc_entry表中的伪端口指针
缓解措施影响
iOS 12引入的os_refcnt_t限制(1-0x0fffffff)影响了利用可靠性:
- 基本端口地址的低32位必须在有效范围内
- 在早期iOS版本中,该漏洞利用更加可靠
时间线
- 2018年12月6日:向Apple报告
- 2018年12月19日:iOS 12.1.3 beta修复
- 快速修复表明该漏洞可能已被其他研究人员发现
总结
该漏洞展示了:
- MIG语义的复杂性及其安全影响
- 占位符代码引入安全漏洞的风险
- 引用计数缓解措施对利用可靠性的影响
利用技术的关键在于精确控制凭证引用计数和巧妙的内存重用,最终构建完全可控的内核任务端口。