0x00 前言
不久以前,研究人员“ccpwd”通过ZDI漏洞计划提交了macOS磁盘管理守护程序(diskmanagementd)中的一个堆缓冲区溢出漏洞。diskmanagementd
是负责驱动器管理及分区的一个服务,用户可以通过“Disk Utility”(磁盘工具)与该服务交互。该服务会运行一个Mach服务端,可以通过进程间通信(IPC)与之交互。客户端可以使用Mach IPC接口来发送及接收消息,通过这种RCP机制执行Mach服务端中的函数,这些函数通过MIG(Mach Interface Generator)生成(MIG是Apple的RPC代码生成工具)。
0x01 漏洞分析
该服务的所有通信流量最终都会流经launchd(这是macOS版的init),我们可以分析该服务对应的plist文件(/System/Library/LaunchDaemons/com.apple.diskmanagementd.plist
)来了解更多信息。
一开始该服务会分配一个回调函数,在发送和接收Mach消息的IPC操作期间会调用这个回调函数。
图1. 设置sub_10000C241回调函数
当在0x10000BE1F
获得receive right(接收权限)后,CFMachPortCreateWithPort会将sub_10000C241
设置为回调函数,以便处理在Mach端口上收到的信息。根据msgh_id
(在Mach消息中发送的一个值,用来传递操作或者函数对应的ID)的具体值,sub_10000C241
会间接使用该id作为两个远程函数dispatch表的索引。sub_100001DA2
以及sub_100002005
分别负责发起并拆分后续的通信会话。
图2. 设置端口权限
Mach端口采用单工(unidirectional)模式,这意味着每个发送/接收请求需要使用自己的端口。Apple有如下一段描述:
端口(port)是客户端与服务端之间的一个单向通信信道,客户端请求服务,服务端提供服务。如果想向服务请求返回响应,那么就必须使用第二个端口。这种模式相当于UNIX中的(unidirectional)管道。
图3. 在off_1001AB6E0
处将msgh_id
作为dispatch表的索引使用
在sub_10000CCA9
中(sub_100001DA2
会调用该函数),该函数会创建另一个Mach端口,设置sub_10000DACC
回调函数,以Comms-F2TPort
作为key保存到一个字典中。该函数会分配大小为0x1000
字节的一个缓冲区,用来响应Mach消息,该缓冲区保存在Comms-F2T-replyarea
key中。
图4. 分配响应缓冲区并创建Mach端口
随后,目标服务会调用setObject:forKey:,将键值对添加到字典中。
图5. 将端口及响应缓冲区以键值对形式加入字典
当客户端发送消息时,目标服务就会触发sub_10000DACC
,然后根据msgh_id
的值来访问对应的MIG远程过程调用。这里我们重点关注sub_1000087C9
。
图6. 通过mig_reply_setup设置回复缓冲区并调用RPC dispatcher
缓冲区溢出点位于sub_1000087C9
函数中,其中用户输入会被添加到回复缓冲区中。经过一系列计算后,最终得出的长度值会超过0x1000
偏移量。
图7. 长度值经过计算后会得到一个较大的偏移量
在图6中,0x1000
大小的回复缓冲区位于r14
中,而用户输入从0x38
偏移处开始,因此用户输入有0xfc8
的可用空间。当输入数据到达0xfc8
时,strlen
会返回相同的值。经过一系列运算后,最终的值为0xfcc [ ((0xfc8 + 1) + 3) & 0xfffffffc]
。在0x100008ABD
地址处,偏移量会变成0x1004 [0xfcc+0x38]
,这样就能泄露4字节并写入4字节,实现可靠的漏洞利用原语。泄露效果可能并不明显,因为缓冲区大小为0x1000
字节,而写入地址位于0x1004
处。这意味着我们可以从下一个块中读取4字节缓冲区。
这个漏洞利用起来有一些限制条件。输入必须不能包含NULL
字符,不然会导致strlen
在该位置停止计算。另一个限制是超出缓冲区末尾写入的数据将始终是var_DC
的内容,而该变量为sub_100085B30
返回的错误代码。
0x02 总结
对这类漏洞分析始终是非常有趣的一个过程,从中我们可以看到,即便一个非常小的错误也可能存在漏洞,最终导致能在目标系统上执行代码。Apple在macOS Mojave 10.14.5中修复了这个bug(以及其他bug),根据官方描述,Apple通过“改进内存处理机制”解决了这个问题。有趣的是,Apple在CVE公告中将这个漏洞拆分到Disk Management组件以及另一个概念模糊的“Security”组件中,而“Security”部分的漏洞已经在macOS Sierra 10.12.6和macOS High Sierra 10.13.6上被修复。不论如何,存在漏洞的代码被修复总是一件不错的结果。