Beispiel #1
0
def normalizeIntervals(intervals):
    """
    Given a list of [min, max) intervals,
        - sort them in increasing order, and
        - collapse contiguous intervals into a single larger interval
    returns: new list of intervals
    """
    assert isinstance(intervals, list)
    intervals.sort(
        key=lambda pair: -1 if (isAst(pair[0]) or isAst(pair[1])) else pair[0]
    )  # sort all symbolic intervals to beginning, otherwise sort by low coordinate
    newIntervals = []
    while intervals:
        interval = intervals.pop()  # gets the interval with largest max
        if intervals:
            prevInterval = intervals[-1]  # the interval before that
            while isDefinitelyEqual(
                    prevInterval[1], interval[0]
            ):  # this interval is contiguous with the previous interval
                intervals.pop()  # remove prevInterval
                interval[0] = prevInterval[
                    0]  # `interval` now covers the entire range
                if not intervals: break  # no intervals left
                prevInterval = intervals[
                    -1]  # now compare with the interval before _that_
            # not contiguous with the previous interval
        newIntervals.append(interval)
    return newIntervals
Beispiel #2
0
 def intervalkey(pair):
     if isAst(pair[0]) and isAst(pair[1]):
         lower = pair[0]
         if lower.op == '__add__':
             try:
                 bvs = next(arg.args[0] for arg in lower.args if arg.op == 'BVS')
                 bvv = next(arg.args[0] for arg in lower.args if arg.op == 'BVV')
                 return (bvs, bvv)
             except StopIteration:
                 pass
         elif lower.op == 'BVS':
             return (lower.args[0], 0)
     elif not isAst(pair[0]):
         return ('\xff', pair[0])
     return ('', -1)
Beispiel #3
0
def _tainted_write(state):
    addr = state.inspect.mem_write_address
    #expr = state.inspect.mem_write_expr
    #l.debug("wrote {} (with leaf_asts {}) to {} (with leaf_asts {})".format(
    #describeAst(expr),
    #list(describeAst(leaf) for leaf in expr.leaf_asts()),
    #describeAst(addr),
    #list(describeAst(leaf) for leaf in addr.leaf_asts())))
    return isAst(addr) and is_tainted(addr)
Beispiel #4
0
def _tainted_read(state):
    addr = state.inspect.mem_read_address
    #expr = state.inspect.mem_read_expr
    #l.debug("read {} (with leaf_asts {}) from {} (with leaf_asts {})".format(
    #describeAst(expr),
    #list(describeAst(leaf) for leaf in expr.leaf_asts()),
    #describeAst(addr),
    #list(describeAst(leaf) for leaf in addr.leaf_asts())))
    return isAst(addr) and is_tainted(addr)
Beispiel #5
0
def _tainted_branch(state):
    guard = state.inspect.exit_guard
    return isAst(guard) and is_tainted(guard) and \
        state.solver.satisfiable(extra_constraints=[guard == True]) and \
        state.solver.satisfiable(extra_constraints=[guard == False])
Beispiel #6
0
    def arm(self, state):
        """
        Setup hooks and breakpoints to perform Spectre gadget vulnerability detection.
        Also set up concretization to ensure addresses always point to secret data when possible.
        """
        if self._armed:
            l.warn("called arm() on already-armed SpectreExplicitState")
            return

        state.inspect.b('mem_read',
                        when=angr.BP_AFTER,
                        condition=_tainted_read,
                        action=detected_spectre_read)
        state.inspect.b('mem_write',
                        when=angr.BP_AFTER,
                        condition=_tainted_write,
                        action=detected_spectre_write)
        state.inspect.b('exit',
                        when=angr.BP_BEFORE,
                        condition=_tainted_branch,
                        action=detected_spectre_branch)

        state.options.add(angr.options.SYMBOLIC_WRITE_ADDRESSES)
        state.options.add(angr.options.SYMBOL_FILL_UNCONSTRAINED_MEMORY)
        state.options.add(angr.options.SYMBOL_FILL_UNCONSTRAINED_REGISTERS)
        state.options.add(angr.options.SYMBOLIC_INITIAL_VALUES)

        secretStart = 0x1100000  # a should-be-unused part of the virtual memory space, after where CLE puts its 'externs' object
        secretMustEnd = 0x2000000  # secrets must be stored somewhere in [secretStart, secretMustEnd)

        notSecretAddresses = []  # see notes in MemoryLayout.__init__
        for (var, val) in self.vars:
            assert isAst(var)
            assert isinstance(val, AbstractValue)
            if val.value is not None: state.add_constraints(var == val.value)
            if val.secret:
                raise ValueError(
                    "not implemented yet: secret arguments passed by value")
            elif isinstance(val, AbstractPointer):
                if val.cannotPointSecret: notSecretAddresses.append(var)
                (mlayout,
                 newStart) = memLayoutForPointee(var, val.pointee, secretStart,
                                                 secretMustEnd)
                secretStart = newStart  # update to account for what was used in the call to memLayoutForPointee
                self.secretIntervals.extend(mlayout.secretIntervals)
                notSecretAddresses.extend(mlayout.notSecretAddresses)
                for (a, (v, bits)) in mlayout.concreteAssignments.items():
                    #print("Assigning address {} to value {}, {} bits".format(describeAst(a), describeAst(v), bits))
                    if bits == 8: state.mem[a].uint8_t = v
                    elif bits == 16: state.mem[a].uint16_t = v
                    elif bits == 32: state.mem[a].uint32_t = v
                    elif bits == 64: state.mem[a].uint64_t = v
                    else:
                        raise ValueError(
                            "unexpected bitlength: {}".format(bits))
            elif isinstance(val, AbstractPointerToUnconstrainedPublic):
                if val.cannotPointSecret: notSecretAddresses.append(var)
            #print("Secret intervals:")
            #for (mn, mx) in self.secretIntervals:
            #print("[{}, {})".format(describeAst(mn), describeAst(mx)))
            #print("Not-secret addresses:")
            #for addr in notSecretAddresses:
            #print(describeAst(addr))

        self.secretIntervals = normalizeIntervals(self.secretIntervals)

        for (mn, mx) in self.secretIntervals:
            if isAst(mn):
                if state.solver.solution(mn, secretStart):
                    mn_as_int = secretStart
                    state.solver.add(mn == mn_as_int)
                    length = state.solver.eval_one(
                        mx - mn_as_int
                    )  # should be only one possible value of that expression, under these constraints
                    if length is None:
                        raise ValueError(
                            "Expected one solution for {} but got these: {}".
                            format(mx - mn_as_int,
                                   state.solver.eval(mx - mn_as_int)))
                    mx_as_int = mn_as_int + length
                    state.solver.add(mx == mx_as_int)
                    secretStart += length
                else:
                    raise ValueError(
                        "Can't resolve secret address {} to desired value {}".
                        format(mn, secretStart))
            elif isAst(mx):
                raise ValueError(
                    "not implemented yet: interval min {} is concrete but max {} is symbolic"
                    .format(mn, mx))
            else:
                mn_as_int = mn
                mx_as_int = mx
            for i in range(mn_as_int, mx_as_int):
                state.mem[i].uint8_t = oob_memory_fill("secret", 8, state)

        for addr in notSecretAddresses:
            state.solver.add(
                claripy.And(*[
                    claripy.Or(addr < mn, addr >= mx)
                    for (mn, mx) in self.secretIntervals
                ]))

        state.memory.read_strategies.insert(
            0, TargetedStrategy(self.secretIntervals))
        state.memory.write_strategies.insert(
            0, TargetedStrategy(self.secretIntervals))
        #state.inspect.b('address_concretization', when=angr.BP_AFTER, condition=concretization_succeeded, action=log_concretization)

        self._armed = True