Beispiel #1
0
def popMultiple(args,
                constraint=None,
                assertion=None,
                clmax=None,
                optimizeLen=False):
    """
    args is a list of pairs (reg, value)
    reg is a reg UID
    value is an int
    Creates a chain that pops values into regs
    """
    if (clmax <= 0):
        return None

    if (constraint is None):
        constr = Constraint()
    else:
        constr = constraint
    if (assertion is None):
        a = Assertion()
    else:
        a = assertion

    perms = itertools.permutations(args)
    for perm in perms:
        clmax_tmp = clmax
        res = ROPChain()
        constr_tmp = constr
        for arg in perm:
            if (optimizeLen):
                pop = search_optimize_len(QueryType.CSTtoREG,
                                          arg[0],
                                          arg[1],
                                          constr_tmp,
                                          a,
                                          n=1,
                                          clmax=clmax_tmp)
            else:
                pop = search(QueryType.CSTtoREG,
                             arg[0],
                             arg[1],
                             constr_tmp,
                             a,
                             n=1,
                             clmax=clmax_tmp)
            if (not pop):
                break
            else:
                clmax_tmp -= len(pop[0])
                # If Reached max length, exit
                if (clmax_tmp < 0):
                    pop = None
                    break
                else:
                    res.addChain(pop[0])
                    constr_tmp = constr_tmp.add(RegsNotModified([arg[0]]))
        if (pop):
            return res
    return None
Beispiel #2
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
Beispiel #3
0
def init_impossible_REGtoREG():
    global global_impossible_REGtoREG
    record = SearchRecord()
    for reg1 in range(0, Arch.ssaRegCount):
        for reg2 in range(0, Arch.ssaRegCount):
            print("Doing {} <- {} ".format(reg1, reg2))
            if (reg2 == reg1):
                continue
            search(QueryType.REGtoREG,
                   reg1, [reg2, 0],
                   Constraint(),
                   Assertion(),
                   n=1,
                   record=record)
    global_impossible_REGtoREG = record.impossible_REGtoREG
Beispiel #4
0
def find(args):
    """
    args - List of user arguments as strings
    (the command should not be included in the list as args[0])
    """
    if (not args):
        print_help()
        return

    if (args[0] == OPTION_HELP or args[0] == OPTION_HELP_SHORT):
        print_help()
        return

    parsed_args = parse_args(args)
    if (not parsed_args[0]):
        error(parsed_args[1])
    else:
        qtype = parsed_args[1]
        arg1 = parsed_args[2]
        arg2 = parsed_args[3]
        constraint = parsed_args[4]
        nbResults = parsed_args[5]
        clmax = parsed_args[6]
        assertion = Assertion().add(\
            RegsValidPtrRead([(Arch.spNum(),-5000, 10000)])).add(\
            RegsValidPtrWrite([(Arch.spNum(), -5000, 0)]))
        # Search
        res = search(qtype,
                     arg1,
                     arg2,
                     constraint,
                     assertion,
                     n=nbResults,
                     clmax=clmax)
        if (res):
            print_chains(res, "Built matching ROPChain(s)",
                         constraint.getBadBytes())
        else:
            res = search_not_chainable(qtype,
                                       arg1,
                                       arg2,
                                       constraint,
                                       assertion,
                                       n=nbResults,
                                       clmax=clmax)
            print_chains(res, "Possibly matching gadget(s)",
                         constraint.getBadBytes())
Beispiel #5
0
def initEngine():
    global INIT_LMAX, INIT_MAXDEPTH
    global global_impossible_REGtoREG
    global baseAssertion

    # Init global variables
    baseAssertion = Assertion().add(\
            RegsValidPtrRead([(Arch.spNum(),-5000, 10000)]), copy=False).add(\
            RegsValidPtrWrite([(Arch.spNum(), -5000, 0)]), copy=False)

    info(string_bold("Initializing Semantic Engine\n"))

    # Init helper for REGtoREG
    global_impossible_REGtoREG = SearchEnvironment(INIT_LMAX, Constraint(),
                                                   baseAssertion,
                                                   INIT_MAXDEPTH)
    init_impossible_REGtoREG(global_impossible_REGtoREG)
Beispiel #6
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
Beispiel #7
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
Beispiel #8
0
def pwn(args):
    global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON
    global EXPLOIT_LMAX
    
    
    if( not args ):
        print_help()
        return 
        
    # Check if gadgets have been loaded in the DB 
    if( not Database.gadgets ):
        error("Oops. You have to load gadgets before pwning ;) ")
        return 
        
    # Set default output format 
    OUTPUT = OUTPUT_CONSOLE
    clmax = EXPLOIT_LMAX
    
    seenOutput = False
    seenLmax = False
    seenBadBytes = False
    seenVerbose = False
    seenOutfile = False
    seenPaddingByte = False
    seenPaddingLen = False

    constraint = Constraint()
    assertion = Assertion()
    subcommand = None
    outfile = None
    paddingByteStr = None 
    paddingLen = 0
    
    i = 0 
    while i < len(args):
        # Parse options     
        if( args[i][0] == '-' ):
            if( args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]):
                if( seenBadBytes ):
                    error("Error. '" + args[i] + "' option should be used only once")
                    return 
                if( i+1 >= len(args)):
                    error("Error. Missing bad bytes after option '"+args[i]+"'")
                    return 
                seenBadBytes = True
                (success, res) = parse_bad_bytes(args[i+1])
                if( not success ):
                    error(res)
                    return
                i = i+2
                constraint = constraint.add(BadBytes(res))
            elif( args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT ):
                if( seenLmax ):
                    error("Error. '" + arg + "' option should be used only once.")
                    return 
                if( i+1 >= len(args)):
                    error("Error. Missing output format after option '"+arg+"'")
                    return 
                try:
                    clmax = int(args[i+1])
                    if( clmax < Arch.octets() ):
                        raise Exception()
                    # Convert number of bytes into number of ropchain elements
                    clmax /= Arch.octets()
                except:
                    error("Error. '" + args[i+1] +"' bytes is not valid")
                    return 
                i = i +2
                seenLmax = True
                       
            elif( args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]):
                if( seenOutput ):
                    error("Option '{}' should be used only once".format(args[i]))
                    return 
                if( i+1 >= len(args)):
                    error("Error. Missing output format after option '"+args[i]+"'")
                    return 
                if( args[i+1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]):
                    OUTPUT = args[i+1]
                    seenOutput = True
                    i += 2
                else:
                    error("Error. Unknown output format: {}".format(args[i+1]))
                    return 
            elif( args[i] in [OPTION_OUTFILE_SHORT, OPTION_OUTFILE] ):
                if( seenOutfile ):
                    error("Option '{}' should be used only once".format(args[i]))
                    return 
                if( i+1 >= len(args)):
                    error("Error. Missing file name after option '"+args[i]+"'")
                    return 
                seenOutfile = True
                outfile = args[i+1]
                i += 2
            elif( args[i] in [OPTION_PADDING_BYTE, OPTION_PADDING_BYTE_SHORT] ):
                if( seenPaddingByte ):
                    error("Option '{}' should be used only once".format(args[i]))
                    return 
                if( i+1 >= len(args)):
                    error("Error. Missing byte after option '"+args[i]+"'")
                    return 
                seenPaddingByte = True
                try:
                    paddingByte = int(args[i+1], 16)
                except:
                    error("Error. '{}' is not a valid byte".format(args[i+1]))
                    return 
                if( paddingByte > 0xff ):
                    error("Error. '{}' can't be stored in one byte".format(args[i+1]))
                    return
                paddingByteStr = "\\x"+format(paddingByte, "02x")
                i += 2
            elif( args[i] in [OPTION_PADDING_LEN, OPTION_PADDING_LEN_SHORT] ):
                if( seenPaddingLen ):
                    error("Option '{}' should be used only once".format(args[i]))
                    return 
                if( i+1 >= len(args)):
                    error("Error. Missing length after option '"+args[i]+"'")
                    return 
                seenPaddingLen = True
                try:
                    paddingLen = int(args[i+1], 10)
                except:
                    try:
                        paddingLen = int(args[i+1], 16)
                    except:
                        error("Error. '{}' is not a valid byte".format(args[i+1]))
                        return 
                if( paddingLen < 0 ):
                    error("Error. Padding length must be > 0")
                    return 
                i += 2
            elif( args[i] in [OPTION_HELP, OPTION_HELP_SHORT]):
                print_help()
                return 
            elif( args[i] in [OPTION_VERBOSE, OPTION_VERBOSE_SHORT]):
                seenVerbose = True
                i += 1
            else:
                error("Error. Unknown option '{}'".format(args[i]))
                return 
                
        # Parse a subcommand
        else:
            # Before parsing, check arguments 
            # Check arguments 
            if( seenPaddingByte and not seenPaddingLen ):
                error("Error. You have to specify padding length if you provide a padding byte. See the '-pl,--padding-length' option")
                return 
            # Parse subcommand 
            verbose_mode(seenVerbose)
            payload = None
            if( args[i] == CMD_DELIVER_SHELLCODE ):
                payload = dshell(args[i+1:], constraint, assertion, lmax=clmax)
            else:
                error("Error. Unknown subcommand : '{}'".format(args[i]))
                verbose_mode(False)
                return 
                
            verbose_mode(False)
            # Print result 
            if( payload == "help"):
                return 
            elif( not payload is None ):
                print(string_bold("\n\tBuilt exploit - {} bytes\n".format(payload.len_bytes)))
                # Normal output 
                if( OUTPUT == OUTPUT_CONSOLE ):
                    payload_string = payload.strConsole(Arch.bits(), constraint.getBadBytes())
                elif( OUTPUT == OUTPUT_PYTHON ):
                    payload_string = payload.strPython(Arch.bits(), constraint.getBadBytes(), \
                        noTab=seenOutfile, paddingByteStr=paddingByteStr, paddingLen=paddingLen)
                # Output to file
                if( outfile ):
                    try: 
                        f = open(outfile, "w")
                        f.write(remove_colors(payload_string))
                        f.close()
                        print(string_bold("\n\tWrote payload in file '{}'\n".format(outfile)))
                    except:
                        error("Error. Couldn't not write payload in file '{}'".format(outfile))
                else:
                    print(payload_string)
            else:
                error("Couldn't generate exploit")
            return 
                
    # Test parsing result 
    if( subcommand is None ):
        error("Missing subcommand")
        return
Beispiel #9
0
def pwn(args):
    global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON
    global EXPLOIT_LMAX

    if (not args):
        print_help()
        return

    # Check if gadgets have been loaded in the DB
    if (not Database.gadgets):
        error("Oops. You have to load gadgets before pwning ;) ")
        return

    # Set default output format
    OUTPUT = OUTPUT_CONSOLE
    clmax = EXPLOIT_LMAX

    seenOutput = False
    seenLmax = False
    seenBadBytes = False
    seenVerbose = False

    constraint = Constraint()
    assertion = Assertion()
    subcommand = None

    i = 0
    while i < len(args):
        # Parse options
        if (args[i][0] == '-'):
            if (args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]):
                if (seenBadBytes):
                    error("Error. '" + args[i] +
                          "' option should be used only once")
                    return
                if (i + 1 >= len(args)):
                    error("Error. Missing bad bytes after option '" + args[i] +
                          "'")
                    return
                seenBadBytes = True
                (success, res) = parse_bad_bytes(args[i + 1])
                if (not success):
                    error(res)
                    return
                i = i + 2
                constraint = constraint.add(BadBytes(res))
            elif (args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT):
                if (seenLmax):
                    error("Error. '" + arg +
                          "' option should be used only once.")
                    return
                if (i + 1 >= len(args)):
                    error("Error. Missing output format after option '" + arg +
                          "'")
                    return
                try:
                    clmax = int(args[i + 1])
                    if (clmax < Arch.octets()):
                        raise Exception()
                    # Convert number of bytes into number of ropchain elements
                    clmax /= Arch.octets()
                except:
                    error("Error. '" + args[i + 1] + "' bytes is not valid")
                    return
                i = i + 2
                seenLmax = True

            elif (args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]):
                if (seenOutput):
                    error("Option '{}' should be used only once".format(
                        args[i]))
                    return
                if (i + 1 >= len(args)):
                    error("Error. Missing output format after option '" +
                          args[i] + "'")
                    return
                if (args[i + 1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]):
                    OUTPUT = args[i + 1]
                    seenOutput = True
                    i += 2
                else:
                    error("Error. Unknown output format: {}".format(args[i +
                                                                         1]))
                    return
            elif (args[i] in [OPTION_HELP, OPTION_HELP_SHORT]):
                print_help()
                return
            elif (args[i] in [OPTION_VERBOSE, OPTION_VERBOSE_SHORT]):
                seenVerbose = True
                i += 1
            else:
                error("Error. Unknown option '{}'".format(args[i]))
                return
        # Parse a subcommand
        else:
            verbose_mode(seenVerbose)
            payload = None
            if (args[i] == CMD_DELIVER_SHELLCODE):
                payload = dshell(args[i + 1:],
                                 constraint,
                                 assertion,
                                 lmax=clmax)
            else:
                error("Error. Unknown subcommand : '{}'".format(args[i]))
                verbose_mode(False)
                return

            verbose_mode(False)
            # Print result
            if (payload):
                print(
                    string_bold("\n\tBuilt exploit - {} bytes\n".format(
                        payload.len_bytes)))
                if (OUTPUT == OUTPUT_CONSOLE):
                    print(
                        payload.strConsole(Arch.bits(),
                                           constraint.getBadBytes()))
                elif (OUTPUT == OUTPUT_PYTHON):
                    print(
                        payload.strPython(Arch.bits(),
                                          constraint.getBadBytes()))
            else:
                error("Couldn't generate exploit")
            return

    # Test parsing result
    if (subcommand is None):
        error("Missing subcommand")
        return
Beispiel #10
0
def store_constant_address(qtype,
                           cst_addr,
                           value,
                           constraint=None,
                           assertion=None,
                           clmax=None,
                           optimizeLen=False):
    """
    Does a XXXtoMEM kind of query BUT the memory address is 
    a simple constant ! 
    
    Expected qtypes are only XXXtoMEM
    cst_addr is the store address
    value is the value to store, a single cst or a couple (reg,cst)
    """
    if (clmax is None):
        clmax = STORE_CONSTANT_ADDRESS_LMAX
    elif (clmax <= 0):
        return None

    if (constraint is None):
        constr = Constraint()
    else:
        constr = constraint
    if (assertion is None):
        a = Assertion()
    else:
        a = assertion

    # Tranform the query type
    if (qtype == QueryType.CSTtoMEM):
        qtype2 = QueryType.CSTtoREG
    elif (qtype == QueryType.REGtoMEM):
        qtype2 = QueryType.REGtoREG
    elif (qtype == QueryType.MEMtoREG):
        qtype2 = QueryType.MEMtoREG
    else:
        raise Exception(
            "Query type {} should not appear in this function!".format(qtype))

    tried_values = []
    tried_cst_addr = []
    best = None  # If optimizeLen
    shortest = clmax  # Shortest ROPChain found if optimizeLen ;)

    for ((addr_reg, addr_cst), (reg,cst), gadget) in \
    sorted(DBAllPossibleWrites(constr.add(Chainable(ret=True)), a), \
    key=lambda x: 0 if (x[1] == value) else 1) :
        # DOn't use rip or rsp...
        if( reg == Arch.ipNum() or reg == Arch.spNum()\
            or addr_reg == Arch.ipNum() or addr_reg == Arch.spNum()):
            continue
        res = None
        # Check if directly the registers we want to write ;)
        value_is_reg = False
        value_to_reg = []
        addr_to_reg = []
        if ((reg, cst) == value):
            value_to_reg = [ROPChain()]
            value_is_reg = True

        # adapt value
        if (not isinstance(value, tuple)):
            adjusted_value = value - cst
        else:
            adjusted_value = (value[0], value[1] - cst)
        adjusted_cst_addr = cst_addr - addr_cst
        # Get spInc
        gadget_paddingLen = (gadget.spInc / Arch.octets()) - 1
        # Check if tried before
        if ((reg, cst) in tried_values):
            continue
        elif ((addr_reg, addr_cst) in tried_cst_addr):
            continue
        ### Try to do reg first then addr_reg
        # Try to put the value into reg
        clmax2 = shortest - gadget_paddingLen - 1
        if (not value_is_reg):
            value_to_reg = search(qtype2,
                                  reg,
                                  adjusted_value,
                                  constr,
                                  a,
                                  clmax=clmax2,
                                  n=1,
                                  optimizeLen=optimizeLen)
            if (not value_to_reg):
                tried_values.append((reg, cst))
                continue
            else:
                clmax2 = clmax2 - len(value_to_reg[0])
        # Try to put the cst_addr in addr_reg
        addr_to_reg = search(QueryType.CSTtoREG,
                             addr_reg,
                             adjusted_cst_addr,
                             constr.add(RegsNotModified([reg])),
                             a,
                             clmax=clmax2,
                             n=1,
                             optimizeLen=optimizeLen)
        if (addr_to_reg):
            # If we found a solution
            # Combine them and return
            # Padd the gadget
            res = value_to_reg[0].addChain(addr_to_reg[0]).addGadget(gadget)
            if (gadget.spInc > 0):
                padding_value = constr.getValidPadding(Arch.octets())
                res = res.addPadding(padding_value,
                                     n=(gadget.spInc / Arch.octets()) - 1)
            if (optimizeLen):
                if (best):
                    best = min(best, res)
                else:
                    best = res
                shortest = len(best)
            else:
                return res

        ### Try to do addr_reg first and then reg
        clmax2 = shortest - gadget_paddingLen - 1
        # Try to put the cst_addr in addr_reg
        addr_to_reg = search(QueryType.CSTtoREG,
                             addr_reg,
                             adjusted_cst_addr,
                             constr,
                             a,
                             clmax=clmax2,
                             n=1,
                             optimizeLen=optimizeLen)
        if (not addr_to_reg):
            tried_cst_addr.append((addr_reg, addr_cst))
            continue
        else:
            clmax2 = clmax2 - len(addr_to_reg[0])
        # Try to put the value into reg
        if (not value_is_reg):
            value_to_reg = search(qtype2,
                                  reg,
                                  adjusted_value,
                                  constr.add(RegsNotModified([addr_reg])),
                                  a,
                                  clmax=clmax2,
                                  n=1,
                                  optimizeLen=optimizeLen)
        if (value_to_reg):
            # If we found a solution
            # Combine them and return
            # Padd the gadget
            res = addr_to_reg[0].addChain(value_to_reg[0]).addGadget(gadget)
            if (gadget.spInc > 0):
                padding_value = constr.getValidPadding(Arch.octets())
                res = res.addPadding(padding_value,
                                     n=(gadget.spInc / Arch.octets()) - 1)
            if (optimizeLen):
                if (best):
                    best = min(best, res)
                else:
                    best = res
                shortest = len(best)
            else:
                return res

        # 5 = two pops for addr_reg and reg + 1 for the write gadget
        # So since 5 is the shortest possible with two pops we can return
        # We can have < 5 if reg is already equal to 'value' argument
        # But we try this case first (see sorted()) when getting possibleWrites ;)
        if (((not optimizeLen) or (not value_is_reg)) and (not best is None)
                and len(best) <= 5):
            return best
        elif (optimizeLen and (not best is None) and len(best) <= 3):
            return best
    return best
Beispiel #11
0
def syscall(args):
    global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON
    # Parsing arguments
    if (not args):
        print_help()
        return
    OUTPUT = OUTPUT_CONSOLE
    funcName = None
    i = 0
    seenOutput = False
    seenFunction = False
    seenBadBytes = False
    seenKeepRegs = False

    constraint = Constraint()
    assertion = Assertion()
    while i < len(args):
        if (args[i] in [OPTION_LIST, OPTION_LIST_SHORT]):
            listSyscalls(args[1:])
            return
        if (args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]):
            if (seenBadBytes):
                error("Error. '" + args[i] +
                      "' option should be used only once")
                return
            if (i + 1 >= len(args)):
                error("Error. Missing bad bytes after option '" + args[i] +
                      "'")
                return
            seenBadBytes = True
            (success, res) = parse_bad_bytes(args[i + 1])
            if (not success):
                error(res)
                return
            i = i + 2
            constraint = constraint.add(BadBytes(res))
        elif (args[i] in [OPTION_KEEP_REGS, OPTION_KEEP_REGS_SHORT]):
            if (seenKeepRegs):
                error("Error. '" + args[i] +
                      "' option should be used only once")
                return
            if (i + 1 >= len(args)):
                error("Error. Missing register after option '" + args[i] + "'")
                return
            seenKeepRegs = True
            (success, res) = parse_keep_regs(args[i + 1])
            if (not success):
                error(res)
                return
            i = i + 2
            constraint = constraint.add(RegsNotModified(res))
        elif (args[i] in [OPTION_FUNCTION, OPTION_FUNCTION_SHORT]):
            if (not loadedBinary()):
                error(
                    "Error. You should load a binary before building ROPChains"
                )
                return
            elif (seenFunction):
                error("Option '{}' should be used only once".format(args[i]))
                return
            userInput = ''
            i += 1
            while (i < len(args) and args[i][0] != "-"):
                userInput += args[i]
                i += 1
            (funcName, funcArgs) = parseFunction(userInput)
            if (not funcName):
                return
            seenFunction = True
        elif (args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]):
            if (seenOutput):
                error("Option '{}' should be used only once".format(args[i]))
                return
            if (i + 1 >= len(args)):
                error("Error. Missing output format after option '" + args[i] +
                      "'")
                return
            if (args[i + 1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]):
                OUTPUT = args[i + 1]
                seenOutput = True
                i += 2
            else:
                error("Error. Unknown output format: {}".format(args[i + 1]))
                return
        elif (args[i] in [OPTION_HELP, OPTION_HELP_SHORT]):
            print_help()
            return
        else:
            error("Error. Unknown option '{}'".format(args[i]))
            return

    if (not funcName):
        error("Missing function to call")
    else:
        call(funcName, funcArgs, constraint, assertion)
Beispiel #12
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
Beispiel #13
0
def popMultiple(args,
                constraint=None,
                assertion=None,
                clmax=None,
                addr=None,
                limit=None,
                optimizeLen=False):
    """
    args is a list of pairs (reg, value) 
        OR a list of triples (reg, value, comment)
    reg is a reg UID
    value is an int OR a string
    addr and limit are used to put strings if args contains strings 
    Creates a chain that pops values into regs
    """
    if (clmax is None):
        clmax = POP_MULTIPLE_LMAX_PER_REG * len(args)
    elif (clmax <= 0):
        return None
    for arg in args:
        if (isinstance(arg, str)):
            clmax += STR_TO_MEM_LMAX

    if (constraint is None):
        constr = Constraint()
    else:
        constr = constraint
    if (assertion is None):
        a = Assertion()
    else:
        a = assertion

    # Get address
    #Find address for the payload
    if (not addr):
        # Get the .bss address
        addr = getSectionAddress('.bss')
        if (not addr):
            return None

    perms = itertools.permutations(args)
    for perm in perms:
        clmax_tmp = clmax
        res = ROPChain()
        constr_tmp = constr
        tmp_addr = addr
        chains = None
        for arg in perm:
            if (len(arg) == 3):
                comment = arg[2]
            else:
                comment = None
            if (isinstance(arg[1], int)):
                chains = search(QueryType.CSTtoREG,
                                arg[0],
                                arg[1],
                                constr_tmp,
                                a,
                                n=1,
                                clmax=clmax_tmp,
                                CSTtoREG_comment=comment,
                                optimizeLen=optimizeLen)
            elif (isinstance(arg[1], str)):
                (address, str_to_mem) = STRtoMEM(arg[1],
                                                 tmp_addr,
                                                 constr_tmp,
                                                 a,
                                                 limit=limit,
                                                 lmax=clmax_tmp,
                                                 addr_str=comment,
                                                 hex_info=True,
                                                 optimizeLen=optimizeLen)
                if (not str_to_mem):
                    break
                tmp_addr = address + len(arg)
                pop = search(QueryType.CSTtoREG,
                             arg[0],
                             address,
                             constr_tmp,
                             a,
                             n=1,
                             clmax=clmax_tmp - len(str_to_mem),
                             optimizeLen=optimizeLen)
                if (not pop):
                    break
                chains = [str_to_mem.addChain(pop[0])]
            else:
                raise Exception(
                    "UNknown argument type in popMultiple: '{}'".format(
                        type(arg)))

            if (not chains):
                break
            else:
                clmax_tmp -= len(chains[0])
                # If Reached max length, exit
                if (clmax_tmp < 0):
                    chains = None
                    break
                else:
                    res.addChain(chains[0])
                    constr_tmp = constr_tmp.add(RegsNotModified([arg[0]]))
        if (chains):
            return res
    return None
Beispiel #14
0
def call(args):
    global OUTPUT, OUTPUT_CONSOLE, OUTPUT_PYTHON
    # Parsing arguments
    if( not args):
        print_help()
        return
    OUTPUT = OUTPUT_CONSOLE
    funcName = None
    i = 0
    seenOutput = False
    seenFunction = False
    seenBadBytes = False
    seenKeepRegs = False
    seenShortest = False
    seenLmax = False
    clmax = None
    
    constraint = Constraint()
    assertion = Assertion()
    while i < len(args):
        if( args[i] in [OPTION_LIST, OPTION_LIST_SHORT]):
            func_list = getAllFunctions()
            print_functions(func_list)
            return 
        if( args[i] in [OPTION_BAD_BYTES, OPTION_BAD_BYTES_SHORT]):
            if( seenBadBytes ):
                error("Error. '" + args[i] + "' option should be used only once")
                return 
            if( i+1 >= len(args)):
                error("Error. Missing bad bytes after option '"+args[i]+"'")
                return 
            seenBadBytes = True
            (success, res) = parse_bad_bytes(args[i+1])
            if( not success ):
                error(res)
                return
            i = i+2
            constraint = constraint.add(BadBytes(res))
        elif( args[i] in [OPTION_KEEP_REGS, OPTION_KEEP_REGS_SHORT]):
            if( seenKeepRegs ):
                error("Error. '" + args[i] + "' option should be used only once")
                return 
            if( i+1 >= len(args)):
                error("Error. Missing register after option '"+args[i]+"'")
                return 
            seenKeepRegs = True
            (success, res) = parse_keep_regs(args[i+1])
            if( not success ):
                error(res)
                return
            i = i+2
            constraint = constraint.add(RegsNotModified(res))
        elif( args[i] in [OPTION_CALL, OPTION_CALL_SHORT] ):
            if( not loadedBinary() ):
                error("Error. You should load a binary before building ROPChains")
                return 
            elif( seenFunction ):
                error("Option '{}' should be used only once".format(args[i]))
                return  
            userInput = ''
            i +=1
            while( i < len(args) and args[i][0] != "-"):
                userInput += args[i]
                i += 1
            (funcName, funcArgs ) = parseFunction(userInput)
            if( not funcName):
                return 
            seenFunction = True
        elif( args[i] in [OPTION_OUTPUT, OPTION_OUTPUT_SHORT]):
            if( seenOutput ):
                error("Option '{}' should be used only once".format(args[i]))
                return 
            if( i+1 >= len(args)):
                error("Error. Missing output format after option '"+args[i]+"'")
                return 
            if( args[i+1] in [OUTPUT_CONSOLE, OUTPUT_PYTHON]):
                OUTPUT = args[i+1]
                seenOutput = True
                i += 2
            else:
                error("Error. Unknown output format: {}".format(args[i+1]))
                return 
        elif( args[i] in [OPTION_SHORTEST, OPTION_SHORTEST_SHORT]):
            if( seenShortest ):
                error("Option '{}' should be used only once".format(args[i]))
                return 
            seenShortest = True
            i += 1
        elif( args[i] == OPTION_LMAX or args[i] == OPTION_LMAX_SHORT ):
            if( seenLmax ):
                error("Option '{}' should be used only once".format(args[i]))
                return 
            if( i+1 >= len(args)):
                error("Error. Missing length after option '"+args[i]+"'")
                return 
            try:
                clmax = int(args[i+1])
                if( clmax < Arch.octets() ):
                    raise Exception()
                # Convert number of bytes into number of ropchain elements
                clmax /= Arch.octets()
            except:
                error("Error. '" + args[i+1] +"' bytes is not valid")
                return 
            i += 2 
            seenLmax = True
        elif( args[i] in [OPTION_HELP, OPTION_HELP_SHORT]):
            print_help()
            return 
        else:
            error("Error. Unknown option '{}'".format(args[i]))
            return 
    
    if( not funcName ):
        error("Missing function to call")
    else:
        res = build_call(funcName, funcArgs, constraint, assertion, clmax=clmax, optimizeLen=seenShortest)
        if( isinstance(res, str) ):
            error(res)
        else:
            print_chains([res], "Built matching ROPChain", constraint.getBadBytes())