Example #1
0
    def _analyze_state(state) -> List[Issue]:
        instruction = state.get_current_instruction()
        address, value = state.mstate.stack[-1], state.mstate.stack[-2]

        target_slot = 0
        target_offset = 0

        # In the following array we'll describe all the conditions that need to hold for a take over of ownership
        vulnerable_conditions = [
            # Lets check that we're writing to address 0 (where the owner variable is located
            address == target_slot,
            # There is only a vulnerability if before the writing to the owner variable: owner != attacker
            Extract(
                20*8 + target_offset,
                0 + target_offset,
                state.environment.active_account.storage[symbol_factory.BitVecVal(0, 256)]
            ) != ACTORS.attacker,
            # There IS a vulnerability if the value being written to owner is the attacker address
            Extract(
                20*8 + target_offset,
                0 + target_offset,
                value,
            ) == ACTORS.attacker,
            # Lets only look for cases where the attacker makes themselves the owner by saying that the attacker
            # is the sender of this transaction
            state.environment.sender == ACTORS.attacker,
        ]

        try:
            # vulnerable_conditions describes when there is a vulnerability
            # lets check if the conditions are actually satisfiable by running the following command:
            # This will raise an UnsatError if the vulnerable_conditions are not satisfiable (i.e. not possible)
            transaction_sequence = solver.get_transaction_sequence(
                state,
                state.world_state.constraints
                + vulnerable_conditions,
            )
            # Note that get_transaction_sequence also gives us `transaction_sequence` which gives us a concrete
            # transaction trace that can be used to exploit/demonstrate the vulnerability.

            # Lets register an issue with Mythril so that the vulnerability is reported to the user!
            return [Issue(
                contract=state.environment.active_account.contract_name,
                function_name=state.environment.active_function_name,
                address=instruction["address"],
                swc_id='000',
                bytecode=state.environment.code.bytecode,
                title="Ownership Takeover",
                severity="High",
                description_head="An attacker can take over ownership of this contract.",
                description_tail="",
                transaction_sequence=transaction_sequence,
                gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
            )]
        except UnsatError:
            # Sadly (or happily), no vulnerabilities were found here.
            log.debug("Vulnerable conditions were not satisfiable")
            return list()
Example #2
0
    def write_word_at(self, index: int, value: Union[int, BitVec, bool,
                                                     Bool]) -> None:
        """Writes a 32 byte word to memory at the specified index`

        :param index: index to write to
        :param value: the value to write to memory
        """
        try:
            # Attempt to concretize value
            if isinstance(value, bool):
                _bytes = (int(1).to_bytes(32, byteorder="big")
                          if value else int(0).to_bytes(32, byteorder="big"))
            else:
                _bytes = util.concrete_int_to_bytes(value)
            assert len(_bytes) == 32
            self[index:index + 32] = list(bytearray(_bytes))
        except (Z3Exception, AttributeError):  # BitVector or BoolRef
            value = cast(Union[BitVec, Bool], value)
            if isinstance(value, Bool):
                value_to_write = If(
                    value,
                    symbol_factory.BitVecVal(1, 256),
                    symbol_factory.BitVecVal(0, 256),
                )
            else:
                value_to_write = value
            assert value_to_write.size() == 256

            for i in range(0, value_to_write.size(), 8):
                self[index + 31 - (i // 8)] = Extract(i + 7, i, value_to_write)
Example #3
0
 def _sanitize(input_: BitVec) -> BitVec:
     if input_.size() == 512:
         return input_
     if input_.size() > 512:
         return Extract(511, 0, input_)
     else:
         return Concat(symbol_factory.BitVecVal(0, 512 - input_.size()), input_)
Example #4
0
 def get_map_index(key: BitVec) -> BitVec:
     if (
         not isinstance(key, BitVecFunc)
         or key.func_name != "keccak256"
         or key.input_ is None
     ):
         return None
     index = Extract(255, 0, key.input_)
     return simplify(index)