def popMultiple(args, constraint=None, assertion=None, clmax=None, optimizeLen=False): """ args is a list of pairs (reg, value) reg is a reg UID value is an int Creates a chain that pops values into regs """ if (clmax <= 0): return None if (constraint is None): constr = Constraint() else: constr = constraint if (assertion is None): a = Assertion() else: a = assertion perms = itertools.permutations(args) for perm in perms: clmax_tmp = clmax res = ROPChain() constr_tmp = constr for arg in perm: if (optimizeLen): pop = search_optimize_len(QueryType.CSTtoREG, arg[0], arg[1], constr_tmp, a, n=1, clmax=clmax_tmp) else: pop = search(QueryType.CSTtoREG, arg[0], arg[1], constr_tmp, a, n=1, clmax=clmax_tmp) if (not pop): break else: clmax_tmp -= len(pop[0]) # If Reached max length, exit if (clmax_tmp < 0): pop = None break else: res.addChain(pop[0]) constr_tmp = constr_tmp.add(RegsNotModified([arg[0]])) if (pop): return res return None
def build_mprotect64(addr, size, prot=7, constraint=None, assertion=None, clmax=SYSCALL_LMAX, optimizeLen=False): """ Call mprotect from X86-64 arch Args must be on registers (rdi, rsi, rdx): Sizes are (unsigned long, size_t, unsigned long) rax must be 10 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if( constraint is None ): constraint = Constraint() if( assertion is None ): assertion = Assertion() # Check if we have the function ! verbose("Trying to call mprotect() function directly") func_call = build_call('mprotect', [addr, size, prot], constraint, assertion, clmax=clmax, optimizeLen=optimizeLen) if( not isinstance(func_call, str) ): verbose("Success") return func_call else: if( not constraint.chainable.ret ): verbose("Coudn't call mprotect(), try direct syscall") else: verbose("Couldn't call mprotect() and return to ROPChain") return None # Otherwise do the syscall by 'hand' # Set the registers args = [[Arch.n2r('rdi'),addr],[Arch.n2r('rsi'), size],[Arch.n2r('rdx'),prot], [Arch.n2r('rax'),10]] chain = popMultiple(args, constraint, assertion, clmax-1, optimizeLen) if( not chain ): verbose("Failed to set registers for the mprotect syscall") return None # Syscall syscalls = search(QueryType.SYSCALL, None, None, constraint, assertion) if( not syscalls ): verbose("Failed to find a syscall gadget") return None else: chain.addChain(syscalls[0]) verbose("Success") return chain
def init_impossible_REGtoREG(): global global_impossible_REGtoREG record = SearchRecord() for reg1 in range(0, Arch.ssaRegCount): for reg2 in range(0, Arch.ssaRegCount): print("Doing {} <- {} ".format(reg1, reg2)) if (reg2 == reg1): continue search(QueryType.REGtoREG, reg1, [reg2, 0], Constraint(), Assertion(), n=1, record=record) global_impossible_REGtoREG = record.impossible_REGtoREG
def find(args): """ args - List of user arguments as strings (the command should not be included in the list as args[0]) """ if (not args): print_help() return if (args[0] == OPTION_HELP or args[0] == OPTION_HELP_SHORT): print_help() return parsed_args = parse_args(args) if (not parsed_args[0]): error(parsed_args[1]) else: qtype = parsed_args[1] arg1 = parsed_args[2] arg2 = parsed_args[3] constraint = parsed_args[4] nbResults = parsed_args[5] clmax = parsed_args[6] assertion = Assertion().add(\ RegsValidPtrRead([(Arch.spNum(),-5000, 10000)])).add(\ RegsValidPtrWrite([(Arch.spNum(), -5000, 0)])) # Search res = search(qtype, arg1, arg2, constraint, assertion, n=nbResults, clmax=clmax) if (res): print_chains(res, "Built matching ROPChain(s)", constraint.getBadBytes()) else: res = search_not_chainable(qtype, arg1, arg2, constraint, assertion, n=nbResults, clmax=clmax) print_chains(res, "Possibly matching gadget(s)", constraint.getBadBytes())
def initEngine(): global INIT_LMAX, INIT_MAXDEPTH global global_impossible_REGtoREG global baseAssertion # Init global variables baseAssertion = Assertion().add(\ RegsValidPtrRead([(Arch.spNum(),-5000, 10000)]), copy=False).add(\ RegsValidPtrWrite([(Arch.spNum(), -5000, 0)]), copy=False) info(string_bold("Initializing Semantic Engine\n")) # Init helper for REGtoREG global_impossible_REGtoREG = SearchEnvironment(INIT_LMAX, Constraint(), baseAssertion, INIT_MAXDEPTH) init_impossible_REGtoREG(global_impossible_REGtoREG)
def build_mprotect64(addr, size, prot=7, constraint=None, assertion=None, clmax=None, optimizeLen=False): """ Call mprotect from X86-64 arch Args must be on registers (rdi, rsi, rdx): Sizes are (unsigned long, size_t, unsigned long) rax must be 10 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if (constraint is None): constraint = Constraint() if (assertion is None): assertion = Assertion() # Set the registers args = [[Arch.n2r('rdi'), addr], [Arch.n2r('rsi'), size], [Arch.n2r('rdx'), prot], [Arch.n2r('rax'), 10]] chain = popMultiple(args, constraint, assertion, clmax - 1, optimizeLen) if (not chain): verbose("Failed to set registers for the mprotect syscall") return None # Syscall syscalls = search(QueryType.SYSCALL, None, None, constraint, assertion) if (not syscalls): verbose("Failed to find a syscall gadget") return None else: chain.addChain(syscalls[0]) verbose("Success") return chain
def build_mprotect32(addr, size, prot=7, constraint=None, assertion = None, clmax=None, optimizeLen=False): """ Call mprotect from X86 arch Args must be on the stack: int mprotect(void *addr, size_t len, int prot) args must be in registers (ebx, ecx, edx) eax must be 0x7d = 125 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if( constraint is None ): constraint = Constraint() if( assertion is None ): assertion = Assertion() # Set the registers args = [[Arch.n2r('eax'),0x7d],[Arch.n2r('ebx'), addr],[Arch.n2r('ecx'),size], [Arch.n2r('edx'),prot]] chain = popMultiple(args, constraint, assertion, clmax-1, optimizeLen) if( not chain ): verbose("Failed to set registers for the mprotect syscall") return None # Int 0x80 int80_gadgets = search(QueryType.INT80, None, None, constraint, assertion) if( not int80_gadgets ): verbose("Failed to find an 'int 80' gadget") return None else: chain.addChain(int80_gadgets[0]) verbose("Success") return chain
def pwn(args): global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON global EXPLOIT_LMAX if( not args ): print_help() return # Check if gadgets have been loaded in the DB if( not Database.gadgets ): error("Oops. You have to load gadgets before pwning ;) ") return # Set default output format OUTPUT = OUTPUT_CONSOLE clmax = EXPLOIT_LMAX seenOutput = False seenLmax = False seenBadBytes = False seenVerbose = False seenOutfile = False seenPaddingByte = False seenPaddingLen = False constraint = Constraint() assertion = Assertion() subcommand = None outfile = None paddingByteStr = None paddingLen = 0 i = 0 while i < len(args): # Parse options if( args[i][0] == '-' ): if( args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]): if( seenBadBytes ): error("Error. '" + args[i] + "' option should be used only once") return if( i+1 >= len(args)): error("Error. Missing bad bytes after option '"+args[i]+"'") return seenBadBytes = True (success, res) = parse_bad_bytes(args[i+1]) if( not success ): error(res) return i = i+2 constraint = constraint.add(BadBytes(res)) elif( args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT ): if( seenLmax ): error("Error. '" + arg + "' option should be used only once.") return if( i+1 >= len(args)): error("Error. Missing output format after option '"+arg+"'") return try: clmax = int(args[i+1]) if( clmax < Arch.octets() ): raise Exception() # Convert number of bytes into number of ropchain elements clmax /= Arch.octets() except: error("Error. '" + args[i+1] +"' bytes is not valid") return i = i +2 seenLmax = True elif( args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]): if( seenOutput ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing output format after option '"+args[i]+"'") return if( args[i+1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]): OUTPUT = args[i+1] seenOutput = True i += 2 else: error("Error. Unknown output format: {}".format(args[i+1])) return elif( args[i] in [OPTION_OUTFILE_SHORT, OPTION_OUTFILE] ): if( seenOutfile ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing file name after option '"+args[i]+"'") return seenOutfile = True outfile = args[i+1] i += 2 elif( args[i] in [OPTION_PADDING_BYTE, OPTION_PADDING_BYTE_SHORT] ): if( seenPaddingByte ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing byte after option '"+args[i]+"'") return seenPaddingByte = True try: paddingByte = int(args[i+1], 16) except: error("Error. '{}' is not a valid byte".format(args[i+1])) return if( paddingByte > 0xff ): error("Error. '{}' can't be stored in one byte".format(args[i+1])) return paddingByteStr = "\\x"+format(paddingByte, "02x") i += 2 elif( args[i] in [OPTION_PADDING_LEN, OPTION_PADDING_LEN_SHORT] ): if( seenPaddingLen ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing length after option '"+args[i]+"'") return seenPaddingLen = True try: paddingLen = int(args[i+1], 10) except: try: paddingLen = int(args[i+1], 16) except: error("Error. '{}' is not a valid byte".format(args[i+1])) return if( paddingLen < 0 ): error("Error. Padding length must be > 0") return i += 2 elif( args[i] in [OPTION_HELP, OPTION_HELP_SHORT]): print_help() return elif( args[i] in [OPTION_VERBOSE, OPTION_VERBOSE_SHORT]): seenVerbose = True i += 1 else: error("Error. Unknown option '{}'".format(args[i])) return # Parse a subcommand else: # Before parsing, check arguments # Check arguments if( seenPaddingByte and not seenPaddingLen ): error("Error. You have to specify padding length if you provide a padding byte. See the '-pl,--padding-length' option") return # Parse subcommand verbose_mode(seenVerbose) payload = None if( args[i] == CMD_DELIVER_SHELLCODE ): payload = dshell(args[i+1:], constraint, assertion, lmax=clmax) else: error("Error. Unknown subcommand : '{}'".format(args[i])) verbose_mode(False) return verbose_mode(False) # Print result if( payload == "help"): return elif( not payload is None ): print(string_bold("\n\tBuilt exploit - {} bytes\n".format(payload.len_bytes))) # Normal output if( OUTPUT == OUTPUT_CONSOLE ): payload_string = payload.strConsole(Arch.bits(), constraint.getBadBytes()) elif( OUTPUT == OUTPUT_PYTHON ): payload_string = payload.strPython(Arch.bits(), constraint.getBadBytes(), \ noTab=seenOutfile, paddingByteStr=paddingByteStr, paddingLen=paddingLen) # Output to file if( outfile ): try: f = open(outfile, "w") f.write(remove_colors(payload_string)) f.close() print(string_bold("\n\tWrote payload in file '{}'\n".format(outfile))) except: error("Error. Couldn't not write payload in file '{}'".format(outfile)) else: print(payload_string) else: error("Couldn't generate exploit") return # Test parsing result if( subcommand is None ): error("Missing subcommand") return
def pwn(args): global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON global EXPLOIT_LMAX if (not args): print_help() return # Check if gadgets have been loaded in the DB if (not Database.gadgets): error("Oops. You have to load gadgets before pwning ;) ") return # Set default output format OUTPUT = OUTPUT_CONSOLE clmax = EXPLOIT_LMAX seenOutput = False seenLmax = False seenBadBytes = False seenVerbose = False constraint = Constraint() assertion = Assertion() subcommand = None i = 0 while i < len(args): # Parse options if (args[i][0] == '-'): if (args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]): if (seenBadBytes): error("Error. '" + args[i] + "' option should be used only once") return if (i + 1 >= len(args)): error("Error. Missing bad bytes after option '" + args[i] + "'") return seenBadBytes = True (success, res) = parse_bad_bytes(args[i + 1]) if (not success): error(res) return i = i + 2 constraint = constraint.add(BadBytes(res)) elif (args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT): if (seenLmax): error("Error. '" + arg + "' option should be used only once.") return if (i + 1 >= len(args)): error("Error. Missing output format after option '" + arg + "'") return try: clmax = int(args[i + 1]) if (clmax < Arch.octets()): raise Exception() # Convert number of bytes into number of ropchain elements clmax /= Arch.octets() except: error("Error. '" + args[i + 1] + "' bytes is not valid") return i = i + 2 seenLmax = True elif (args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]): if (seenOutput): error("Option '{}' should be used only once".format( args[i])) return if (i + 1 >= len(args)): error("Error. Missing output format after option '" + args[i] + "'") return if (args[i + 1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]): OUTPUT = args[i + 1] seenOutput = True i += 2 else: error("Error. Unknown output format: {}".format(args[i + 1])) return elif (args[i] in [OPTION_HELP, OPTION_HELP_SHORT]): print_help() return elif (args[i] in [OPTION_VERBOSE, OPTION_VERBOSE_SHORT]): seenVerbose = True i += 1 else: error("Error. Unknown option '{}'".format(args[i])) return # Parse a subcommand else: verbose_mode(seenVerbose) payload = None if (args[i] == CMD_DELIVER_SHELLCODE): payload = dshell(args[i + 1:], constraint, assertion, lmax=clmax) else: error("Error. Unknown subcommand : '{}'".format(args[i])) verbose_mode(False) return verbose_mode(False) # Print result if (payload): print( string_bold("\n\tBuilt exploit - {} bytes\n".format( payload.len_bytes))) if (OUTPUT == OUTPUT_CONSOLE): print( payload.strConsole(Arch.bits(), constraint.getBadBytes())) elif (OUTPUT == OUTPUT_PYTHON): print( payload.strPython(Arch.bits(), constraint.getBadBytes())) else: error("Couldn't generate exploit") return # Test parsing result if (subcommand is None): error("Missing subcommand") return
def store_constant_address(qtype, cst_addr, value, constraint=None, assertion=None, clmax=None, optimizeLen=False): """ Does a XXXtoMEM kind of query BUT the memory address is a simple constant ! Expected qtypes are only XXXtoMEM cst_addr is the store address value is the value to store, a single cst or a couple (reg,cst) """ if (clmax is None): clmax = STORE_CONSTANT_ADDRESS_LMAX elif (clmax <= 0): return None if (constraint is None): constr = Constraint() else: constr = constraint if (assertion is None): a = Assertion() else: a = assertion # Tranform the query type if (qtype == QueryType.CSTtoMEM): qtype2 = QueryType.CSTtoREG elif (qtype == QueryType.REGtoMEM): qtype2 = QueryType.REGtoREG elif (qtype == QueryType.MEMtoREG): qtype2 = QueryType.MEMtoREG else: raise Exception( "Query type {} should not appear in this function!".format(qtype)) tried_values = [] tried_cst_addr = [] best = None # If optimizeLen shortest = clmax # Shortest ROPChain found if optimizeLen ;) for ((addr_reg, addr_cst), (reg,cst), gadget) in \ sorted(DBAllPossibleWrites(constr.add(Chainable(ret=True)), a), \ key=lambda x: 0 if (x[1] == value) else 1) : # DOn't use rip or rsp... if( reg == Arch.ipNum() or reg == Arch.spNum()\ or addr_reg == Arch.ipNum() or addr_reg == Arch.spNum()): continue res = None # Check if directly the registers we want to write ;) value_is_reg = False value_to_reg = [] addr_to_reg = [] if ((reg, cst) == value): value_to_reg = [ROPChain()] value_is_reg = True # adapt value if (not isinstance(value, tuple)): adjusted_value = value - cst else: adjusted_value = (value[0], value[1] - cst) adjusted_cst_addr = cst_addr - addr_cst # Get spInc gadget_paddingLen = (gadget.spInc / Arch.octets()) - 1 # Check if tried before if ((reg, cst) in tried_values): continue elif ((addr_reg, addr_cst) in tried_cst_addr): continue ### Try to do reg first then addr_reg # Try to put the value into reg clmax2 = shortest - gadget_paddingLen - 1 if (not value_is_reg): value_to_reg = search(qtype2, reg, adjusted_value, constr, a, clmax=clmax2, n=1, optimizeLen=optimizeLen) if (not value_to_reg): tried_values.append((reg, cst)) continue else: clmax2 = clmax2 - len(value_to_reg[0]) # Try to put the cst_addr in addr_reg addr_to_reg = search(QueryType.CSTtoREG, addr_reg, adjusted_cst_addr, constr.add(RegsNotModified([reg])), a, clmax=clmax2, n=1, optimizeLen=optimizeLen) if (addr_to_reg): # If we found a solution # Combine them and return # Padd the gadget res = value_to_reg[0].addChain(addr_to_reg[0]).addGadget(gadget) if (gadget.spInc > 0): padding_value = constr.getValidPadding(Arch.octets()) res = res.addPadding(padding_value, n=(gadget.spInc / Arch.octets()) - 1) if (optimizeLen): if (best): best = min(best, res) else: best = res shortest = len(best) else: return res ### Try to do addr_reg first and then reg clmax2 = shortest - gadget_paddingLen - 1 # Try to put the cst_addr in addr_reg addr_to_reg = search(QueryType.CSTtoREG, addr_reg, adjusted_cst_addr, constr, a, clmax=clmax2, n=1, optimizeLen=optimizeLen) if (not addr_to_reg): tried_cst_addr.append((addr_reg, addr_cst)) continue else: clmax2 = clmax2 - len(addr_to_reg[0]) # Try to put the value into reg if (not value_is_reg): value_to_reg = search(qtype2, reg, adjusted_value, constr.add(RegsNotModified([addr_reg])), a, clmax=clmax2, n=1, optimizeLen=optimizeLen) if (value_to_reg): # If we found a solution # Combine them and return # Padd the gadget res = addr_to_reg[0].addChain(value_to_reg[0]).addGadget(gadget) if (gadget.spInc > 0): padding_value = constr.getValidPadding(Arch.octets()) res = res.addPadding(padding_value, n=(gadget.spInc / Arch.octets()) - 1) if (optimizeLen): if (best): best = min(best, res) else: best = res shortest = len(best) else: return res # 5 = two pops for addr_reg and reg + 1 for the write gadget # So since 5 is the shortest possible with two pops we can return # We can have < 5 if reg is already equal to 'value' argument # But we try this case first (see sorted()) when getting possibleWrites ;) if (((not optimizeLen) or (not value_is_reg)) and (not best is None) and len(best) <= 5): return best elif (optimizeLen and (not best is None) and len(best) <= 3): return best return best
def syscall(args): global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON # Parsing arguments if (not args): print_help() return OUTPUT = OUTPUT_CONSOLE funcName = None i = 0 seenOutput = False seenFunction = False seenBadBytes = False seenKeepRegs = False constraint = Constraint() assertion = Assertion() while i < len(args): if (args[i] in [OPTION_LIST, OPTION_LIST_SHORT]): listSyscalls(args[1:]) return if (args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]): if (seenBadBytes): error("Error. '" + args[i] + "' option should be used only once") return if (i + 1 >= len(args)): error("Error. Missing bad bytes after option '" + args[i] + "'") return seenBadBytes = True (success, res) = parse_bad_bytes(args[i + 1]) if (not success): error(res) return i = i + 2 constraint = constraint.add(BadBytes(res)) elif (args[i] in [OPTION_KEEP_REGS, OPTION_KEEP_REGS_SHORT]): if (seenKeepRegs): error("Error. '" + args[i] + "' option should be used only once") return if (i + 1 >= len(args)): error("Error. Missing register after option '" + args[i] + "'") return seenKeepRegs = True (success, res) = parse_keep_regs(args[i + 1]) if (not success): error(res) return i = i + 2 constraint = constraint.add(RegsNotModified(res)) elif (args[i] in [OPTION_FUNCTION, OPTION_FUNCTION_SHORT]): if (not loadedBinary()): error( "Error. You should load a binary before building ROPChains" ) return elif (seenFunction): error("Option '{}' should be used only once".format(args[i])) return userInput = '' i += 1 while (i < len(args) and args[i][0] != "-"): userInput += args[i] i += 1 (funcName, funcArgs) = parseFunction(userInput) if (not funcName): return seenFunction = True elif (args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]): if (seenOutput): error("Option '{}' should be used only once".format(args[i])) return if (i + 1 >= len(args)): error("Error. Missing output format after option '" + args[i] + "'") return if (args[i + 1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]): OUTPUT = args[i + 1] seenOutput = True i += 2 else: error("Error. Unknown output format: {}".format(args[i + 1])) return elif (args[i] in [OPTION_HELP, OPTION_HELP_SHORT]): print_help() return else: error("Error. Unknown option '{}'".format(args[i])) return if (not funcName): error("Missing function to call") else: call(funcName, funcArgs, constraint, assertion)
def build_mprotect32(addr, size, prot=7, constraint=None, assertion=None, clmax=SYSCALL_LMAX, optimizeLen=False): """ Call mprotect from X86 arch Args must be on the stack: int mprotect(void *addr, size_t len, int prot) args must be in registers (ebx, ecx, edx) eax must be 0x7d = 125 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if (constraint is None): constraint = Constraint() if (assertion is None): assertion = Assertion() # Check if we have the function ! verbose("Trying to call mprotect() function directly") func_call = build_call('mprotect', [addr, size, prot], constraint, assertion, clmax=clmax, optimizeLen=optimizeLen) if (not isinstance(func_call, str)): verbose("Success") return func_call else: if (not constraint.chainable.ret): verbose("Coudn't call mprotect(), try direct syscall") else: verbose("Couldn't call mprotect() and return to ROPChain") return None # Otherwise do syscall directly # Set the registers args = [[Arch.n2r('eax'), 0x7d], [Arch.n2r('ebx'), addr], [Arch.n2r('ecx'), size], [Arch.n2r('edx'), prot]] chain = popMultiple(args, constraint, assertion, clmax - 1, optimizeLen) if (not chain): verbose("Failed to set registers for the mprotect syscall") return None # Int 0x80 int80_gadgets = search(QueryType.INT80, None, None, constraint, assertion) if (not int80_gadgets): verbose("Failed to find an 'int 80' gadget") return None else: chain.addChain(int80_gadgets[0]) verbose("Success") return chain
def popMultiple(args, constraint=None, assertion=None, clmax=None, addr=None, limit=None, optimizeLen=False): """ args is a list of pairs (reg, value) OR a list of triples (reg, value, comment) reg is a reg UID value is an int OR a string addr and limit are used to put strings if args contains strings Creates a chain that pops values into regs """ if (clmax is None): clmax = POP_MULTIPLE_LMAX_PER_REG * len(args) elif (clmax <= 0): return None for arg in args: if (isinstance(arg, str)): clmax += STR_TO_MEM_LMAX if (constraint is None): constr = Constraint() else: constr = constraint if (assertion is None): a = Assertion() else: a = assertion # Get address #Find address for the payload if (not addr): # Get the .bss address addr = getSectionAddress('.bss') if (not addr): return None perms = itertools.permutations(args) for perm in perms: clmax_tmp = clmax res = ROPChain() constr_tmp = constr tmp_addr = addr chains = None for arg in perm: if (len(arg) == 3): comment = arg[2] else: comment = None if (isinstance(arg[1], int)): chains = search(QueryType.CSTtoREG, arg[0], arg[1], constr_tmp, a, n=1, clmax=clmax_tmp, CSTtoREG_comment=comment, optimizeLen=optimizeLen) elif (isinstance(arg[1], str)): (address, str_to_mem) = STRtoMEM(arg[1], tmp_addr, constr_tmp, a, limit=limit, lmax=clmax_tmp, addr_str=comment, hex_info=True, optimizeLen=optimizeLen) if (not str_to_mem): break tmp_addr = address + len(arg) pop = search(QueryType.CSTtoREG, arg[0], address, constr_tmp, a, n=1, clmax=clmax_tmp - len(str_to_mem), optimizeLen=optimizeLen) if (not pop): break chains = [str_to_mem.addChain(pop[0])] else: raise Exception( "UNknown argument type in popMultiple: '{}'".format( type(arg))) if (not chains): break else: clmax_tmp -= len(chains[0]) # If Reached max length, exit if (clmax_tmp < 0): chains = None break else: res.addChain(chains[0]) constr_tmp = constr_tmp.add(RegsNotModified([arg[0]])) if (chains): return res return None
def call(args): global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON # Parsing arguments if( not args): print_help() return OUTPUT = OUTPUT_CONSOLE funcName = None i = 0 seenOutput = False seenFunction = False seenBadBytes = False seenKeepRegs = False seenShortest = False seenLmax = False clmax = None constraint = Constraint() assertion = Assertion() while i < len(args): if( args[i] in [OPTION_LIST, OPTION_LIST_SHORT]): func_list = getAllFunctions() print_functions(func_list) return if( args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]): if( seenBadBytes ): error("Error. '" + args[i] + "' option should be used only once") return if( i+1 >= len(args)): error("Error. Missing bad bytes after option '"+args[i]+"'") return seenBadBytes = True (success, res) = parse_bad_bytes(args[i+1]) if( not success ): error(res) return i = i+2 constraint = constraint.add(BadBytes(res)) elif( args[i] in [OPTION_KEEP_REGS, OPTION_KEEP_REGS_SHORT]): if( seenKeepRegs ): error("Error. '" + args[i] + "' option should be used only once") return if( i+1 >= len(args)): error("Error. Missing register after option '"+args[i]+"'") return seenKeepRegs = True (success, res) = parse_keep_regs(args[i+1]) if( not success ): error(res) return i = i+2 constraint = constraint.add(RegsNotModified(res)) elif( args[i] in [OPTION_CALL, OPTION_CALL_SHORT] ): if( not loadedBinary() ): error("Error. You should load a binary before building ROPChains") return elif( seenFunction ): error("Option '{}' should be used only once".format(args[i])) return userInput = '' i +=1 while( i < len(args) and args[i][0] != "-"): userInput += args[i] i += 1 (funcName, funcArgs ) = parseFunction(userInput) if( not funcName): return seenFunction = True elif( args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]): if( seenOutput ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing output format after option '"+args[i]+"'") return if( args[i+1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]): OUTPUT = args[i+1] seenOutput = True i += 2 else: error("Error. Unknown output format: {}".format(args[i+1])) return elif( args[i] in [OPTION_SHORTEST, OPTION_SHORTEST_SHORT]): if( seenShortest ): error("Option '{}' should be used only once".format(args[i])) return seenShortest = True i += 1 elif( args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT ): if( seenLmax ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing length after option '"+args[i]+"'") return try: clmax = int(args[i+1]) if( clmax < Arch.octets() ): raise Exception() # Convert number of bytes into number of ropchain elements clmax /= Arch.octets() except: error("Error. '" + args[i+1] +"' bytes is not valid") return i += 2 seenLmax = True elif( args[i] in [OPTION_HELP, OPTION_HELP_SHORT]): print_help() return else: error("Error. Unknown option '{}'".format(args[i])) return if( not funcName ): error("Missing function to call") else: res = build_call(funcName, funcArgs, constraint, assertion, clmax=clmax, optimizeLen=seenShortest) if( isinstance(res, str) ): error(res) else: print_chains([res], "Built matching ROPChain", constraint.getBadBytes())