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 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 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 set_ropgadget(path): global DEFAULT_PATH_ROPGADGET global PATH_ROPGADGET if ((os.path.isfile(path) and path[:-3] == ".py") or path == DEFAULT_PATH_ROPGADGET or path == "ROPgadget"): PATH_ROPGADGET = path notify("New ropgadget command : " + path) else: notify("Error. '" + path + "' could not be found")
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_arch(arch, quiet=False): global ARCH if (arch in Analysis.supportedArchs): ARCH = arch Analysis.setArch(arch) if (not quiet): notify("Now working under architecture: " + arch) else: if (not quiet): notify("Architecture '" + arch + "' not supported. Available architectures: " + ','.join(Analysis.supportedArchs))
def set_limit(limit): global LIMIT if (isinstance(limit, int)): LIMIT = limit else: try: limit = int(limit, 10) LIMIT = limit notify("Now looking for up to {} gadgets by request".format( str(LIMIT))) except: notify("Error. 'limit' parameter should be a base 10 integer")
def check_binaryType(filename): """ Checks the binary type of the file Precondition: the file exists ! """ ELF32_strings = ["ELF 32-bit"] ELF64_strings = ["ELF 64-bit", "x86-64"] output = from_file(os.path.realpath(filename)) if ([sub for sub in ELF32_strings if sub in output]): notify("ELF 32-bit detected") return "X86" elif ([sub for sub in ELF64_strings if sub in output]): notify("ELF 64-bit detected") return "X86-64" else: notify("Unknown binary type") return None
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 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
def check_binaryType(filename): """ Checks the binary type of the file Precondition: the file exists ! """ INTEL_strings = ["x86", "x86-64", "X86", "X86-64", "Intel", "80386"] ELF32_strings = ["ELF 32-bit"] ELF64_strings = ["ELF 64-bit"] PE32_strings = ["PE32 "] PE64_strings = ["PE32+"] output = from_file(os.path.realpath(filename)) if ([sub for sub in INTEL_strings if sub in output]): if ([sub for sub in ELF32_strings if sub in output]): notify("ELF 32-bits detected") Analysis.setFiletype("ELF") return "X86" elif ([sub for sub in ELF64_strings if sub in output]): notify("ELF 64-bits detected") Analysis.setFiletype("ELF") return "X86-64" elif ([sub for sub in PE32_strings if sub in output]): notify("PE 32-bits detected") Analysis.setFiletype("PE") return "X86" elif ([sub for sub in PE64_strings if sub in output]): notify("PE 64-bits detected") Analysis.setFiletype("PE") return "X86-64" else: notify("Unknown binary type") return None else: notify("Unknown architecture") return None