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] optimizeLen = parsed_args[7] assertion = getBaseAssertion() # Search res = search(qtype, arg1, arg2, constraint, assertion, n=nbResults, clmax=clmax, optimizeLen=optimizeLen) 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 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 offset = 0 seenOffset = False seenOutput = False seenLmax = False seenBadBytes = False seenVerbose = False seenOutfile = False seenPaddingByte = False seenPaddingLen = False constraint = Constraint() assertion = getBaseAssertion() 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_OFFSET, OPTION_OFFSET_SHORT] ): if( seenOffset ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing offset after option '"+args[i]+"'") return seenOffset = True try: offset = int(args[i+1], 10) except: try: offset = int(args[i+1], 16) except: error("Error. '{}' is not a valid offset".format(args[i+1])) return if( paddingLen < 0 ): error("Error. Offset 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 and execute subcommand verbose_mode(seenVerbose) payload = None ### set offset if( not set_offset(offset)): error("Error. Your offset is too big :'(") return try: ## Execute strategy 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 # Print result verbose_mode(False) 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") except Exception, e: reset_offset() raise sys.exc_info()[1], None, sys.exc_info()[2] ### reset offset reset_offset() return
def syscall(args): global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON # Parsing arguments if( not args): print_help() return OUTPUT = OUTPUT_CONSOLE funcName = None offset = 0 i = 0 seenOutput = False seenFunction = False seenBadBytes = False seenKeepRegs = False seenOffset = False constraint = Constraint() assertion = getBaseAssertion() 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] == OPTION_OFFSET or args[i] == OPTION_OFFSET_SHORT ): if( seenOffset ): error("Error. '"+ args[i] + "' option should be used only once") return if( i+1 >= len(args)): error("Error. Missing offset after option '"+args[i]+"'") return try: offset = int(args[i+1]) if( offset < 0 ): raise Exception() except: try: offset = int(args[i+1], 16) if( offset < 0 ): raise Exception() except: error("Error. '" + args[i+1] +"' is not a valid offset") return i += 2 seenOffset = True 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: # Set offset if ( not set_offset(offset) ): error("Error. Your offset is too big :'(") return try: call(funcName, funcArgs, constraint, assertion) except Exception, e: reset_offset() import sys raise sys.exc_info()[1], None, sys.exc_info()[2] # Reset offset reset_offset()
def build_syscall_Linux(syscall, arg_list, arch_bits, constraint=None, assertion=None, clmax=SYSCALL_LMAX, optimizeLen=False): """ arch_bits = 32 or 64 :) """ # Check args if (syscall.nb_args() != len(arg_list)): error("Error. Expected {} arguments, got {}".format( len(syscall.arg_types), len(arg_list))) return None # Check args length for i in range(0, len(arg_list)): if (not verifyArgType(arg_list[i], syscall.arg_types[i])): error("Argument error for '{}': expected '{}', got '{}'".format( arg_list[i], syscall.arg_types[i], type(arg_list[i]))) return None # Check constraint and assertion if (constraint is None): constraint = Constraint() if (assertion is None): assertion = getBaseAssertion() # Check if we have the function ! verbose("Trying to call {}() function directly".format(syscall.def_name)) func_call = build_call(syscall.function(), arg_list, 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 {}(), try direct syscall".format( syscall.def_name)) else: verbose("Couldn't call {}() and return to ROPChain".format( syscall.def_name)) return None # Otherwise do syscall directly # Set the registers args = [(Arch.n2r(x[0]), x[1]) for x in zip(syscall.arg_regs, arg_list) + syscall.syscall_arg_regs ] chain = popMultiple(args, constraint, assertion, clmax - 1, optimizeLen=optimizeLen) if (not chain): verbose("Failed to set registers for the mprotect syscall") return None # Int 0x80 if (arch_bits == 32): syscall_gadgets = search(QueryType.INT80, None, None, constraint, assertion) # syscall elif (arch_bits == 64): syscall_gadgets = search(QueryType.SYSCALL, None, None, constraint, assertion) if (not syscall_gadgets): verbose("Failed to find an 'int 0x80' OR 'syscall' gadget") return None else: chain.addChain(syscall_gadgets[0]) verbose("Success") return chain
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 seenOffset = False clmax = None offset = 0 constraint = Constraint() assertion = getBaseAssertion() 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] == OPTION_OFFSET or args[i] == OPTION_OFFSET_SHORT ): if( seenOffset ): error("Option '{}' should be used only once".format(args[i])) return if( i+1 >= len(args)): error("Error. Missing offset after option '"+args[i]+"'") return try: offset = int(args[i+1]) if( offset < 0 ): raise Exception() except: try: offset = int(args[i+1], 16) if( offset < 0 ): raise Exception() except: error("Error. '" + args[i+1] +"' is not a valid offset") return i += 2 seenOffset = 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: # Set offset if( not set_offset(offset) ): error("Error. Your offset is too big :'(") return try: 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()) except Exception, e: reset_offset() raise sys.exc_info()[1], None, sys.exc_info()[2] # Reset offset reset_offset()