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 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 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 load_config(): global ARCH global PATH_ROPGADGET global LIMIT # Check if the ROPGenerator director exists if (not os.path.isdir(ROPGENERATOR_DIRECTORY)): try: os.system('mkdir ' + ROPGENERATOR_DIRECTORY) except: pass try: f = open(ROPGENERATOR_CONFIG_FILE, "r") ARCH = f.readline()[:-1] PATH_ROPGADGET = f.readline()[:-1] LIMIT = int(f.readline()[:-1], 10) f.close() #info_colored("Loaded configuration\n") except: info_colored( "Couldn't load custom configuration, using the default one\n") default_config() Analysis.setArch(ARCH)
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 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 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)
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")
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