Exemplo n.º 1
0
def call(funcName, parsedArgs, constraint, assertion):
    # Get target system
    if (Arch.currentBinType == Arch.BinaryType.X86_ELF):
        syscall = Linux32.available.get(funcName)
        system = sysLinux32
    elif (Arch.currentBinType == Arch.BinaryType.X64_ELF):
        syscall = Linux64.available.get(funcName)
        system = sysLinux64
    else:
        error("Binary type '{}' not supported yet".format(Arch.currentBinType))
        return

    if (not syscall):
        error("Syscall '{}' not supported for system '{}'".format(\
        funcName, system))
        return

    if (len(parsedArgs) != len(syscall.args)):
        error("Error. Wrong number of arguments")
        return

    # Build syscall
    res = _build_syscall(syscall.buildFunc, parsedArgs, constraint, assertion)
    # Print result
    if (not res):
        print(string_bold("\n\tNo matching ROPChain found"))
    else:
        print(string_bold("\n\tFound matching ROPChain\n"))
        badBytes = constraint.getBadBytes()
        if (OUTPUT == OUTPUT_CONSOLE):
            print(res.strConsole(Arch.bits(), badBytes))
        elif (OUTPUT == OUTPUT_PYTHON):
            print(res.strPython(Arch.bits(), badBytes))
Exemplo n.º 2
0
 def __init__(self, num, ind=0, size=None):
     Expr.__init__(self)
     if (isinstance(num, SSAReg)):
         self.reg = SSAReg(num.num, num.ind)
     else:
         self.reg = SSAReg(num, ind)
     if (size is None):
         size = Arch.bits()
     self.size = size
Exemplo n.º 3
0
 def addOffset(self, offset):
     new_addresses = []
     for addr in self.addrList:
         new = addr + offset
         # Check if offset isn't too big
         if( new >= (0x1 << Arch.bits())\
             or new < 0 ):
             return False
         new_addresses.append(new)
     self.addrList = new_addresses
     return True
Exemplo n.º 4
0
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)
Exemplo n.º 5
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
Exemplo n.º 6
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
Exemplo n.º 7
0
def _adjust_ret(qtype, arg1, arg2, env, n):
    """
    Search with basic but adjust the bad returns they have 
    """
    global LMAX
    ID = StrategyType.ADJUST_RET

    ## Test for special cases
    # Test lmax
    if (env.getLmax() <= 0):
        return FailRecord(lmax=True)
    # Limit number of calls to ...
    elif (env.nbCalls(ID) >= 2):
        return FailRecord()
    # Test for ip
    # Reason: can not adjust ip if ip is the
    # target of the query :/
    elif (arg1 == Arch.ipNum()):
        return FailRecord()

    # Set env
    env.addCall(ID)
    saved_adjust_ret = env.getImpossible_adjust_ret().copy()

    ########################################
    res = []
    res_fail = FailRecord()
    padding = env.getConstraint().getValidPadding(Arch.octets())
    # Get possible gadgets
    constraint = env.getConstraint()
    env.setConstraint(constraint.add(Chainable(jmp=True, call=True)))
    possible = _basic(qtype, arg1, arg2, env, 10 * n)
    env.setConstraint(constraint)

    if (not possible):
        res_fail.merge(possible)
        possible = []

    # Try to adjust them
    for chain in possible:
        g = chain.chain[0]
        ret_reg = g.retValue.reg.num
        # Check if we already know that ret_reg can't be adjusted
        if (env.checkImpossible_adjust_ret(ret_reg)):
            continue
        #Check if ret_reg not modified within the gadget
        elif (ret_reg in g.modifiedRegs()):
            continue
        # Check if stack is preserved
        elif (g.spInc is None):
            continue

        # Find adjustment
        if (g.spInc < 0):
            offset = -1 * g.spInc
            padding_length = 0
        else:
            padding_length = g.spInc / Arch.octets()
            if (g.retType == RetType.JMP):
                offset = 0
            else:
                offset = Arch.octets()
        if (isinstance(arg1, int)):
            arg1_reg = arg1
        else:
            arg1_reg = arg1[0]

        # Get adjustment gadgets
        env.setConstraint(constraint.add(RegsNotModified([arg1_reg])))
        saved_lmax = env.getLmax()
        env.setLmax(LMAX)
        adjust_gadgets = _search(QueryType.MEMtoREG, Arch.ipNum(), \
                (Arch.spNum(),offset), env, n=1)
        env.setConstraint(constraint)
        env.setLmax(saved_lmax)

        if (not adjust_gadgets):
            res_fail.merge(adjust_gadgets)
            continue
        else:
            adjust_addr = int(validAddrStr(adjust_gadgets[0].chain[0],\
                    constraint.getBadBytes(), Arch.bits()),  16)

        # Find gadgets to put the gadget address in the jmp/call register
        if (isinstance(arg2, int)):
            arg2_reg = arg2
        else:
            arg2_reg = arg2[0]

        env.setConstraint(constraint.add(RegsNotModified([arg2_reg])))
        env.subLmax(1 + padding_length)
        env.pushComment(
            StrategyType.CSTtoREG_POP,
            "Address of " + string_bold(str(adjust_gadgets[0].chain[0])))
        adjust = _search(QueryType.CSTtoREG, ret_reg, adjust_addr, env, n=1)
        env.popComment(StrategyType.CSTtoREG_POP)
        env.addLmax(1 + padding_length)
        env.setConstraint(constraint)
        if (adjust):
            res.append(adjust[0].addGadget(g).addPadding(padding,
                                                         n=padding_length))
            if (len(res) >= n):
                break
        else:
            # Update the search record to say that reg_ret cannot be adjusted
            env.addImpossible_adjust_ret(ret_reg)
            res_fail.merge(adjust)
    ########################################
    # Restore env
    env.impossible_adjust_ret = saved_adjust_ret
    env.removeCall(ID)
    return res if res else res_fail
Exemplo n.º 8
0
def _adjust_ret(qtype,
                arg1,
                arg2,
                constraint,
                assertion,
                n,
                clmax=LMAX,
                record=None,
                comment=""):
    """
    Search with basic but adjust the bad returns they have 
    """
    # Test clmax
    if (clmax <= 0):
        return []

    # Test for ip
    if (arg1 == Arch.ipNum()):
        return []
    # Test for search record
    if (record is None):
        record = SearchRecord()

    res = []
    possible = _basic(qtype, arg1, arg2, \
            constraint.add(Chainable(jmp=True, call=True)), assertion, n)
    padding = constraint.getValidPadding(Arch.currentArch.octets)
    for chain in possible:
        g = chain.chain[0]
        ret_reg = g.retValue.reg.num
        # Check if we already know that ret_reg can't be adjusted
        if (record.impossible_AdjustRet.check(ret_reg)):
            continue
        #Check if ret_reg not modified within the gadget
        if (ret_reg in g.modifiedRegs()):
            continue
        # Check if stack is preserved
        if (g.spInc is None):
            continue

        # Find adjustment
        if (g.spInc < 0):
            offset = -1 * g.spInc
            padding_length = 0
        else:
            padding_length = g.spInc
            if (g.retType == RetType.JMP):
                offset = 0
            else:
                offset = Arch.octets()
        adjust_gadgets = search(QueryType.MEMtoREG, Arch.ipNum(), \
                (Arch.spNum(),offset), constraint.add(RegsNotModified([arg1])), assertion, n=1, record=record)
        if (not adjust_gadgets):
            continue
        else:
            adjust_addr = int(validAddrStr(adjust_gadgets[0].chain[0],\
                    constraint.getBadBytes(), Arch.bits()),  16)
        # Put the gadget address in the register
        adjust = search(QueryType.CSTtoREG, ret_reg, adjust_addr, \
            constraint.add(RegsNotModified([arg2[0]])), assertion, n=1, clmax=clmax-len(chain),record=record,\
            comment="Address of "+string_bold(str(adjust_gadgets[0].chain[0])))
        if (adjust):
            res.append(adjust[0].addGadget(g).addPadding(padding,
                                                         n=padding_length))
            if (len(res) >= n):
                return res
        else:
            # Update the search record to say that reg_ret cannot be adjusted
            record.impossible_AdjustRet.add(ret_reg)
    return res
Exemplo n.º 9
0
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)