예제 #1
0
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)
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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
예제 #9
0
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
예제 #10
0
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)
예제 #11
0
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)