当前位置: 首页 > 科技观察

macOS二进制plist解析漏洞分析

时间:2023-03-13 04:29:08 科技观察

属性表文件(Plist)是一种文件形式,通常用于存储用户设置,也可以用于存储捆绑信息。此功能由提供的旧MacOS中的资源分支提供。由于Plist中存储的数据是抽象的,因此它可能采用不止一种文件格式。macOS看起来很有趣,尤其是属性列表(plists),它是存储序列化对象的文件,在Apple操作系统中很常见,类似于MicrosoftWindows使用注册表存储配置数据的方式。macOSApplicationAutomator的基于xml的示例属性列表如下所示。该属性列表存储应用程序的版本信息以及其他有用的数据,如下所示:属性列表也可以是二进制形式,否则称为bplist。顾名思义,这些是二进制格式的属性列表,可以启用许多其他对象类型和关系,包括字典。这是一个示例bplist,它由bplist00标记标识,尽管使用其他标记可能支持其他版本的格式:它可以工作。Apple开源代码中定义的bplist格式如下:二进制plist格式属性列表为模糊测试提供了一个有趣的目标,因为它们很容易被操作系统的许多部分创建和使用,包括更高特权的进程。Apple的开源代码允许我创建任意bplist并开始混淆文件格式,同时使用内置的macOSplutil命令行工具确保语法正确。我花了几天时间生成bplists来强制格式,并很快发现某些对象类型被常见的macOS二进制文件(如Finder)以及更高权限的二进制文件(包括LaunchServicesDaemon(LSD))使用它导致异常,而解析。系统崩溃日志表明CoreFoundation框架中存在漏洞,但是,正如我们稍后将看到的,该漏洞存在于多个位置。CoreFoundation(简称CF)是MacOS和iOS中的一组C语言API,由一些底层例程和包装函数组成。Apple发布的最大的CF开源项目称为CFLite。基于CFLite,可以开发跨MacOSX、Linux和Windows平台的应用程序。另一个名为OpenCFLite的第三方开源实现具有相同的功能。大多数CoreFoundation例程的对象通常遵循这个命名规则,例如:CFDictionaryRef出现在以CFDictionary开头的函数中,这些对象通常通过CFRetain和CFRelease手动管理。在内部,CoreFoundation还将一些原始类型转换为Objective-C运行时可用的格式。大多数生成的崩溃似乎是由CoreFoundation解析bplist然后尝试使用创建的对象的方式引起的。bplist的ObjectTable中任何非字符串类型的对象(Date、Data、Bool等)在调用不存在的字符串相关选择器时都会导致解析过程崩溃。因此,任何使用CoreFoundation读取属性列表的进程都可能因无法识别的选择器异常而崩溃。下面是一个易受攻击的代码路径示例:使用以下C代码和一个名为Info.plist的恶意属性列表(位于与测试应用程序相同的目录中)可以轻松实现此路径:可以通过编程方式或通过修改bplist的方式进行崩溃分析放在系统上自动分析它为这个漏洞生成崩溃,实际上这个漏洞的第一个迹象是当LSD反复击中我的系统崩溃时。Objective-See有一篇很棒的博客文章,详细介绍了通过LSD进行应用程序注册和属性列表的自动解析。下图是控制台输出,显示了将修改后的bplist作为合法Info.plist在我的桌面上发生崩溃的频率,还注意到用户级和系统级进程崩溃。LSD崩溃通过修改单个字节将ASCII字符串对象(类型0x5X)更改为另一种对象类型(例如DATE(类型0x33))来创建恶意bplist。下面是一个修改后的bplist示例:这个微小的字节更改现在可用于对macOS系统和iOS造成严重破坏,尽管该平台未在本研究中进行测试。此方法还会影响包括Spotlight在内的多个数据库,这些数据库已被此恶意Info.plist破坏,即使在重新启动后也会导致反复崩溃。漏洞是如何被发现的?能够轻松重现崩溃让我深入研究了错误实际发生的位置。追踪此漏洞的一种简单方法是查看崩溃进程的堆栈跟踪。下面是前面显示的测试应用程序的崩溃日志,它使用CoreFoundation读取恶意属性列表。阅读这篇文章将有助于理解CoreFoundation如何处理无法识别的选择器异常并阐明堆栈跟踪中的_CF_forwarding_prep_0。有了这些信息,我将之前的返回地址视为CFStringFind中异常的可能来源,尤其是在调用_CFStringGetLength之后。以下反汇编说明了此调用:CFStringFindDisassembly我在LLDB中逐步执行CFStringFind,直到调用_CFStringGetLength检查寄存器之前。从Apple的_CFStringGetLength文档中,我们知道第一个参数应该是一个字符串,因此我们可以使用以下LLDB命令检查RDI寄存器。可以看出第一个参数的对象类型不是字符串,而是恶意bplist中的一个_NSDate对象。以下_CFStringGetLength的反编译说明了可能出错的地方:匹配崩溃日志。如果我们继续执行这个函数,我们最终会在Objective-C异常处理内部遇到一个异常,说明我们已经找到了这些崩溃的根本原因。其他选择器继续使用非字符串对象生成bplist,并且能够从其他无法识别的选择器在CoreFoundation中产生其他崩溃。下面的crashlog是使用恶意bplist和剩余的nscfdata对象后的LSD的crashlog:这个LSDcrash的stacktrace如下:注意在Objective-C异常之前,crash的位置不是来自CFStringFind处理,但实际上调用_CFStringGetCStringPtrInternal的CFStringFindWithOptionsAndLocale最终由于调用错误的选择器_fastCStringContents而崩溃。这样做的原因是剩下的nscfdata类型实际上有一个长度选择器,所以它成功地通过了我们之前看到的第一个崩溃位置,并进一步进入CoreFoundation,直到它调用另一个无法识别的selectdevice。多个漏洞的发现在这项研究的早期,我使用plutil从恶意bplist生成崩溃,然后编写自己的代码以到达必要的代码路径。以下命令设置一个LLDB会话以通过使用plutil作为目标进程和打印plist标志来开始调试此崩溃,该标志仅打印出属性列表的人类可读版本。执行几次后,很明显plutil实际上是在其他地方崩溃了,而不是在CoreFoundation中。下面的输出说明它试图在__NSDate类型上调用长度选择器,这会导致无法识别的选择器异常,但此漏洞存在于plutil中,而不存在于CoreFoundation中。许多假定bplist仅包含字符串对象类型的macOS应用程序中似乎存在类似的漏洞。LSD进程崩溃的堆栈跟踪如下所示:如果我们使用GHIDRA反汇编_LSPlistCompactString函数,我们可以看到偏移量45或0x2D导致我们对易受攻击的对象类型进行另一个长度调用,大概是从我们现在所在的位置开始由LSD数据库中的恶意bplist调用:我们可以通过在_LSPlistCompactString上设置断点并使用以下断点命令打印第一个参数来验证这一点:下面的输出显示LSD正在从恶意bplist获取__NSDate对象:这证实了我最初认为是一个漏洞实际上在多个macOS二进制文件中存在很多,并且所有这些都源于bplist仅包含字符串对象的假设。恶意影响根级进程可??能会在正常用户帐户中崩溃,如果操作系统重新生成根级进程,它们会反复崩溃(例如,LSD和MDS)。系统不稳定和拒绝服务尤其发生在Finder或其他UI相关进程使用恶意bplist并使崩溃进程需要崩溃0-click时,因为应用程序包、包等在写入磁盘处理时会自动完成。有可能使普通用户帐户中与安全相关的进程崩溃,从而消除安全边界(XProtect等),尽管本文未对此进行全面探讨。在自动分析bplist的情况下,远程利用的可能性。受该漏洞影响的系统组件包括使用CoreFoundation解析bplist的应用,占比较大。快速搜索macOS10.15.3上安装的1,000多个二进制文件会导入实现此漏洞的函数。许多应用程序通过CoreFoundation解析bplist数据,但也会在自己的代码中错误地访问结果对象,这意味着出现漏洞的机会更大。本文翻译自:https://objective-see.com/blog/blog_0x5A.html【责任编辑:赵宁宁TEL:(010)68476606】