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()
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)
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_)
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)