def load(args): if (len(args) > 0): filename = args[0] msg = string_bold( "Extracting gadgets from file") + " '" + filename + "'" if (len(args) > 1): msg += " (Ignoring extra arguments '" msg += ', '.join(args[1:]) msg += "')" info_colored(msg + '\n') else: print( string_bold("\n\tMissing argument.\n\tType 'load help' for help")) # Cleaning the data structures Gadget.reinit() Database.reinit() Analysis.reinit() SearchHelper.reinit() if (generate_opcodes.generate(filename)): BinaryScanner.set_binary(filename) Database.generated_gadgets_to_DB() Database.simplifyGadgets() Database.gadgetLookUp.fill()
def show_shellcodes(arch): global native_shellcodes global custom_shellcodes global selected_shellcode if (arch not in Analysis.supportedArchs): print( string_bold( "\n\tError. Architecture {} is not supported".format(arch))) return print(string_bold('\n\t------------------------------------')) print(string_bold("\tAvailable payloads for arch " + string_special(arch))) if (selected_shellcode[arch] == 0): print("\t(Currently selected: None)") else: print("\t(Currently selected: {})".format( string_payload(str(selected_shellcode[arch])))) print(string_bold('\t------------------------------------')) if ((not native_shellcodes[arch]) and (not custom_shellcodes[arch])): print("\n\tNo payloads available for architecture " + arch) i = 0 for shellcode in custom_shellcodes[arch] + native_shellcodes[arch]: i = i + 1 if (i == selected_shellcode[arch]): number = "(" + ROPGENERATOR_COLOR_ANSI + "*" + END_COLOR_ANSI + ")" else: number = "({})".format(string_bold(str(i))) print("\n\t{} {}\n\t{} - {} bytes".format(number, shellcode[1], \ string_special(short_shellcode(shellcode[0])), str(len(shellcode[0]))))
def show_context(): print(string_bold("\n\tROPGenerator's current context:\n")) print(string_bold("\t{}:\t\t".format(ASLR)) + b2s(values[ASLR])) print(string_bold("\t{}:\t\t".format(NX)) + b2s(values[NX])) print(string_bold("\t{}:\t\t".format(BAD_BYTES)) + \ ','.join([string_special(b) for b in values[BAD_BYTES]])) print("")
def print_config(): global ARCH global PATH_ROPGADGET global LIMIT print(string_bold("\n\tROPGenerator's current configuration:\n")) print(string_bold("\tropgadget:\t") + PATH_ROPGADGET) print(string_bold("\tlimit:\t\t") + str(LIMIT)) print("")
def remove_payload(): print(string_bold('\n\t--------------------\n\tRemoving a payload\n\t--------------------\n')) arch_input = '' while( not arch_input in Analysis.supportedArchs ): sys.stdout.write('\t'+ROPGENERATOR_COLOR_ANSI+'> '+END_COLOR_ANSI+'Enter the payload architecture ({}):\n\t'.format\ (','.join([string_special(s) for s in Analysis.supportedArchs]))) arch_input = prompt(u"") show_shellcodes(arch_input) print("") choice = '' ok = False while( not ok ): sys.stdout.write('\t'+ROPGENERATOR_COLOR_ANSI+'> '+END_COLOR_ANSI+'Select a payload to remove:\n\t') choice_input = prompt(u"") try: choice = int(choice_input) ok = remove_shellcode(arch_input, choice) except: ok = False print("") notify('Payload removed')
def add_payload(): print(string_bold('\n\t----------------------\n\tAdding a new payload\n\t----------------------\n')) arch_input = '' while( not arch_input in Analysis.supportedArchs ): sys.stdout.write('\t'+ROPGENERATOR_COLOR_ANSI+'> '+END_COLOR_ANSI+'Enter the target architecture ({}):\n\t'.format\ (','.join([string_special(s) for s in Analysis.supportedArchs]))) arch_input = prompt(u"") shellcode = '' ok = False while( not ok ): sys.stdout.write('\t'+ROPGENERATOR_COLOR_ANSI+'> '+END_COLOR_ANSI+'Enter your payload as a string in hex format:\n\t') shellcode_input = prompt(u"") try: shellcode = shellcode_input.replace('\\x','').decode('hex') ok = True except: ok = False if( not ok ): print(string_special("\tError. Your payload input is in wrong format or invalid")) sys.stdout.write('\t'+ROPGENERATOR_COLOR_ANSI+'> '+END_COLOR_ANSI+'Enter short payload description:\n\t') info = prompt(u"") info = filter( lambda x: x in set(string.printable), info) add_shellcode(arch_input, shellcode, info)
def select_payload(): if( Database.gadgetDB ): arch_input = Analysis.ArchInfo.currentArch print("") notify('Detected architecture from loaded binary: ' + string_special(arch_input)) else: print(string_bold('\n\tOops! You should load a binary before selecting a payload')) return show_shellcodes(arch_input) print("") choice = '' ok = False while( not ok ): sys.stdout.write('\t'+ROPGENERATOR_COLOR_ANSI+'> '+END_COLOR_ANSI+'Select a payload number:\n\t') choice_input = prompt(u"") try: choice = int(choice_input) ok = select_shellcode(arch_input, choice) except: ok = False if( not ok ): print(string_special("\tError. Invalid payload number\n")) show_selected()
def update_config(args): """ Update config with user supplied args """ if (len(args) == 1 and args[0] == 'show'): print_config() return info_colored(string_bold("Updating configuration\n")) for arg in args: arg_list = arg.split('=') left = arg_list[0] if (len(arg_list) < 2): notify("Error. Missing right part in argument " + arg) return else: right = arg_list[1] if (left == "arch"): set_arch(right) elif (left == "ropgadget"): set_ropgadget(right) elif (left == "limit"): set_limit(right) else: notify("Ignored unknown parameter '" + left + "'")
def show_selected(): if( not Database.gadgetDB ): print(string_bold("\n\tOops! You should load a binary before selecting a payload")) return else: arch = Analysis.ArchInfo.currentArch if( selected_shellcode[arch] == 0 ): print(string_bold("\n\tNo payload selected for architecture ") + string_special(arch)) return print(string_bold('\n\t-------------------------------')) print(string_bold("\tSelected payload - arch " + string_special(arch))) print(string_bold('\t-------------------------------')) (shellcode, info) = selected(arch) print("\n\t{}\n\n{} - {} bytes".format( info, \ string_special(pack_shellcode(shellcode)), str(len(shellcode))))
def generate(filename): """ Returns true if success, false otherwise """ global opcodes_file if (not os.path.isfile(filename)): print( string_bold( "\n\tError. Could not find file '{}'".format(filename))) return False binType = check_binaryType(filename) if (not binType): error_colored("Could not determine architecture for binary: " + filename + "\n") return False else: Config.set_arch(binType, quiet=True) ropgadget = Config.PATH_ROPGADGET notify("Executing ROPgadget as: " + ropgadget) try: p = subprocess.Popen( [ropgadget, "--binary", filename, "--dump", "--all"], stdout=subprocess.PIPE) except Exception as e: error_colored("Could not execute ' " + ropgadget + " --binary " + filename + " --dump '") print("\tError message is: " + str(e)) print( "\n\t(Maybe check/update your config with the 'config' command, or make sure you have the last ROPgadget version installed)" ) return False f = open(opcodes_file, "w") # Write gadgets first = True count = 0 for l in p.stdout.readlines(): if ("0x" in l): arr = l.split(' ') addr = arr[0] gadget = arr[-1] it = iter(gadget) gadget = ''.join(a + b for a, b in zip(it, it)) f.write(addr + '#') f.write(gadget + '\n') count += 1 f.close() notify("Finished : %d gadgets generated" % (count)) return (count > 0)
def set_context(args): for arg in args: try: (left,right)=arg.split('=') if( not left or not right ): print(string_bold("\n\tError. Invalid parameter {}".format(arg))) return except: print(string_bold("\n\tError. Invalid parameter {}".format(arg))) return if( left in [ASLR, NX] ): if( right not in ['yes', 'no']): print(string_bold("\n\tError. Invalid {} value: {}".format(left, right))) return values[left]= s2b(right) elif( left == BAD_BYTES ): print(string_bold("\n\tError. Bad bytes not supported yet for context. Comming soon ;) ".format(left, right))) return else: print(string_bold("\n\tError. Unknown parameter: {}".format(left))) return
def payload(args): # Parsing arguments if( args[0] == 'current' ): show_selected() elif( args[0] == 'list' ): list_payloads(args[1:]) elif( args[0] == 'add' ): add_payload() elif( args[0] == 'select'): select_payload() elif( args[0] == 'remove' ): remove_payload() else: print(string_bold("\n\tError. Unknown sub-command '{}'".format(args[0]))) return
def pretty_print_registers(): if (not gadgetDB): print( "You should generate gadgets before looking at the registers. Type 'load help' for help" ) else: print(string_bold("\n\tRegisters present in the gadget database:")) print( string_special("\t(Architeture is '" + Analysis.ArchInfo.currentArch + "')\n")) for reg in Analysis.regNamesTable.keys(): if (reg == Analysis.ArchInfo.ip): print('\t' + reg + string_special(" (instruction pointer)")) elif (reg == Analysis.ArchInfo.sp): print('\t' + reg + string_special(" (stack pointer)")) else: print('\t' + reg)
def build_REG_write_to_memory(): global record_REG_write_to_memory global built_REG_write_to_memory if (built_REG_write_to_memory): return # Initialization for printing charging bar chargingBarSize = Analysis.ssaRegCount chargingBarStr = " " * chargingBarSize info_colored( string_bold("Performing additionnal analysis") + ": writing registers on stack\n") sys.stdout.write("\tProgression [") sys.stdout.write(chargingBarStr) sys.stdout.write("]\r\tProgression [") sys.stdout.flush() # Initializing the dictionnaries for reg in range(0, Analysis.ssaRegCount): record_REG_write_to_memory[reg] = dict() for reg2 in range(0, Analysis.ssaRegCount): record_REG_write_to_memory[reg][reg2] = dict() # Filling the dictionnaries : db = Database.gadgetLookUp[GadgetType.REGtoMEM] for reg in range(0, Analysis.ssaRegCount): # Printing the charging bar sys.stdout.write("|") sys.stdout.flush() for i in range(0, len(db.addr_list)): addr = db.addr_list[i] # We want to store only addresses of type REG +-/* CST (isInc, inc) = addr.isRegIncrement(addr) if (isInc): add_REG_write_to_memory(reg, reg_list[0], offset, [ g for g in db.written_values[i] if Database.gadgetDB[g].hasNormalRet() and Database.gadgetDB[g].isValidSpInc() ]) sys.stdout.write("\r" + " " * 70 + "\r") built_REG_write_to_memory = True
def simplifyGadgets(): """ Apply some simplifications on the gadget dependencies """ chargingBarSize = 30 chargingBarStr = " " * chargingBarSize i = 0 info_colored(string_bold("Processing gadgets\n")) for gadget in gadgetDB: charging_bar(len(gadgetDB) - 1, i, 30) gadget.getDependencies().simplifyConditions() i = i + 1 # Second pass analysis once all gadgets are collected for gadget in gadgetDB: gadget.calculateSpInc() gadget.calculateRet() gadget.calculatePreConstraint()
def run_payload(): """ Builds an exploit that aims at executing a payload """ # get the shellcode (payload, payload_info) = selected(Analysis.ArchInfo.currentArch) if (not payload): print( string_bold("\n\tError, no payload selected :/" + "\n\tCheck the 'payload select' command ")) return # Check context Context.check_context() # Build exploit exploit = build_mprotect_datareuse(payload) return exploit
def check_context(): info_colored(string_bold('Checking exploit context\n')) notify('NX stack: ' + b2s(values[NX])) notify('ASLR: ' + b2s(values[NX])) notify('Forbidden bytes in exploit: ' +\ ','.join([string_special(b) for b in values[BAD_BYTES]]))
def fill(self): def filter_cond(condition): if (condition.isTrue()): return None else: return condition # Initialize the data structures ! self.types[GadgetType.CSTtoMEM] = cstToMemLookUp() self.types[GadgetType.REGEXPRtoMEM] = exprToMemLookUp() self.types[GadgetType.MEMEXPRtoMEM] = exprToMemLookUp() for reg_num in Analysis.revertRegNamesTable.keys(): self.types[GadgetType.CSTtoREG][reg_num] = cstLookUp() self.types[GadgetType.REGEXPRtoREG][reg_num] = exprLookUp(reg_num) self.types[GadgetType.MEMEXPRtoREG][reg_num] = exprLookUp(reg_num) # Initialize the printed charging bar chargingBarSize = 30 chargingBarStr = " " * chargingBarSize info_colored(string_bold("Sorting gadgets semantics\n")) # Update the gadgetLookUp table for i in range(0, len(gadgetDB)): charging_bar(len(gadgetDB) - 1, i, 30) gadget = gadgetDB[i] # Check for special gadgets (int 0x80 and syscall if (gadget.sort == GadgetSort.INT80): self.list_int80.append(i) continue elif (gadget.sort == GadgetSort.SYSCALL): self.list_syscall.append(i) continue # For XXXtoREG for reg, deps in gadget.getDependencies().regDep.iteritems(): for dep in deps: # For REGEXPRtoREG if (isinstance(dep[0], Expr.SSAExpr)): self.types[GadgetType.REGEXPRtoREG][ reg.num].add_gadget(dep[0].reg.num, 0, i, condition=filter_cond(dep[1])) elif (isinstance(dep[0], Expr.Op)): (isInc, num, inc) = dep[0].isRegIncrement(-1) if (isInc): self.types[GadgetType.REGEXPRtoREG][ reg.num].add_gadget(num, inc, i, condition=filter_cond( dep[1])) # For CSTtoREG elif (isinstance(dep[0], Expr.ConstExpr)): self.types[GadgetType.CSTtoREG][reg.num].add_gadget( dep[0].value, i, condition=filter_cond(dep[1])) # For MEMEXPRtoREG elif (isinstance(dep[0], Expr.MEMExpr)): if (isinstance(dep[0].addr, Expr.SSAExpr)): self.types[GadgetType.MEMEXPRtoREG][ reg.num].add_gadget(dep[0].addr.reg.num, 0, i, condition=filter_cond( dep[1])) elif (isinstance(dep[0].addr, Expr.Op)): (isInc, num, inc) = dep[0].addr.isRegIncrement(-1) if (isInc): self.types[GadgetType.MEMEXPRtoREG][ reg.num].add_gadget(num, inc, i, condition=filter_cond( dep[1])) # If we found a true dependency, no need to check others #if( dep[1].isTrue()): # break # For XXXtoMEM for addr, deps in gadget.getDependencies().memDep.iteritems(): addr_reg = None addr_cst = None # Check if the address is of type REG + CST if (isinstance(addr, Expr.SSAExpr)): addr_reg = addr.reg.num addr_cst = 0 elif (isinstance(addr, Expr.Op)): (isInc, addr_reg, addr_cst) = addr.isRegIncrement(-1) if (not isInc): continue else: continue # Going through dependencies for dep in deps: # Check for integrity of the database if (not isinstance(dep[0], Expr.Expr)): raise Exception( "Invalid dependency in fillGadgetLookUp(): " + str(dep[0])) # For REGEXPRtoMEM if (isinstance(dep[0], Expr.SSAExpr)): self.types[GadgetType.REGEXPRtoMEM].add_gadget(addr_reg, \ addr_cst, dep[0].reg.num, 0, i,condition=filter_cond(dep[1])) elif (isinstance(dep[0], Expr.Op)): (isInc, num, inc) = dep[0].isRegIncrement(-1) if (isInc): self.types[GadgetType.REGEXPRtoMEM].add_gadget(addr_reg,\ addr_cst, num, inc, i,condition=filter_cond(dep[1])) # For CSTtoMEM elif (isinstance(dep[0], Expr.ConstExpr)): self.types[GadgetType.CSTtoMEM].add_gadget(addr_reg, \ addr_cst, dep[0].value, i,condition=filter_cond(dep[1])) # For MEMEXPRtoMEM elif (isinstance(dep[0], Expr.MEMExpr)): if (isinstance(dep[0].addr, Expr.SSAExpr)): self.types[GadgetType.MEMEXPRtoMEM].add_gadget(addr_reg,\ addr_cst, dep[0].addr.reg.num, 0, i,condition=filter_cond(dep[1])) elif (isinstance(dep[0].addr, Expr.Op)): (isInc, num, inc) = dep[0].addr.isRegIncrement(-1) if (isInc): self.types[GadgetType.MEMEXPRtoMEM].add_gadget(addr_reg,\ addr_cst, num, inc, i,condition=filter_cond(dep[1])) # If we found a true dependency, no need to check others #if( dep[1].isTrue()): # break # Clean the charging bar sys.stdout.write("\r" + " " * 70 + "\r")
# ROPGenerator - Config.py module # Stores the configuration for the tool import ropgenerator.Analysis as Analysis from ropgenerator.Colors import notify, string_special, string_bold, info_colored, error_colored, BOLD_COLOR_ANSI, END_COLOR_ANSI import os # Help for the config command CMD_CONFIG_HELP = string_bold("\n\t------------------------------") CMD_CONFIG_HELP += string_bold("\n\tROPGenerator 'config' command\n\t") CMD_CONFIG_HELP += string_special("(Configure ROPGenerator)") CMD_CONFIG_HELP += string_bold("\n\t------------------------------") CMD_CONFIG_HELP += "\n\n\t" + string_bold( "Usage" ) + ":\tconfig show\n\t\tconfig <parameter>=<value> [<parameter>=<value> ...]" CMD_CONFIG_HELP += "\n\n\t" + string_bold( "Parameters" ) + ":\n\t\t" + string_special( "ropgadget" ) + ':\tcommand to run ROPgadget tool (typically\n\t\t\t\t"ROPgadget" or "/path/to/ROPgadget.py")\n\t\t' + string_special( "limit") + ':\t\tnumber of matching gadgets to find for a query' CMD_CONFIG_HELP += "\n\n\t" + string_bold( "Examples" ) + ":\n\t\tconfig ropgadget=ROPgadget\n\t\tconfig ropgadget=/usr/ROPgadget.py limit=4" # ROPGENERATOR CONIGURATION DEFAULT DEFAULT_ARCH = "X86-64" DEFAULT_PATH_ROPGADGET = "ROPgadget" DEFAULT_LIMIT = 3 ARCH = DEFAULT_ARCH PATH_ROPGADGET = DEFAULT_PATH_ROPGADGET
def print_exploit(exploit, output, outstream, colors=True): """ Exploit format is a list of pairs (ropchain, description) """ if (not colors): disable_colors() if (output == OUTPUT_CONSOLE): print( string_bold("\n\tBuilt exploit - {} bytes\n".format( (Analysis.ArchInfo.bits / 8) * sum([len(chain) for (chain, info) in exploit])))) for (chain, info) in exploit: info_string = string_bold( "\t" + '-' * len(info) + '\n') + string_exploit( '\t' + info + '\n') + string_bold("\t" + '-' * len(info) + '\n') outstream.write(info_string) for gadget_num in chain: if (SearchHelper.is_padding(gadget_num)): padding_str = string_special( '0x' + format(SearchHelper.get_padding_unit(gadget_num), '0' + str(Analysis.ArchInfo.bits / 4) + 'x')) if (gadget_num == SearchHelper.DEFAULT_PADDING_UNIT_INDEX): padding_str += " (Padding)" elif (gadget_num in SearchHelper.num_to_str): padding_str += " (" + SearchHelper.num_to_str[ gadget_num] + ")" elif (SearchHelper.get_padding_unit(gadget_num) in SearchHelper.addr_to_gadgetStr): padding_str += " (" + SearchHelper.addr_to_gadgetStr[ SearchHelper.get_padding_unit(gadget_num)] + ")" else: padding_str += " (Custom Padding)" outstream.write("\t" + padding_str + "\n") else: outstream.write( "\t" + string_special(Database.gadgetDB[gadget_num].addrStr) + " (" + string_bold(Database.gadgetDB[gadget_num].asmStr) + ")\n") elif (output == OUTPUT_PYTHON): # Getting endianness to pack values if (Analysis.ArchInfo.bits == 32): endianness_str = '<I' else: endianness_str = '<Q' pack_str = "p += pack(" + endianness_str + "," # Printing outstream.write( string_bold("\n\tBuilt exploit - {} bytes\n".format( (Analysis.ArchInfo.bits / 8) * sum([len(chain) for (chain, info) in exploit]))) + '\n') outstream.write(string_bold("\t#" + '-------------\n')) outstream.write(string_exploit('\t# Padding here\n')) outstream.write(string_bold("\t#" + '-------------\n')) outstream.write("\tp = ''\n") for (chain, info) in exploit: outstream.write(string_bold("\t# " + '-' * len(info)) + '\n') outstream.write(string_exploit('\t# ' + info) + '\n') outstream.write(string_bold("\t# " + '-' * len(info)) + '\n') for gadget_num in chain: if (SearchHelper.is_padding(gadget_num)): padding_str = pack_str padding_str += string_special('0x' + format( SearchHelper.get_padding_unit(gadget_num), '0' + str(Analysis.ArchInfo.bits / 4) + 'x')) + ")" if (gadget_num == SearchHelper.DEFAULT_PADDING_UNIT_INDEX): padding_str += " # Padding" elif (gadget_num in SearchHelper.num_to_str): padding_str += " # " + SearchHelper.num_to_str[ gadget_num] elif (SearchHelper.get_padding_unit(gadget_num) in SearchHelper.addr_to_gadgetStr): padding_str += " # " + SearchHelper.addr_to_gadgetStr[ SearchHelper.get_padding_unit(gadget_num)] else: padding_str += " # Custom Padding" outstream.write("\t" + padding_str + "\n") else: outstream.write( "\t" + pack_str + string_special(Database.gadgetDB[gadget_num].addrStr) + ") # " + string_bold(Database.gadgetDB[gadget_num].asmStr) + '\n') elif (output == OUTPUT_RAW): print("\tRaw output not supported yet :'( ") enable_colors()
def build_mprotect_datareuse(payload): """ Build a ROPchain that does : - mprotect RWX to a static memory area - copy payload to this memory area - jmp to payload """ info_colored(string_bold('Building mprotect + datareuse exploit\n')) # Get the initial constraint constraint = Constraint().add(ConstraintType.BAD_BYTES, Context.bad_bytes()) # Then get address of the bss notify('Getting .bss address') bss_addr = BinaryScanner.bss_address() if (not bss_addr): info("Could not find static .bss section to copy payload to") return [] else: info("Found .bss at address: " + hex(bss_addr)) # Then get the mprotect chain notify('Building mprotect ropchain to make .bss RWX') if (Analysis.ArchInfo.currentArch == "X86-64"): mprotect_chain = mprotect_X64(bss_addr, len(payload) + 1, 7) elif (Analysis.ArchInfo.currentArch == "X86"): mprotect_chain = mprotect_X86(bss_addr, len(payload) + 1, 7) else: info("mprotect chain for arch '{}' not supported yet".format( Analysis.ArchInfo.currentArch)) return [] if (not mprotect_chain): info("Could not build mprotect chain") return [] mprotect_info = "Create RWX memory : calling mprotect({},{},{})".format( hex(bss_addr), len(payload) + 1, 7) # Then write shellcode in memory notify('Building data-reuse chain to copy payload into .bss') datareuse = search.str_to_mem(bss_addr, '.bss', payload, constraint.add(ConstraintType.CHAINABLE_RET, []), hex_info=True) if (not datareuse): info("Could not build datareuse chain") return [] datareuse_info = "Copy payload into custom RWX memory" notify('Building a chain to jump to .bss and execute payload') # Then jump to the payload ip_num = Analysis.regNamesTable[Analysis.ArchInfo.ip] jmp_payload = search.jmp_addr(bss_addr, constraint) if (not jmp_payload): info("Could not build jmp_payload chain") return [] jmp_payload_info = "Jump to payload" # Concatenate to full exploit return [[mprotect_chain, mprotect_info], [datareuse, datareuse_info], [jmp_payload, jmp_payload_info]]
def exploit(args): # Parse args i = 0 verbose = False output = OUTPUT_CONSOLE outfile = sys.stdout seenOutput = False seenOutfile = False colors = True while (i < len(args) and args[i][0] == '-'): if (args[i] == OPTION_VERBOSE or args[i] == OPTION_VERBOSE_SHORT): verbose = True elif (args[i] == OPTION_OUTPUT or args[i] == OPTION_OUTPUT_SHORT): if (seenOutput): print( string_bold("\n\tError. '" + OPTION_OUTPUT + "' option should be used only once.")) return if (i + 1 >= len(args)): print( string_bold( "\n\tError. Missing output format after option '" + args[i] + "'")) return if (args[i + 1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]): output = args[i + 1] seenOutput = True i = i + 1 else: print( string_bold("\n\tError. '" + args[i + 1] + "' output format is not supported")) return elif (args[i] == OPTION_OUTFILE or args[i] == OPTION_OUTFILE_SHORT): if (seenOutfile): print( string_bold("\n\tError. '" + OPTION_OUTFILE + "' option should be used only once.")) return if (i + 1 >= len(args)): print( string_bold( "\n\tError. Missing output format after option '" + args[i] + "'")) return try: outfile = open(args[i + 1], "w") seenOutfile = True colors = False # No ANSI colors when writing in file i = i + 1 except: print( string_bold("\n\tError. Could not open file '{}'".format( args[i + 1]))) return else: print(string_bold("\n\tUnknown option '{}'".format(args[i]))) return i = i + 1 # Process options verbose_mode(verbose) if (i == len(args)): print( string_bold( "\n\tMissing sub-command\n\tType 'exploit help' for help". format(args[0]))) return # BuIld exploit if (args[i] == 'run-payload'): exploit_chain = run_payload() if (exploit_chain): print_exploit(exploit_chain, output, outfile, colors) else: print(string_bold("\n\tFailed to build exploit")) else: print(string_bold("\n\tSub-command '{}' not supported".format( args[0]))) # Restore normal state verbose_mode(False) # Close output stream if (seenOutfile): outfile.close()
# RPGEnerator - Load.py module # Read a binary and load the gadgets contained in the file import ropgenerator.Database as Database import ropgenerator.Analysis as Analysis import ropgenerator.generate_opcodes as generate_opcodes import ropgenerator.SearchHelper as SearchHelper import ropgenerator.Gadget as Gadget import ropgenerator.BinaryScanner as BinaryScanner from ropgenerator.Colors import string_bold, info_colored, BOLD_COLOR_ANSI, END_COLOR_ANSI, string_special # Help for the load command CMD_LOAD_HELP = string_bold("\n\t---------------------------------") CMD_LOAD_HELP += string_bold("\n\tROPGenerator 'load' command\n\t") CMD_LOAD_HELP += string_special("(Load gadgets from a binary file)") CMD_LOAD_HELP += string_bold("\n\t---------------------------------") CMD_LOAD_HELP += "\n\n\t" + string_bold( "Usage") + ":\tload [OPTIONS] <filename>" CMD_LOAD_HELP += "\n\n\t" + string_bold( "Options") + ": No options available for the moment" CMD_LOAD_HELP += "\n\n\t" + string_bold( "Examples" ) + ":\n\t\tload /bin/ls\t\t(load gadgets from /bin/ls program)\n\t\tload ../test/vuln_prog\t(load gadgets from own binary)" def print_help(): print(CMD_LOAD_HELP) def load(args):
# Options OPTION_VERBOSE = '--verbose' OPTION_OUTPUT = '--output-format' OPTION_OUTFILE = '--output-file' # Short options OPTION_VERBOSE_SHORT = '-v' OPTION_OUTPUT_SHORT = '-f' OPTION_OUTFILE_SHORT = '-o' # Options for output OUTPUT_CONSOLE = 'console' OUTPUT_PYTHON = 'python' OUTPUT_RAW = 'raw' # Help CMD_EXPLOIT_HELP = string_bold("\n\t-------------------------------") CMD_EXPLOIT_HELP += string_bold("\n\tROPGenerator 'exploit' command\n\t") CMD_EXPLOIT_HELP += string_special("(Build exploits automatically)") CMD_EXPLOIT_HELP += string_bold("\n\t-------------------------------") CMD_EXPLOIT_HELP += "\n\n\t" + string_bold( "Usage") + ":\texploit [OPTIONS] <" + string_ropg("subcommand") + ">" CMD_EXPLOIT_HELP += "\n\n\t"+string_bold("Sub-commands")+":"+\ "\n\t\t"+string_ropg("run-payload")+"\t("+string_special('build an exploit that runs the selected payload')+")" CMD_EXPLOIT_HELP += "\n\n\t" + string_bold("Options") + ":" CMD_EXPLOIT_HELP += "\n\t\t" + string_special( OPTION_VERBOSE_SHORT) + "," + string_special(OPTION_VERBOSE) CMD_EXPLOIT_HELP += "\n\t\t" + string_special( OPTION_OUTPUT_SHORT) + "," + string_special( OPTION_OUTPUT) + " <" + '|'.join( [string_special(g) for g in [OUTPUT_CONSOLE, OUTPUT_PYTHON]]) + ">" CMD_EXPLOIT_HELP += "\n\t\t" + string_special(
import ropgenerator.Context as Context import ropgenerator.exploit.Exploit as Exploit import ropgenerator.Logs as Logs from prompt_toolkit import PromptSession from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.completion import WordCompleter from prompt_toolkit.styles import Style import sys import cProfile, pstats ASCII_art = string_bold(""" ___ ____ ___ _____ __ / _ \/ __ \/ _ \/ ______ ___ ___ _______ _/ /____ ________ / , _/ /_/ / ___/ (_ / -_/ _ / -_/ __/ _ `/ __/ _ \/ ______/ /_/|_|\____/_/ \___/\__/_//_\__/_/ \_,_/\__/\___/_/ v0.5 """) # Definitions of commands CMD_HELP = "help" CMD_LOAD = "load" CMD_REGISTERS = "registers" CMD_FIND = "find" CMD_PAYLOAD = "payload" CMD_CONTEXT = "context" CMD_CONFIG = "config" CMD_EXPLOIT = "exploit" CMD_EXIT = "exit"
def main(time_mesure=False): if (time_mesure): pr = cProfile.Profile() pr.enable() style = Style.from_dict({ 'prompt': '#00FF00', }) message = [ (u'class:prompt', u'>>> '), ] #try: # Launching ROPGenerator write_colored(ASCII_art) Config.load_config() Logs.init() session = PromptSession() quit = False while (not quit): try: user_input = session.prompt(message, style=style) args = user_input.split() argslen = len(args) if (argslen > 0): command = args[0] else: command = None if (command == None): pass elif (command == CMD_HELP): print( string_bold( "\n\t-----------------------------------------------------------\n\tROPGenerator commands" )) print( string_special( "\t(For more information about a command type '<command> help')" )) print( string_bold( "\t-----------------------------------------------------------\n" )) print('\t' + string_bold(CMD_LOAD) + ': \t\tload usable gadgets from a binary file') print('\t' + string_bold(CMD_FIND) + ': \t\tsemantic search for gadgets/ropchains') print('\t' + string_bold(CMD_PAYLOAD) + ': \tmanage payloads to use in your exploit') print('\t' + string_bold(CMD_EXPLOIT) + ':\tbuild an exploit') print( '\t' + string_bold(CMD_REGISTERS) + ': \tprint available registers for the current architecture' ) print('\t' + string_bold(CMD_CONFIG) + ': \tconfigure ROPGenerator') print('\t' + string_bold(CMD_HELP) + ': \t\tprint available commands') print('\t' + string_bold(CMD_EXIT) + ': \t\texit ROPGenerator') elif (command == CMD_FIND): if (argslen > 1): if (args[1] == CMD_HELP): SearchEngine.print_help() else: SearchEngine.set_user_input(user_input[len(CMD_FIND):]) SearchEngine.find_gadgets(args[1:]) else: SearchEngine.print_help() #print("Missing arguments. Type 'find help' for help") elif (command == CMD_EXPLOIT): if (argslen > 1): if (args[1] == CMD_HELP): Exploit.print_help() else: Exploit.exploit(args[1:]) else: Exploit.print_help() elif (command == CMD_PAYLOAD): if (argslen > 1): if (args[1] == CMD_HELP): Payload.print_help() else: Payload.payload(args[1:]) else: Payload.print_help() #print("Missing arguments. Type 'payload help' for help") elif (command == CMD_LOAD): if (argslen > 1): if (args[1] == CMD_HELP): Load.print_help() else: Load.load(args[1:]) else: Load.print_help() #print("Missing arguments. Type 'load help' for help") elif (command == CMD_REGISTERS): pretty_print_registers() elif (command == CMD_CONFIG): if (argslen > 1): if (args[1] == CMD_HELP): Config.print_help() else: Config.update_config(args[1:]) else: Config.print_help() #print("Missing arguments. Type 'config help' for help") elif (command == CMD_CONTEXT): if (argslen > 1): if (args[1] == CMD_HELP): Context.print_help() else: Context.context(args[1:]) else: Context.print_help() elif (command == CMD_EXIT): quit = True Config.save_config() Payload.save_payloads() else: print(string_bold("\n\tUnknown command '" + command+\ "'. Type 'help' for available commands")) # New line if (command != None): print("") except KeyboardInterrupt: pass info_colored(string_bold("Closing ROPGenerator...\n")) #except KeyboardInterrupt: # pass #except Exception as e: # print("") # error_colored("ROPGenerator failed unexpectedly\n") # print(e) if (time_mesure): pr.disable() s = pstats.Stats(pr).sort_stats('tottime') s.print_stats(0.02) exit(0)
# Manage the context for exploit development from ropgenerator.Colors import string_special, string_bold, notify, info_colored # Context parameters ASLR='ASLR' NX='NX' BAD_BYTES='BAD-BYTES' # Default values values = dict() values[ASLR]=True values[NX]=True values[BAD_BYTES]=[] # Help for the context command CMD_CONTEXT_HELP = string_bold("\n\t-----------------------------------") CMD_CONTEXT_HELP += string_bold("\n\tROPGenerator 'context' command\n\t") CMD_CONTEXT_HELP += string_special("(Set a security context for your exploit)") CMD_CONTEXT_HELP += string_bold("\n\t-----------------------------------") CMD_CONTEXT_HELP += "\n\n\t"+string_bold("Usage")+":\tcontext show\n\t\tcontext <parameter>=<value> [<parameter>=<value> ...]" CMD_CONTEXT_HELP += "\n\n\t"+string_bold("Parameters")+\ ":\n\t\t"+string_bold('Name'+"\t\tValues")+\ "\n\t\t"+string_special(ASLR)+":\t\t'yes'/'no'"+\ "\n\t\t"+string_special(NX)+":\t\t'yes'/'no'"+\ "\n\t\t"+string_special(BAD_BYTES)+':\tlist of bad bytes' CMD_CONTEXT_HELP += "\n\n\t"+string_bold("Examples")+":\n\t\tcontext ASLR=yes\n\t\tcontext ASLR=no NX=yes" def print_help(): print(CMD_CONTEXT_HELP)
# ROPGenerator - PAYLOAD module # Building PAYLOADs from ropgenerator.Colors import BOLD_COLOR_ANSI, END_COLOR_ANSI, string_bold, info_colored, string_special, ROPGENERATOR_COLOR_ANSI, notify from ropgenerator.payload.Shellcode import remove_shellcode, show_shellcodes, save_shellcodes, add_shellcode, select_shellcode, show_selected from prompt_toolkit import prompt import ropgenerator.Analysis as Analysis import sys import string import ropgenerator.Database as Database CMD_PAYLOAD_HELP = string_bold("\n\t------------------------------------") CMD_PAYLOAD_HELP += string_bold("\n\tROPGenerator 'payload' command\n\t") CMD_PAYLOAD_HELP += string_special("(Manage payloads for your exploit)") CMD_PAYLOAD_HELP += string_bold("\n\t------------------------------------") CMD_PAYLOAD_HELP += "\n\n\t"+string_bold("Usage")+\ ":\tpayload current \t(" + string_special('show currently selected payload') + ")" +\ "\n\t\tpayload list [<arch>]\t(" + string_special('list available payloads') + ")" +\ "\n\t\tpayload select \t\t(" + string_special('select a payload for your exploit') + ")" +\ "\n\t\tpayload add\t\t("+ string_special('add a payload to your exploit') + ")"+\ "\n\t\tpayload remove\t\t("+string_special('remove a previously added payload') + ")" CMD_PAYLOAD_HELP += "\n\n\t"+string_bold("Supported architectures")+": "+','.join([string_special(arch) for arch in Analysis.supportedArchs]) def print_help(): print(CMD_PAYLOAD_HELP) def payload(args): # Parsing arguments if( args[0] == 'current' ): show_selected() elif( args[0] == 'list' ): list_payloads(args[1:])
def generated_gadgets_to_DB(): """ Generates the list of the available gadgets for ROP Usage : must be called after the gadgets opcodes have been stored into the opcodes_gadget array in Generated_opcodes.py file. Result : No value returned. But the gadgets are stored in the gadgets[] array in Database module. """ global sigint global current_gadget global old_stdout global old_stderr def sigint_handler(signal, frame): global sigint sigint = True # Read all gadgets that have been generated ! f = open(opcodes_file, "r") asmGadgets = [] for line in f: (addr, instr) = line[:-1].split('#') addr = int(addr, 16) instr = instr.decode("hex") asmGadgets.append((addr, instr)) f.close() # Sort the gadgets according to their instructions asmGadgets.sort(key=lambda x: x[1]) # Analyze them junk_file = open("/dev/null", "w") i = 0 success = 0 warnings = 0 info_colored( string_bold("Working under architecture: ") + Analysis.ArchInfo.currentArch + '\n') info_colored(string_bold("Creating gadget database\n")) warnings_file = ROPGENERATOR_DIRECTORY + "warnings-logs" f = open(warnings_file, "w") original_sigint_handler = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, sigint_handler) startTime = datetime.now() for g in asmGadgets: if (sigint): break asm = g[1] addr = g[0] try: charging_bar(len(asmGadgets) - 1, i, 30) #print("Gadget : " + '\\x'.join(["%02x" % ord(c) for c in asm]) + "\n") sys.stdout = sys.stderr = junk_file signal.alarm(1) gadget = Gadget(i, addr, asm) signal.alarm(0) sys.stdout = old_stdout sys.stderr = old_stderr success += 1 gadgetDB.append(gadget) except Exception as e: signal.alarm(0) sys.stdout = old_stdout sys.stderr = old_stderr if (not isinstance(e, GadgetException)): warnings = warnings + 1 f.write("Unexpected error in : " + '\\x'.join(["%02x" % ord(c) for c in asm]) + "\nException type: " + str(type(e)) + "\nException message: " + str(e) + '\n\n') i = i + 1 # Trick to find syscalls for addr in find_syscalls(): gadget = Gadget(i, addr, '\x0f\x05') gadgetDB.append(gadget) i = i + 1 # Restoring the state f.close() junk_file.close() signal.signal(signal.SIGINT, original_sigint_handler) # This variable should be written before calculating spInc or simplifying conditions !!! Expr.nb_regs = Analysis.ssaRegCount - 1 # Getting time cTime = datetime.now() - startTime # Printing summary information if (sigint): print("\n") error_colored( "SIGINT ended the analysis prematurely, gadget database might be incomplete\n" ) sigint = False notify("Gadgets analyzed : " + str(i)) notify("Successfully translated : " + str(success)) notify("Computation time : " + str(cTime)) if (warnings > 0): pass