Project Zero:突破音频屏障第一部分:使用Mach消息对CoreAudio进行模糊测试
作者:Dillon Franke,高级安全工程师,20%时间参与Project Zero项目
每秒钟,高权限的MacOS系统守护进程都会接收和处理数百个IPC消息。在某些情况下,这些消息处理程序会从沙箱化或无特权进程接收数据。
在本博客文章中,我将探讨使用Mach IPC消息作为攻击向量来发现和利用沙箱逃逸。我将详细介绍如何使用自定义模糊测试工具、动态插桩以及大量调试/静态分析来识别coreaudiod系统守护进程中的高风险类型混淆漏洞。在此过程中,我将讨论遇到的一些困难和权衡。
方法:知识驱动的模糊测试
对于这个研究项目,我采用了结合模糊测试和手动逆向工程的混合方法,我称之为知识驱动的模糊测试。这种方法平衡了自动化与针对性调查。模糊测试提供了快速测试各种输入并识别系统行为偏离预期区域的手段。然而,当模糊测试器的代码覆盖率停滞不前或出现特定障碍时,手动分析就会发挥作用,迫使我更深入地研究目标的内部工作原理。
知识驱动的模糊测试有两个关键优势。首先,研究过程永远不会停滞,因为提高模糊测试器代码覆盖率的目标始终存在。其次,实现这一目标需要深入了解正在模糊测试的代码。当你开始分类真正与安全相关的崩溃时,逆向工程过程将使你对代码库有广泛的了解,从而能够从知情角度分析崩溃。
识别攻击向量
标准浏览器沙箱通过限制直接操作系统访问来限制代码执行。因此,利用浏览器漏洞通常需要使用单独的"沙箱逃逸"漏洞。
由于进程间通信(IPC)机制允许两个进程相互通信,它们自然可以作为从沙箱化进程到无限制进程的桥梁。这使它们成为沙箱逃逸的主要攻击向量。
我选择了Mach消息,这是MacOS操作系统中最低级别的IPC组件,作为本研究的重点攻击向量。我选择它们主要是因为我想在最核心层面理解MacOS IPC机制,以及Mach消息在历史上的安全问题记录。
选择目标
在决定研究Mach服务后,下一个问题是选择哪个服务作为目标。为了让沙箱化进程向服务发送Mach消息,必须明确允许。如果进程使用Apple的应用沙箱功能,这是在.sb文件中完成的,使用TinyScheme格式编写。
最终,我选择查看coreaudiod守护进程,特别是com.apple.audio.audiohald服务,原因如下:
- 这是一个复杂的进程
- 它允许来自多个有影响力应用程序的Mach通信,包括Safari GPU进程
- Mach服务有大量的消息处理程序
- 该服务似乎允许控制和修改音频硬件,这可能需要提升权限
- coreaudiod二进制文件及其大量使用的CoreAudio框架都是闭源的,这将提供独特的逆向工程挑战
创建模糊测试工具
一旦选择了攻击向量和目标,下一步就是创建一个能够通过攻击向量(Mach消息)在目标内适当位置发送输入的模糊测试工具。
覆盖引导的模糊测试器是一个强大的武器,但只有当它的能量集中在正确的地方时才能发挥作用——就像放大镜聚焦阳光来生火一样。没有适当的聚焦,能量就会消散,影响甚微。
确定入口点
理想情况下,模糊测试器应该完美复制潜在攻击者可用的环境和能力。然而,这并不总是实用的。通常需要做出权衡,例如为了提高性能、简化插桩或易于开发而接受更高的误报率。
直接工具方法
虽然需要更多前期工作,但另一个选择是编写一个直接加载和调用感兴趣的Mach消息处理程序的模糊测试工具。这将具有将我们的模糊测试器和插桩放在与消息处理程序相同的进程中的巨大优势,使我们能够更容易地获得代码覆盖率。
这种方法的一个显著缺点是它假设所有模糊测试器生成的输入都通过了内核的Mach消息验证层,在真实系统中,这发生在消息处理程序被调用之前。然而,在我看来,在同一进程空间中进行模糊测试的优点(速度和易于收集代码覆盖率)超过了潜在增加误报的缺点。
寻找Mach消息处理程序
首先,我搜索了Mach服务标识符com.apple.audio.audiohald,但在coreaudiod二进制文件中没有找到对其的引用。接下来,我使用otool检查了它加载的库。从逻辑上讲,CoreAudio框架似乎是容纳我们消息处理程序代码的良好候选者。
事实证明,这是由于使用了Mach接口生成器(MIG),这是Apple的一种接口定义语言,通过抽象掉大部分Mach层,使编写RPC客户端和服务器变得更加容易。编译时,MIG消息处理代码被捆绑到一个称为子系统的结构中。
创建基本模糊测试工具
在确定了要模糊测试的函数后,下一步是编写一个程序来读取文件并将文件内容作为输入传递给目标函数。这可能是将CoreAudio库与我的模糊测试工具链接并调用_HALB_MIGServer_server函数那么简单,但不幸的是,该函数没有被导出。
相反,我借用了Ivan Fratric及其TinyInst工具的一些逻辑,该工具从库中返回提供的符号地址。该代码解析Mach-O二进制文件的结构,特别是它们的头部和加载命令,以定位和提取符号信息。这使得即使目标函数没有被导出,也能在我的模糊测试工具中解析和调用目标函数。
模糊测试并产生崩溃
有了小型种子语料库和输入传递机制,下一步是配置模糊测试器以使用创建的模糊测试工具并获取代码覆盖率。我使用了由Ivan Fratric构建和维护的优秀Jackalope模糊测试器。我选择Jackalope主要是因为它高度可定制——它允许轻松实现自定义变异器、插桩和样本传递。
迭代模糊测试工具
这个工具很快产生了许多崩溃,表明我走在了正确的轨道上。然而,我很快了解到,最初的崩溃通常并不表示安全漏洞,而是模糊测试工具本身的设计缺陷或无效假设。
迭代1:目标初始化
我的模糊测试方法的一个困难是,我的目标函数(Mach消息处理程序)期望HAL系统处于特定状态才能开始接收Mach消息。通过简单地使用我的模糊测试工具调用库函数,这些假设被打破了。
迭代2:API调用链
我的第一个模糊测试工具很酷,但它做了一个相当大的假设:所有可访问的Mach消息处理程序都彼此独立运行。我很快了解到这个假设是错误的。
迭代3:模拟有错误/不需要的功能
有时覆盖率会停滞不前,模糊测试器难以探索新的代码路径。例如,假设我们正在模糊测试一个HTTP服务器,但它一直卡住,因为它试图在启动时读取和解析配置文件。如果我们的重点是服务器的请求解析和响应逻辑,我们可能会选择模拟我们不关心的功能,以便将模糊测试器的代码覆盖率探索集中在其他地方。
迭代4:改进样本结构
以模糊测试为中心的审计技术的一个优点是,它突出了你正在审计的代码中的知识差距。当你解决这些差距时,你会更深入地了解模糊测试工具应生成的输入的结构和约束。这些见解使你能够改进工具以产生更有针对性的输入,有效渗透更深的代码路径并提高整体代码覆盖率。
漏洞
经过多次模糊测试工具迭代、lldb"下一条指令"命令以及使我的MacBook Pro过热的时间后,我终于开始对CoreAudio框架有了理解并产生了一些有意义的崩溃。
硬件抽象层(HAL)
com.apple.audio.audiohald Mach服务公开了一个称为硬件抽象层(HAL)的接口。HAL允许客户端与操作系统上的音频设备、插件和设置进行交互,在coreaudiod进程中表示为类型为HALS_Object的C++对象。
一个有趣的崩溃
每当我的模糊测试器产生崩溃时,我总是花时间充分理解崩溃的根本原因。通常,崩溃与安全无关(即NULL解引用),但充分理解崩溃背后的原因帮助我更好地理解目标和我的模糊测试器所做的无效假设。最终,当我确实识别出与安全相关的崩溃时,我已经对它们周围的上下文有了很好的理解。
哪里出了问题
导致崩溃的操作表明,在获取的HALS_Object的偏移量0x68处,代码期望有一个指向带有vtable的对象的指针。然后代码将在vtable中查找一个函数,该函数大概会检索对象的"工作组端口"。
当获取的对象类型为ioct(IOContext)时,一切正常。然而,我的模糊测试器生成的测试输入导致函数获取了不同类型的HALS_Object,这导致了无效的函数调用。
这种漏洞类型被称为类型混淆,其中易受攻击的代码假设检索到的对象或结构是特定类型,但可能提供不同的类型。对象的内存布局可能完全不同,这意味着内存访问和vtable查找可能发生在错误的位置,甚至超出边界。类型混淆漏洞可能非常强大,因为它们能够形成可靠的利用。
受影响的功能
_XIOContext_Fetch_Workgroup_Port Mach消息处理程序并不是唯一一个假设它正在处理ioct对象而不检查类型的函数。
创建概念验证
因为我的模糊测试工具连接在Mach消息处理过程的下游,所以构建一个使用mach_msg API向coreaudiod中的易受攻击消息处理程序发送Mach消息的端到端概念验证非常重要。
Apple如何修复问题
我在2024年10月9日向Apple报告了此类型混淆漏洞。它于2024年12月11日修复,分配了CVE-2024-54529,并在MacOS Sequoia 15.2、Sonoma 14.7.2和Ventura 13.7.2中引入了补丁。
Apple的修复很简单:由于每个HALS对象都包含有关其类型的信息,补丁在受影响的函数中添加了一个检查,以确保在解引用对象和执行函数调用之前获取的对象是ioct类型。
建议
为防止将来出现类似的类型混淆漏洞,Apple应考虑修改CopyObjectByObjectID函数(或任何其他对对象类型做出假设的函数)以包含类型检查。这可以通过将预期的对象类型作为参数传递并在返回之前验证获取的对象的类型来实现。
结论
这篇博客文章描述了我进入MacOS漏洞研究和模糊测试世界的旅程。我希望我已经展示了知识驱动的模糊测试方法如何允许快速原型设计和迭代、对目标的深入理解以及高影响力的错误。
在我的下一篇文章中,我将详细介绍我尝试利用CVE-2024-54529的经验。