0x00 摘要
OS X
系统的10.11.4的系统补丁中修复了一个在内核中可以导致代码执行的漏洞,漏洞形成的原因是缺少了必要的边界值检测。
0x01 准备工作
因为这个漏洞是一个内核级的漏洞,所以需要搭建一个内核调试的环境。
1.1 内核调试环境的搭建
内核调试环境的搭建并不复杂,但是需要一台装有OS X
的虚拟机,只需要下载官方的Kernel Debug Kit
,安装并按照ReadMe.html
中的步骤操作即可。
一般情况下默认路径是/Library/Developer/KDKs/KDK_10.11.3_15D13b.kdk/ReadMe.html
KDK下载地址
也可以参考这篇文章OSX内核调试技巧分享
1.2 利用lldb调试kernel core dump
在默认情况下内核崩溃后会产生panic文件,记录这一次内核崩溃的最后调用栈,用来分析崩溃的原因,但是panic文件的信息量有限,而进行一次内核的动态调试步骤又比较复杂,这个时候对kernel core dump的分析是一种折中的方式。但是OS X
系统生成的kernle core不能在本机保存需要设置一个服务器,在系统内核崩溃时会将core文件发送到服务器。
设置方法可以参考苹果给出的官方文档,这里简单的叙述一下。在KDK的README文件中也有设置的步骤。
1.2.1 设置服务器(物理机)
- 创建core dump的文件夹
1 | server$ sudo mkdir /PanicDumps |
启用core dump服务
1
2server$ sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.kdumpd.plist
Password:********确认服务已经开启
1
2
3server$ sudo launchctl list | grep kdump
Password:********
- 0 com.apple.kdumpd
1.2.2 设置客户端(虚拟机)
1 | client$ sudo nvram boot-args="debug=0xd44 _panicd_ip=10.0.40.2" |
这里的这个ip需要填物理的ip。且虚拟机可以通过该ip和物理机简历连接。
1.2.3 使用lldb调试kernel core
当系统内核崩溃后,在物理机的/PanicDumps
路径中会出现xnu-XXX.gz
的文件。是通过zip压缩的。1
gunzip xnu-XXX.gz
通过指令解压后利用lldb查看core文件1
sudo lldb -c /PanicDumps/core-xnu-3248.30.4-172.16.9.186-ca2fd00a
注意需要使用sudo,否则会报错。这个时候就可以看到core dump的情况进行分析了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78➜ ~ sudo lldb -c /PanicDumps/core-xnu-3248.30.4-172.16.9.186-ca2fd00a
(lldb) target create --core "/PanicDumps/core-xnu-3248.30.4-172.16.9.186-ca2fd00a"
Kernel UUID: DB8A107C-3A4F-31AB-8BCE-EB77F80B1CD7
Load Address: 0xffffff8010c00000
warning: 'kernel' contains a debug script. To run this script in this debug session:
command script import "/Library/Developer/KDKs/KDK_10.11.3_15D13b.kdk/System/Library/Kernels/kernel.development.dSYM/Contents/Resources/DWARF/../Python/kernel.py"
To run all discovered debug scripts in this session:
settings set target.load-script-from-symbol-file true
Kernel slid 0x10a00000 in memory.
Loaded kernel file /Library/Developer/KDKs/KDK_10.11.3_15D13b.kdk/System/Library/Kernels/kernel.development
Loading 97 kext modules warning: Can't find binary/dSYM for com.apple.kec.corecrypto (D6E082B5-93B2-3FF0-AB4B-4AA310173CE8)
.....warning: Can't find binary/dSYM for com.apple.driver.AppleACPIPlatform (3BE4E926-E063-3BBD-BE05-F6F97358C7A4)
....warning: Can't find binary/dSYM for com.apple.driver.DiskImages (97177A33-27BD-34A9-9B42-1173BE480BCD)
.warning: Can't find binary/dSYM for com.apple.driver.AppleCredentialManager (E3817462-FFEE-38AE-839B-79932133E7EF)
.warning: Can't find binary/dSYM for com.apple.driver.AppleMobileFileIntegrity (09620E73-2D73-3F62-9E5D-4B9DC2147F70)
.warning: Can't find binary/dSYM for com.apple.driver.AppleKeyStore (7AF14D78-EEBE-3474-B605-66CC957F2FE5)
...warning: Can't find binary/dSYM for com.apple.security.sandbox (F3202072-6ED5-33BF-97B0-AD49F500ABF6)
...warning: Can't find binary/dSYM for com.apple.driver.AppleAPIC (46368557-CAF1-3FAC-AF62-A03389987023)
.warning: Can't find binary/dSYM for com.apple.driver.AppleSMBIOS (558EB25D-8E3F-3429-B2DC-ADAE2EF0F7C3)
...warning: Can't find binary/dSYM for com.apple.driver.AppleACPIButtons (767834A6-B80F-36ED-9C0A-A6179A144279)
....warning: Can't find binary/dSYM for com.apple.driver.AppleUSBHostMergeProperties (D338A98F-2B8F-3411-BD87-BD00F620A223)
.......warning: Can't find binary/dSYM for com.apple.driver.AppleFileSystemDriver (998B4AF6-388A-304E-9627-EBB1237252F8)
...warning: Can't find binary/dSYM for com.apple.driver.Intel82574L (92C2095F-4CB1-36CE-ACF9-518F4610AE68)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBXHCI (38F68C79-811D-3AA2-B8D4-0D444FF4DB4B)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBXHCIPCI (7AC984CE-8AAA-3B8D-92E3-24BE18DF3DEC)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBEHCI (FA569D7A-D439-32EB-9B57-0A5D5227AC12)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBUHCI (55F5C3FB-6419-35F2-B9A3-836F696C3DBC)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBUHCIPCI (4C589408-0FA4-35A0-B8BF-A65EEDFB971F)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBEHCIPCI (C2569C25-E38A-3AC0-8502-594A75E63C76)
..warning: Can't find binary/dSYM for com.apple.driver.AppleAHCIPort (20356FAA-8898-36F8-BAAD-8961AFC23E9B)
.warning: Can't find binary/dSYM for com.apple.iokit.IOAHCIBlockStorage (0A852267-0F62-363B-86D7-C2B02972EE48)
..warning: Can't find binary/dSYM for com.apple.iokit.IOAHCISerialATAPI (D1CA586E-89CA-36BE-A293-CE0BBD19367D)
.warning: Can't find binary/dSYM for com.apple.driver.AppleXsanScheme (00C3E9DA-99B0-3518-8B4B-38114EE146A8)
......warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBHostCompositeDevice (3E1A0840-033C-321B-B5ED-7BEA6996B1E0)
.warning: Can't find binary/dSYM for com.apple.driver.usb.AppleUSBHub (271D9C2E-FF74-3503-958E-24C554595575)
.warning: Can't find binary/dSYM for com.apple.driver.usb.IOUSBHostHIDDevice (65F7A241-C50F-3370-9CE8-54566F0130DE)
..warning: Can't find binary/dSYM for com.apple.driver.AppleSMC (535447F9-30E0-39BA-A2B8-1A027DED5D53)
.warning: Can't find binary/dSYM for com.apple.vecLib.kext (E62681B7-BE2F-3F89-8065-91C5C2876EBA)
..warning: Can't find binary/dSYM for com.apple.iokit.IOHDAFamily (3BF83381-C3DA-3EC4-BBE6-F2024D3EACC7)
..warning: Can't find binary/dSYM for com.apple.driver.AppleHDAController (AC7816C9-DEF7-310A-B059-5852BF07A843)
.warning: Can't find binary/dSYM for com.apple.iokit.IOBluetoothFamily (022A55C7-EF37-3BE7-AC09-0436CDEFCE95)
.warning: Can't find binary/dSYM for com.apple.iokit.IOBluetoothHostControllerUSBTransport (67B0326E-F86A-3AEF-BE41-99958414F094)
.warning: Can't find binary/dSYM for com.vmware.kext.VMwareGfx (00FD0C5F-0A29-3656-8718-EBF372456B8E)
....warning: Can't find binary/dSYM for com.apple.driver.AppleHV (8E08FFC5-4E33-3D66-BB9B-2EC170B650E6)
.....warning: Can't find binary/dSYM for com.apple.iokit.IOBluetoothSerialManager (A6A7E1A3-4063-3C42-9984-67E3BB1A0191)
.warning: Can't find binary/dSYM for com.apple.iokit.IOSurface (5D984125-CEC9-39B6-BA6E-6C6C6004552C)
.warning: Can't find binary/dSYM for com.apple.iokit.IOUserEthernet (6D2530ED-C0BC-3F64-B2FC-4490CC30BC06)
.warning: Can't find binary/dSYM for com.apple.driver.pmtelemetry (C3F2C16A-A407-389C-AD2B-B8582742FE5E)
.warning: Can't find binary/dSYM for com.apple.driver.IOPlatformPluginFamily (EC53D03F-6CD9-383A-8160-33E02C141EAA)
.warning: Can't find binary/dSYM for com.apple.driver.IOPlatformPluginLegacy (15BBAC18-907A-394F-BA5B-CC40E055BA13)
.warning: Can't find binary/dSYM for com.apple.driver.ACPI_SMC_PlatformPlugin (04F77CAB-EA07-362C-B7A2-0167D56D55BC)
..warning: Can't find binary/dSYM for com.apple.driver.AppleSMBusController (04C9295B-23E8-388B-8BB6-07CC377CADD2)
....warning: Can't find binary/dSYM for com.apple.driver.DspFuncLib (F1E07A68-221D-3ED3-A2BA-1735E0582F3F)
.warning: Can't find binary/dSYM for com.apple.driver.AppleHDA (344D4A99-D22C-3E43-9699-82C1B7044CE2)
.warning: Can't find binary/dSYM for com.apple.driver.AppleHDAHardwareConfigDriver (EDCBE684-9F4F-349A-9E17-D1704C26BD84)
.warning: Can't find binary/dSYM for com.apple.driver.AppleOSXWatchdog (0CE80268-ACDD-3FCC-8370-8A041468F898)
....warning: Can't find binary/dSYM for com.vmware.kext.vmmemctl (C2161D7F-F967-3406-A377-CD7D11EDE95A)
.warning: Can't find binary/dSYM for com.vmware.kext.vmhgfs (22192699-95BC-3ACC-96B1-023E6C6073AA)
.. done.
Core file '/PanicDumps/core-xnu-3248.30.4-172.16.9.186-ca2fd00a' (x86_64) was loaded.
(lldb) bt
IOUSBFamily was compiled with optimization - stepping may behave oddly; variables may not be available.
* thread #1: tid = 0x0000, 0xffffff7f91b11581 IOUSBFamily`AppleUSBPipe::Abort(this=<unavailable>, streamID=<unavailable>) + 153 at AppleUSBPipe.cpp:1181, stop reason = signal SIGSTOP
* frame #0: 0xffffff7f91b11581 IOUSBFamily`AppleUSBPipe::Abort(this=<unavailable>, streamID=<unavailable>) + 153 at AppleUSBPipe.cpp:1181 [opt]
frame #1: 0xffffff7f91b01197 IOUSBFamily`IOUSBInterfaceUserClient::AbortStreamsPipe(this=<unavailable>, pipeRef=<unavailable>, streamID=4042322160) + 305 at IOUSBInterfaceUserClient.cpp:3656 [opt]
frame #2: 0xffffff7f91afbcf9 IOUSBFamily`IOUSBInterfaceUserClient::_AbortStreamsPipe(target=<unavailable>, reference=<unavailable>, arguments=<unavailable>) + 241 at IOUSBInterfaceUserClient.cpp:3636 [opt]
frame #3: 0xffffff80112b9c17 kernel.development`::is_io_connect_method(connection=0xffffff801a719c00, selector=36, scalar_input=<unavailable>, scalar_inputCnt=<unavailable>, inband_input=<unavailable>, inband_inputCnt=0, ool_input=<unavailable>, ool_input_size=<unavailable>, inband_output=<unavailable>, inband_outputCnt=<unavailable>, scalar_output=<unavailable>, scalar_outputCnt=<unavailable>, ool_output=<unavailable>, ool_output_size=<unavailable>) + 487 at IOUserClient.cpp:3720 [opt]
frame #4: 0xffffff8010d5cfc0 kernel.development`_Xio_connect_method(InHeadP=<unavailable>, OutHeadP=0xffffff80195c55d0) + 384 at device_server.c:8255 [opt]
frame #5: 0xffffff8010c88ee3 kernel.development`ipc_kobject_server(request=0xffffff801c7f3be0) + 259 at ipc_kobject.c:340 [opt]
frame #6: 0xffffff8010c64e13 kernel.development`ipc_kmsg_send(kmsg=<unavailable>, option=<unavailable>, send_timeout=0) + 195 at ipc_kmsg.c:1441 [opt]
frame #7: 0xffffff8010c7b435 kernel.development`mach_msg_overwrite_trap(args=<unavailable>) + 197 at mach_msg.c:470 [opt]
frame #8: 0xffffff8010d83850 kernel.development`mach_call_munger64(state=0xffffff801b6471e0) + 480 at bsd_i386.c:560 [opt]
frame #9: 0xffffff8010db9516 kernel.development`hndl_mach_scall64 + 22
(lldb)
可以清楚的看到系统崩溃时的调用栈了。这个栈就是POC程序在虚拟机中执行后返回的结果。
0x02 POC崩溃现场分析
通过对POC执行后崩溃的现场,可以得知具体的崩溃原因,已经函数的调用顺序,这样在做动态分析和静态分析的时候才能有的放矢。
2.1 调用栈分析
1 | * frame #0: 0xffffff7f91b11581 IOUSBFamily`AppleUSBPipe::Abort(this=<unavailable>, streamID=<unavailable>) + 153 at AppleUSBPipe.cpp:1181 [opt] |
结合frame #3
的信息,以及poc中的相关代码段1
2
3
4
5
6
7
8
9
10
11
12
13//...
err = IOConnectCallMethod(
conn,
36,
inputScalar,
inputScalarCnt,
inputStruct,
inputStructCnt,
outputScalar,
&outputScalarCnt,
outputStruct,
&outputStructCnt);
//...
- 是在应用层程序调用IOUSBFamily的36号方法,
_AbortStreamsPipe
时触发的漏洞。 _AbortStreamsPipe
又调用了IOUSBInterfaceUserClient::AbortStreamsPipe
函数。IOUSBInterfaceUserClient::AbortStreamsPipe
函数最后调用了AppleUSBPipe::Abort
并触发了函数的崩溃。
2.2 崩溃原因
1 | 0xffffff7f91b1155f <+119>: callq 0xffffff80112ecc50 ; kprintf at pe_kprintf.c:105 |
1 | (lldb) register read |
崩溃的指令是1
-> 0xffffff7f91b11581 <+153>: movq (%rdi), %rax
1 | 0x000000000002c581 mov rax, qword [ds:rdi] |
对AT&T格式汇编不熟悉的可以看第二行的汇编代码,他们是一样的。$rdi
的值为0x4141414141414141
,而该指令试图读取地址为0x4141414141414141
出的值并复制给$rax
,所以就崩溃了。
0x03 IOUSBFamily代码分析
通过结合动态分析与静态分析,给出分析后的伪代码。分析过程略过,都是体力活。
3.1 IOUSBInterfaceUserClient::_AbortStreamsPipe
1 | int __fastcall IOUSBInterfaceUserClient::_AbortStreamsPipe(__int64 a1, __int64 a2, __int64 a3) |
这个函数的逻辑非常简单,就是根据收到的参数处理后调用了IOUSBInterfaceUserClient::AbortStreamsPipe
函数,每一个参数已经在注释中体现了。
3.2IOUSBInterfaceUserClient::AbortStreamsPipe
1 | __int64 __fastcall IOUSBInterfaceUserClient::AbortStreamsPipe(IOUSBInterfaceUserClient *this, unsigned __int8 a2, unsigned int a3) |
调用AppleUSBPipe::Abort
3.3 AppleUSBPipe::Abort
这个函数看汇编代码更容易理解一些1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16...
0x000000000002c569 mov eax, r14d
0x000000000002c56c mov rcx, qword [ds:rbx+0x88]
0x000000000002c573 mov rdi, qword [ds:rcx+rax*8]
0x000000000002c577 mov eax, 0xe00002f0
0x000000000002c57c test rdi, rdi
0x000000000002c57f je 0x2c5c9
->0x000000000002c581 mov rax, qword [ds:rdi]
0x000000000002c584 xor esi, esi
0x000000000002c586 mov edx, 0xe00002eb
0x000000000002c58b xor ecx, ecx
0x000000000002c58d call qword [ds:rax+0x178]
0x000000000002c593 cmp eax, 0xe00002d6
0x000000000002c598 je 0x2c5b6
...
各个寄存器的值如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23(lldb) register read
General Purpose Registers:
rax = 0x00000000e00002f0
rbx = 0xffffff801c1a6100
rcx = 0x0000000000000000
rdx = 0xffffff801779f6e0
rdi = 0x4141414141414141
rsi = 0x00000000f0f0f0f0
rbp = 0xffffff887b613b20
rsp = 0xffffff887b613ae0
r8 = 0x0000000000000000
r9 = 0x0000000000000000
r10 = 0xffffff7f91b408a1 ""
r11 = 0x0000000000000000
r12 = 0x0000000000000000
r13 = 0x0000000000000000
r14 = 0x00000000f0f0f0f0
r15 = 0x00000000f0f0f0f0
rip = 0xffffff7f91b11581 IOUSBFamily`AppleUSBPipe::Abort(unsigned int) + 153 at AppleUSBPipe.cpp:1181
rflags = 0x0000000000010206
cs = 0x0000000000000008
fs = 0x0000000000000000
gs = 0x0000000000000000
当执行到这里时,因为rax是应用层传入的参数0xf0f0f0f0
,而rcx的值是0x0000000000000000
,所以根据rax的不同,rdi的值会是一个从0x0000000000000000
地址开始偏移量是IOUSBInterfaceUserClient::AbortStreamsPipe函数中的SteamID,也就是POC中的0xf0f0f0f0
乘以8LL
之后获得的所得地址所指向的内存处的值。
因为0xf0f0f0f0
是一个POC中可控值,所以0x000000000002c573 mov rdi, qword [ds:rcx+rax*8]
是一个从0x0000000000000000地址开始任意偏移量的任意读取。
因为0xf0f0f0f0*0x8=0x787878780,结合POC中代码1
2
3
4
5
6
7
8
9
10
11void map_payload(uint64_t target_rip) {
uint64_t*** obj_ptr_ptr = (void*)0x0000000787878780;
void* request = (void*)0x0000000787878000;
void* page = mmap(request, 0x1000, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_ANON|MAP_PRIVATE, -1, 0);
if (request != page) {
printf("MAP_FIXED didn't give us the right page\n");
exit(EXIT_FAILURE);
}
memset((void*)page, 'A', 0x1000);
}
从地址0x0000000787878000开始一直到0x0000000787878000+0x1000处所有的值都为0x41。
所以rdi寄存器的值为0x4141414141414141,从而导致了POC执行时出现崩溃。
至此POC分析完毕。
3.4 小结
调试poc花了一些时间,陷入了各种代码实现的分析,和做开发时一样,调bug时需要注重崩溃的现场,分析的过程中经常埋头分析了一大通之后发现得到的信息在崩溃现场已经有了,甚至还有一些分析过程中想不通的问题,在崩溃的现场也已经有线索了。
reference
1.OS X Kernel code execution due to lack of bounds checking in AppleUSBPipe::Abort
PS
这是我的学习分享博客http://turingh.github.io/
欢迎大家来探讨,不足之处还请指正。