Exemplo n.º 1
0
def BYTE(i, x):
	bit = (i + 1) * 8
	return If(
		UGT(i, x.size() / 8 - 1),
		BitVecVal(0, x.size()),
		(LShR(x, (x.size() - bit))) & 0xff
	)
Exemplo n.º 2
0
def _analyze_state(state):
    instruction = state.get_current_instruction()
    node = state.node

    if instruction["opcode"] != "CALL":
        return []

    call_value = state.mstate.stack[-3]
    target = state.mstate.stack[-2]

    eth_sent_total = BitVecVal(0, 256)

    constraints = copy(node.constraints)

    for tx in state.world_state.transaction_sequence:
        if tx.caller == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF:

            # There's sometimes no overflow check on balances added.
            # But we don't care about attacks that require more 2^^256 ETH to be sent.

            constraints += [
                BVAddNoOverflow(eth_sent_total, tx.call_value, False)
            ]
            eth_sent_total = Sum(eth_sent_total, tx.call_value)
    constraints += [
        UGT(call_value, eth_sent_total), target == state.environment.sender
    ]

    try:

        transaction_sequence = solver.get_transaction_sequence(
            state, constraints)

        debug = str(transaction_sequence)

        issue = Issue(
            contract=node.contract_name,
            function_name=node.function_name,
            address=instruction["address"],
            swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
            title="Ether thief",
            _type="Warning",
            bytecode=state.environment.code.bytecode,
            description=
            "Arbitrary senders other than the contract creator can withdraw ETH from the contract"
            +
            " account without previously having sent an equivalent amount of ETH to it. This is likely to be"
            + " a vulnerability.",
            debug=debug,
            gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
        )
    except UnsatError:
        logging.debug("[ETHER_THIEF] no model found")
        return []

    return [issue]
Exemplo n.º 3
0
 def constraints(self):
     constraints = []
     if self.concrete:
         for calldata_byte in self.starting_calldata:
             if type(calldata_byte) == int:
                 self._calldata.append(BitVecVal(calldata_byte, 8))
             else:
                 self._calldata.append(calldata_byte)
         constraints.append(
             self.calldatasize == len(self.starting_calldata))
     else:
         x = BitVec("x", 256)
         constraints.append(
             ForAll(x, Implies(self[x] != 0, UGT(self.calldatasize, x))))
     return constraints
Exemplo n.º 4
0
    def __getitem__(self, item: Union[int, slice]) -> Any:
        if isinstance(item, slice):
            start, step, stop = item.start, item.step, item.stop
            try:
                if start is None:
                    start = 0
                if step is None:
                    step = 1
                if stop is None:
                    stop = self.calldatasize
                current_index = (start if isinstance(start, BitVecRef) else
                                 BitVecVal(start, 256))
                dataparts = []
                while simplify(current_index != stop):
                    dataparts.append(self[current_index])
                    current_index = simplify(current_index + step)
            except Z3Exception:
                raise IndexError("Invalid Calldata Slice")

            values, constraints = zip(*dataparts)
            result_constraints = []
            for c in constraints:
                result_constraints.extend(c)
            return simplify(Concat(values)), result_constraints

        if self.concrete:
            try:
                return self._calldata[get_concrete_int(item)], ()
            except IndexError:
                return BitVecVal(0, 8), ()
        else:
            constraints = [
                Implies(self._calldata[item] != 0, UGT(self.calldatasize,
                                                       item))
            ]

            return self._calldata[item], constraints
Exemplo n.º 5
0
    def visit_MLIL_CMP_UGT(self, expr):
        left, right = self.visit_both_sides(expr)

        return UGT(left, right)
Exemplo n.º 6
0
 def visit_MLIL_CMP_UGT(self, expr):
     left = self.visit(expr.left)
     right = self.visit(expr.right)
     if None not in (left, right):
         return UGT(left, right)
Exemplo n.º 7
0
 def visit_MLIL_CMP_UGT(self, expr):
     left, right = self.visit_both_sides(expr)
     if right.size() != left.size():
         right = ZeroExt(left.size() - right.size(), right)
     return UGT(left, right)
Exemplo n.º 8
0
 def gt_(self, global_state):
     state = global_state.mstate
     exp = UGT(util.pop_bitvec(state), util.pop_bitvec(state))
     state.stack.append(exp)
     return [global_state]
Exemplo n.º 9
0
 def operate_GT(self, *values):
     s0 = hlp.convert_to_bitvec(values[0])
     s1 = hlp.convert_to_bitvec(values[1])
     return hlp.get_concrete_int(UGT(s0, s1))
Exemplo n.º 10
0
def GT(x, y):
	return If(UGT(x, y), BitVecVal(1, x.size()), BitVecVal(0, x.size()))
n_bits = 64

# Input vars
X = BitVec('X', n_bits)
A = BitVec('A', n_bits)
B = BitVec('B', n_bits)

# Constants
BitWidth = BitVecVal(n_bits, n_bits)

# Requirements
rule.require(ULT(A, BitWidth))
rule.require(ULT(B, BitWidth))

# Non optimized result
nonopt = SHR(B, SHL(A, X))

# Optimized result
Mask = SHR(B, SHL(A, Int2BV(IntVal(-1), n_bits)))
opt = If(
	UGT(A, B),
	AND(SHL(A - B, X), Mask),
		If(
			UGT(B, A),
			AND(SHR(B - A, X), Mask),
			AND(X, Mask)
		)
	)

rule.check(nonopt, opt)
Exemplo n.º 12
0
    def _analyze_state(state, node):
        issues = []
        instruction = state.get_current_instruction()

        if instruction["opcode"] != "CALL":
            return []

        call_value = state.mstate.stack[-3]
        target = state.mstate.stack[-2]

        not_creator_constraints, constrained = get_non_creator_constraints(
            state)
        if constrained:
            return []

        eth_sent_total = BitVecVal(0, 256)

        for tx in state.world_state.transaction_sequence[1:]:
            eth_sent_total += tx.call_value

        try:

            model = solver.get_model(
                node.constraints + not_creator_constraints + [
                    UGT(call_value, eth_sent_total),
                    state.environment.sender == ARBITRARY_SENDER_ADDRESS,
                    target == state.environment.sender,
                ])

            transaction_sequence = solver.get_transaction_sequence(
                state,
                node.constraints + not_creator_constraints + [
                    call_value > eth_sent_total,
                    state.environment.sender == ARBITRARY_SENDER_ADDRESS,
                    target == state.environment.sender,
                ],
            )

            debug = "Transaction Sequence: " + str(transaction_sequence)

            issue = Issue(
                contract=node.contract_name,
                function_name=node.function_name,
                address=instruction["address"],
                swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
                title="Ether thief",
                _type="Warning",
                bytecode=state.environment.code.bytecode,
                description=
                "Arbitrary senders other than the contract creator can withdraw ETH from the contract"
                +
                " account without previously having sent an equivalent amount of ETH to it. This is likely to be"
                + " a vulnerability.",
                debug=debug,
                gas_used=(state.mstate.min_gas_used,
                          state.mstate.max_gas_used),
            )
            issues.append(issue)
        except UnsatError:
            logging.debug("[ETHER_THIEF] no model found")

        return issues