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消息解析代码的工具,其语义规则如下:

  1. 成功情况:MIG服务例程获取所有传入资源的所有权
  2. 失败情况: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;
}

该实现存在两个引用计数问题:

  1. 引用泄漏in_out_old_voucher的输入值是task_swap_mach_voucher拥有的凭证引用,但被无条件覆盖而没有先调用ipc_voucher_release()
  2. 引用消耗new_voucher不归task_swap_mach_voucher()所有,但它在in_out_old_voucher的输出值中返回

漏洞利用原语

  1. 引用计数泄漏:使用凭证作为第三个参数调用task_swap_mach_voucher()可泄漏凭证对象的引用计数
  2. 引用计数减少:将凭证作为第二个参数可减少凭证对象的引用计数

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-0x0fffffff
  • iv_port:指向表示该凭证的ipc_port对象

漏洞利用步骤

1. 存储凭证指针

  1. 调用thread_set_mach_voucher()存储凭证引用
  2. 使用漏洞删除添加的引用
  3. 在用户空间取消分配凭证端口以释放凭证

2. 重新分配已释放凭证

  1. 强制区域GC
  2. 使用外线端口描述符重新分配:
    • 发送包含外线端口描述符的Mach消息
    • 确保iv_port字段被NULL覆盖
    • iv_refs与真实Mach端口的低32位重叠

3. 获取凭证端口

  1. 调用thread_get_mach_voucher()
    • 如果iv_port非NULL,直接返回该端口
    • 如果iv_port为NULL,分配新凭证端口

4. 修改引用计数

  1. 再次使用漏洞修改iv_refs字段
  2. 改变外线基本端口指针,使其指向其他位置

5. 获取任意内存发送权

  1. 接收包含外线端口的Mach消息
  2. 获得解释为ipc_port的任意内存发送权

完整利用技术

管道缓冲区技术

  1. 使基本端口位于内核内存中的管道缓冲区前
  2. 泄漏凭证引用以增加外线端口数组中的基本端口指针
  3. 使其指向管道缓冲区
  4. 通过读取/写入重叠管道的文件描述符直接操作伪ipc_port内存

获取内核读/写

  1. 初始读取原语

    • 将端口转换为伪任务端口
    • 使伪任务的bsd_info指向目标内存
    • 调用pid_for_task()读取bsd_info->p_pid
  2. 定位管道缓冲区

    • 在虚假端口上调用mach_port_request_notification()
    • 读取基本端口地址并计算管道缓冲区地址
  3. 完整内核任务

    • 在管道缓冲区内构建伪内核任务
    • 使用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修复
  • 快速修复表明该漏洞可能已被其他研究人员发现

总结

该漏洞展示了:

  1. MIG语义的复杂性及其安全影响
  2. 占位符代码引入安全漏洞的风险
  3. 引用计数缓解措施对利用可靠性的影响

利用技术的关键在于精确控制凭证引用计数和巧妙的内存重用,最终构建完全可控的内核任务端口。

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() 实现 该实现存在两个引用计数问题: 引用泄漏 : 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凭证结构 关键字段: iv_refs :32位引用计数,范围1-0x0fffffff iv_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语义的复杂性及其安全影响 占位符代码引入安全漏洞的风险 引用计数缓解措施对利用可靠性的影响 利用技术的关键在于精确控制凭证引用计数和巧妙的内存重用,最终构建完全可控的内核任务端口。