def add(arch): print(banner([string_bold('Adding a new shellcode')])) shellcode = '' ok = False while (not ok): sys.stdout.write('\t' + string_ropg('> ') + 'Enter your shellcode as a string in hex format:\n') 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 input is in wrong format or invalid")) sys.stdout.write('\t' + string_ropg('> ') + 'Enter short shellcode name/description:\n') info = "" while (not info): info = prompt(u" > ") info = filter(lambda x: x in set(string.printable), info) add_shellcode(arch, shellcode, info)
def build_call(funcName, funcArgs, constraint, assertion): # Find the address of the fonction (funcName2, funcAddr) = getFunctionAddress(funcName) if (funcName2 is None): return "Couldn't find function '{}' in the binary".format(funcName) # Check if bad bytes in function address if (not constraint.badBytes.verifyAddress(funcAddr)): return "'{}' address ({}) contains bad bytes".format( funcName2, string_special('0x' + format(funcAddr, '0' + str(Arch.octets() * 2) + 'x'))) # Find a gadget for the fake return address offset = len( funcArgs) * 8 - 8 # Because we do +8 at the beginning of the loop skip_args_chains = [] i = 4 while (i > 0 and (not skip_args_chains)): offset += 8 skip_args_chains = search(QueryType.MEMtoREG, Arch.ipNum(), \ (Arch.spNum(),offset), constraint, assertion, n=1) i -= 1 if (not skip_args_chains): return "Couldn't build ROP-Chain" skip_args_chain = skip_args_chains[0] # Build the ropchain with the arguments args_chain = ROPChain() arg_n = len(funcArgs) for arg in reversed(funcArgs): if (isinstance(arg, int)): args_chain.addPadding(arg, comment="Arg{}: {}".format( arg_n, string_ropg(hex(arg)))) arg_n -= 1 else: return "Type of argument '{}' not supported yet :'(".format(arg) # Build call chain (function address + fake return address) call_chain = ROPChain() call_chain.addPadding(funcAddr, comment=string_ropg(funcName2)) skip_args_addr = int( validAddrStr(skip_args_chain.chain[0], constraint.getBadBytes(), Arch.bits()), 16) call_chain.addPadding(skip_args_addr, comment="Address of: " + string_bold(str(skip_args_chain.chain[0]))) return call_chain.addChain(args_chain)
def build_call_linux86(funcName, funcArgs, constraint, assertion, clmax=None, optimizeLen=False): # Find the address of the fonction (funcName2, funcAddr) = getFunctionAddress(funcName) if( funcName2 is None ): return "Couldn't find function '{}' in the binary".format(funcName) # Check if bad bytes in function address if( not constraint.badBytes.verifyAddress(funcAddr) ): return "'{}' address ({}) contains bad bytes".format(funcName2, string_special('0x'+format(funcAddr, '0'+str(Arch.octets()*2)+'x'))) # Check if lmax too small if( (1 + len(funcArgs) + (lambda x: 1 if len(x)>0 else 0)(funcArgs)) > clmax ): return "Not enough bytes to call function '{}'".format(funcName) # Find a gadget for the fake return address if( funcArgs ): offset = (len(funcArgs)-1)*Arch.octets() # Because we do +octets() at the beginning of the loop skip_args_chains = [] i = 4 # Try 4 more maximum while( i > 0 and (not skip_args_chains)): offset += Arch.octets() skip_args_chains = search(QueryType.MEMtoREG, Arch.ipNum(), \ (Arch.spNum(),offset), constraint, assertion, n=1, optimizeLen=optimizeLen) i -= 1 if( not skip_args_chains ): return "Couldn't build ROP-Chain" skip_args_chain = skip_args_chains[0] else: # No arguments skip_args_chain = None # Build the ropchain with the arguments args_chain = ROPChain() arg_n = len(funcArgs) for arg in reversed(funcArgs): if( isinstance(arg, int) ): args_chain.addPadding(arg, comment="Arg{}: {}".format(arg_n, string_ropg(hex(arg)))) arg_n -= 1 else: return "Type of argument '{}' not supported yet :'(".format(arg) # Build call chain (function address + fake return address) call_chain = ROPChain() call_chain.addPadding(funcAddr, comment=string_ropg(funcName2)) if( funcArgs ): skip_args_addr = int( validAddrStr(skip_args_chain.chain[0], constraint.getBadBytes(), Arch.bits()) ,16) call_chain.addPadding(skip_args_addr, comment="Address of: "+string_bold(str(skip_args_chain.chain[0]))) return call_chain.addChain(args_chain)
def select_shellcode(arch): """ Returns shellcode pair (shellcode, description) """ if (not shellcodes[arch]): error("No shellcodes available for architecture " + arch) return (None, None) list_shellcodes(arch) print("") choice = None ok = False sys.stdout.write('\t' + string_ropg('> ') + 'Select a shellcode:\n') while (not ok): choice_input = prompt(u" > ") try: choice = int(choice_input) if (choice >= 1 and choice <= len(shellcodes[arch])): ok = True else: print(string_special("\tError. Invalid choice")) except: ok = False return shellcodes[arch][choice - 1]
def build_call_linux64(funcName, funcArgs, constraint, assertion, clmax=None, optimizeLen=False): # Arguments registers # (Args should go in these registers for x64) argsRegsNames = ['rdi','rsi','rdx','rcx', 'r8', 'r9'] argsRegs = [Arch.n2r(name) for name in argsRegsNames] # Find the address of the fonction (funcName2, funcAddr) = getFunctionAddress(funcName) if( funcName2 is None ): return "Couldn't find function '{}' in the binary".format(funcName) # Check if bad bytes in function address if( not constraint.badBytes.verifyAddress(funcAddr) ): return "'{}' address ({}) contains bad bytes".format(funcName2, string_special('0x'+format(funcAddr, '0'+str(Arch.octets()*2)+'x'))) # Check how many arguments if( len(funcArgs) > 6 ): return "Doesn't support function call with more than 6 arguments with Linux X64 calling convention :(" # Find a gadget for the fake return address if( funcArgs ): # Build the ropchain with the arguments args_chain = popMultiple(map(lambda x,y:(x,)+y, argsRegs[:len(funcArgs)], funcArgs), constraint, assertion, clmax=clmax, optimizeLen=optimizeLen) if( not args_chain): return "Couldn't load arguments in registers" else: # No arguments args_chain = ROPChain() # Build call chain (function address + fake return address) return args_chain.addPadding(funcAddr, comment=string_ropg(funcName2))
def main(): print(string_ropg(string_bold(ASCII_art))) initLogs() finish = False promptSession = PromptSession(ANSI(u"(" + string_ropg(u'main') + u")> ")) while (not finish): try: user_input = promptSession.prompt() args = user_input.split() argslen = len(args) if (argslen > 0): command = args[0] else: command = None continue if (command == CMD_LOAD): load(args[1:]) elif (command == CMD_EXIT): finish = True elif (command == CMD_HELP): print(helpStr) elif (command == CMD_SEARCH): if (not Database.gadgets): error( "You have to load gadgets before entering semantic-mode" ) elif (not semantic_mode()): finish = True elif (command == CMD_EXPLOIT): if (not exploit_mode()): finish = True else: error("Unknown command '{}'".format(command)) if (command != None): print('') except KeyboardInterrupt: pass closeLogs() save_shellcodes() exit(0)
def remove(arch): if (not shellcodes[arch]): error("No shellcodes to remove for architecture " + arch) return list_shellcodes(arch) print("") choice = '' ok = False sys.stdout.write('\t' + string_ropg('> ') + 'Select a shellcode to remove:\n') while (not ok): choice_input = prompt(u" > ") try: choice = int(choice_input) ok = remove_shellcode(arch, choice) if (not ok): print(string_special("\tError. Invalid choice")) except: ok = False print("") notify('Shellcode removed')
def STRtoMEM_memcpy(string, addr, constraint, assertion, lmax=STR_TO_MEM_LMAX, addr_str=None, hex_info=False): """ MEMCPY STRATEGY Copy the string using memcpy function """ if (not addr_str): addr_str = "0x" + format(addr, '0' + str(Arch.octets() * 2) + 'x') # Getting strcpy function (func_name, func_addr) = getFunctionAddress('memcpy') if (not func_addr): verbose('Could not find memcpy function') return None elif (not constraint.badBytes.verifyAddress(func_addr)): verbose("memcpy address ({}) contains bad bytes".format( hex(func_addr))) return None # We decompose the string in substrings to be copied substrings_addr = findBytes(string, badBytes=constraint.getBadBytes()) if (not substrings_addr): return None elif (len(substrings_addr) * 5 > lmax): verbose( "Memcpy: ROP-Chain too long (length: {}, available bytes: {}) ". format( len(substrings_addr) * 5 * Arch.octets(), lmax * Arch.octets())) return None # Get a pop-pop-pop-ret gadget pppr_chains = _basic(QueryType.MEMtoREG, Arch.ipNum(), [Arch.spNum(), 3 * Arch.octets()], constraint.add( StackPointerIncrement(4 * Arch.octets())), assertion, clmax=1, noPadding=True) if (not pppr_chains): verbose("Memcpy: Could not find suitable pop-pop-pop-ret gadget") return None pppr_gadget = pppr_chains[0].chain[0] # Get the first gadget # Build chain res = ROPChain() offset = 0 custom_stack = addr for (substring_addr, substring_str) in substrings_addr: if (hex_info): substring_info = "'" + '\\x' + '\\x'.join( ["%02x" % ord(c) for c in substring_str]) + "'" else: substring_info = "'" + substring_str + "'" res.addPadding(func_addr, comment=string_ropg(func_name)) res.addGadget(pppr_gadget) res.addPadding(len(substring_str), comment="Arg3: " + string_ropg(str(len(substring_str)))) res.addPadding(substring_addr, comment="Arg2: " + string_ropg(substring_info)) res.addPadding(custom_stack, comment="Arg1: " + string_ropg("{} + {}".format(addr_str, offset))) # Adjust custom_stack = custom_stack + len(substring_str) offset = offset + len(substring_str) return res
def STRtoMEM_strcpy(string, addr, constraint, assertion, limit=None, lmax=STR_TO_MEM_LMAX, addr_str=None, hex_info=False): """ STRCPY STRATEGY Copy the string using strcpy function """ if (not addr_str): addr_str = hex(addr) # Getting strcpy function (func_name, func_addr) = getFunctionAddress('strcpy') if (not func_addr): verbose('Could not find strcpy function') return (None, None) elif (not constraint.badBytes.verifyAddress(func_addr)): verbose("strcpy address ({}) contains bad bytes".format( hex(func_addr))) return (None, None) # We decompose the string in substrings to be copied substrings_addr = findBytes(string, badBytes=constraint.getBadBytes(), add_null=True) if (not substrings_addr): return (None, None) # Find delivery address substr_lengthes = [len(substr[1]) - 1 for substr in substrings_addr] # -1 becasue strcpy substr_lengthes[-1] += 1 if (not limit is None): custom_stack = find_closest_base_fake_stack_address( addr, limit, substr_lengthes, constraint) if (custom_stack is None): verbose("Couldn't write string in memory because of bad bytes") return (None, None) else: custom_stack = find_closest_base_fake_stack_address( addr, addr + sum(substr_lengthes), substr_lengthes, constraint) if (custom_stack is None): verbose("Couldn't write string in memory because of bad bytes") return (None, None) if (custom_stack != addr): addr_str = hex(custom_stack) # Build chain res = ROPChain() offset = 0 saved_custom_stack = custom_stack for (substring_addr, substring_str) in substrings_addr: if (hex_info): substring_info = '\\x' + '\\x'.join( ["%02x" % ord(c) for c in substring_str]) else: substring_info = substring_str commentStack = "Arg2: " + string_ropg("{} + {}".format( addr_str, offset)) commentSubStr = "Arg1: " + string_ropg(substring_info) func_call = build_call(func_name, [substring_addr, custom_stack], constraint, assertion, [commentSubStr, commentStack], optimizeLen=True) if (isinstance(func_call, str)): verbose("strcpy: " + func_call) return (None, None) else: res.addChain(func_call) if (len(res) > lmax): return (None, None) # Adjust # -1 Because strcpy has a null byte :/ # Except when we INTEND to write a null byte if (substring_str == '\x00'): dec = 0 else: dec = 1 custom_stack = custom_stack + len(substring_str) - dec offset = offset + len(substring_str) - dec return (saved_custom_stack, res)
def STRtoMEM_memcpy(string, addr, constraint, assertion, limit=None, lmax=STR_TO_MEM_LMAX, addr_str=None, hex_info=False): """ MEMCPY STRATEGY Copy the string using memcpy function """ if (not addr_str): addr_str = hex(addr) # Getting strcpy function (func_name, func_addr) = getFunctionAddress('memcpy') if (not func_addr): verbose('Could not find memcpy function') return (None, None) elif (not constraint.badBytes.verifyAddress(func_addr)): verbose("memcpy address ({}) contains bad bytes".format( hex(func_addr))) return (None, None) # We decompose the string in substrings to be copied substrings_addr = findBytes(string, badBytes=constraint.getBadBytes()) if (not substrings_addr): return (None, None) # Find delivery address substr_lengthes = [len(substr[1]) for substr in substrings_addr] if (not limit is None): custom_stack = find_closest_base_fake_stack_address( addr, limit, substr_lengthes, constraint) if (custom_stack is None): verbose("Couldn't write string in memory because of bad bytes") return (None, None) else: custom_stack = find_closest_base_fake_stack_address( addr, addr + sum(substr_lengthes), substr_lengthes, constraint) if (custom_stack is None): verbose("Couldn't write string in memory because of bad bytes") return (None, None) if (custom_stack != addr): addr_str = hex(custom_stack) # Build chain res = ROPChain() offset = 0 saved_custom_stack = custom_stack for (substring_addr, substring_str) in substrings_addr: if (hex_info): substring_info = "'" + '\\x' + '\\x'.join( ["%02x" % ord(c) for c in substring_str]) + "'" else: substring_info = "'" + substring_str + "'" comment3 = "Arg3: " + string_ropg(str(len(substring_str))) comment2 = "Arg2: " + string_ropg(substring_info) comment1 = "Arg1: " + string_ropg("{} + {}".format(addr_str, offset)) func_call = build_call(func_name, [custom_stack, substring_addr, len(substring_str)],\ constraint, assertion, [comment1, comment2, comment3], optimizeLen=True) if (isinstance(func_call, str)): verbose("memcpy: " + func_call) return (None, None) res.addChain(func_call) if (len(res) > lmax): return (None, None) # Adjust custom_stack = custom_stack + len(substring_str) offset = offset + len(substring_str) return (saved_custom_stack, res)