漏洞分析(二)iOS kernel.backtrace信息泄漏漏洞
0x0 背景
Apple在iOS 10中引入内核的一些代码,这段代码为kernel.backtrace sysctl实现了一个新的sysctl处理程序,此sysctl用于检索当前线程的用户级别回溯。
0x1 kernel.backtrace
kernel.backtrace是一个相对较新的iOS内核功能,它可以让当前进程获取自己的用户级别回溯。虽然用户级别的回溯的逻辑隐藏在内核源代码的Mach部分中,但sysctl处理程序本身在文件
/bsd/kern/kern_backtrace.c
中实现。
处理程序的代码如下所示,首先验证传入的参数并限制可以检索的回溯的深度(第58-66行)。然后它将分配一个堆缓冲区来存储第67行中用户选择的深度的回溯,并使用外部辅助函数用用户级别回溯填充缓冲区(第72行)。然后将实际检索的回溯复制到用户区(第77行)并释放堆缓冲区(第84行):
48 static int
49 backtrace_sysctl SYSCTL_HANDLER_ARGS
50 {
51 #pragma unused(oidp, arg2)
52 uintptr_t *bt;
53 uint32_t bt_len, bt_filled;
54 uintptr_t type = (uintptr_t)arg1;
55 bool user_64;
56 int err = 0;
57
58 if (type != BACKTRACE_USER) {
59 return EINVAL;
60 }
61
62 if (req->oldptr == USER_ADDR_NULL || req->oldlen == 0) {
63 return EFAULT;
64 }
65
66 bt_len = req->oldlen > MAX_BACKTRACE ? MAX_BACKTRACE : req->oldlen;
67 bt = kalloc(sizeof(uintptr_t) * bt_len);
68 if (!bt) {
69 return ENOBUFS;
70 }
71
72 err = backtrace_user(bt, bt_len, &bt_filled, &user_64);
73 if (err) {
74 goto out;
75 }
76
77 err = copyout(bt, req->oldptr, bt_filled * sizeof(uint64_t));
78 if (err) {
79 goto out;
80 }
81 req->oldidx = bt_filled;
82
83 out:
84 kfree(bt, sizeof(uintptr_t) * bt_len);
85 return err;
86 }
0x2 漏洞
这里是将回溯复制到用户区的代码,复制到用户区的字节数是
bt_filled * sizeof(uint64_t)
,这是将填充的回溯条目的数量乘以8个字节:77 err = copyout(bt, req->oldptr, bt_filled * sizeof(uint64_t));
78 if (err) {
79 goto out;
80 }
那么再看堆缓冲区大小,堆缓冲区的大小由
sizeof(uintptr_t)\ * bt_len
确定,这是最大检索的回溯条目的数量乘以指针的大小。67 bt = kalloc(sizeof(uintptr_t) * bt_len);
68 if (!bt) {
69 return ENOBUFS;
70 }
在较新的64位设备上,指针的大小为8。而在较旧的iOS设备(iPhone 5c及更低版本)和较旧的Apple Watch(系列3)内部均为32位设备,因此只有4个字节的指针。这意味着在这些旧设备上,对copyout()的调用将允许从堆中复制两倍大小的字节,而不是缓冲区大小,这是一个经典的堆缓冲区溢出漏洞。
0x3 影响
虽然这是一个内核信息泄漏的0day漏洞,但依然有许多缓解因素:
- 该漏洞仅影响32位iOS设备 - 苹果目前在32位版本中仍然支持的唯一设备是Apple Watch Series 3及更低版本
- 该漏洞只能在应用程序沙箱之外触发 - 因此它只能用作漏洞链的一部分,而不能直接从应用程序中利用
0x4 iOS 12 copyin/copyout缓解
从iOS 12开始Apple向内核添加了缓解措施,如果内核的堆缓冲区具有继续操作所需的大小,则每次执行copyin()或copyout()时都会进行检查。如果攻击者试图在内核区域堆元素的边界上读取或写入,则内核将会发生混乱。
但是,Apple没有将此保护添加到32位内核,估计Apple已经放弃对32位设备的支持了。
0x5 漏洞赏金
Apple安全奖金计划眼中的这个安全漏洞的价格为0。这有三个原因:
- Apple只支付影响其最新设备的漏洞。
- Apple不支付影响MacOS/tvOS/WatchOS的漏洞,只为iOS设备付费。
- 尽管许多缓解措施依赖于内核信息,但Apple暂未支付信息泄露漏洞。
0x6 结论
使用两种不同的数据类型进行分配和复制是相当难以理解的,而且也非常明显。所以很难解释为什么每次添加新代码时,对新内核代码的安全审查都没有发现这一点。