Source code for mythril.analysis.module.modules.suicide

from mythril.analysis import solver
from mythril.analysis.report import Issue
from mythril.analysis.swc_data import UNPROTECTED_SELFDESTRUCT
from mythril.exceptions import UnsatError
from mythril.analysis.issue_annotation import IssueAnnotation
from mythril.analysis.module.base import DetectionModule, EntryPoint
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.transaction.symbolic import ACTORS
from mythril.laser.smt.bool import And
from mythril.laser.ethereum.transaction.transaction_models import (
    ContractCreationTransaction,
)
import logging
from mythril.laser.ethereum.function_managers import keccak_function_manager


log = logging.getLogger(__name__)

DESCRIPTION = """
Check if the contact can be 'accidentally' killed by anyone.
For kill-able contracts, also check whether it is possible to direct the contract balance to the attacker.
"""


[docs]class AccidentallyKillable(DetectionModule): """This module checks if the contact can be 'accidentally' killed by anyone.""" name = "Contract can be accidentally killed by anyone" swc_id = UNPROTECTED_SELFDESTRUCT description = DESCRIPTION entry_point = EntryPoint.CALLBACK pre_hooks = ["SELFDESTRUCT"] def __init__(self): super().__init__() self._cache_address = {}
[docs] def reset_module(self): """ Resets the module :return: """ super().reset_module()
def _execute(self, state: GlobalState) -> None: """ :param state: :return: """ return self._analyze_state(state) def _analyze_state(self, state): log.info("Suicide module: Analyzing suicide instruction") instruction = state.get_current_instruction() to = state.mstate.stack[-1] log.debug("SELFDESTRUCT in function %s", state.environment.active_function_name) description_head = "Any sender can cause the contract to self-destruct." attacker_constraints = [] for tx in state.world_state.transaction_sequence: if not isinstance(tx, ContractCreationTransaction): attacker_constraints.append( And(tx.caller == ACTORS.attacker, tx.caller == tx.origin) ) try: try: constraints = ( state.world_state.constraints + [to == ACTORS.attacker] + attacker_constraints ) transaction_sequence = solver.get_transaction_sequence( state, constraints ) description_tail = ( "Any sender can trigger execution of the SELFDESTRUCT instruction to destroy this " "contract account and withdraw its balance to an arbitrary address. Review the transaction trace " "generated for this issue and make sure that appropriate security controls are in place to prevent " "unrestricted access." ) except UnsatError: constraints = state.world_state.constraints + attacker_constraints transaction_sequence = solver.get_transaction_sequence( state, constraints ) description_tail = ( "Any sender can trigger execution of the SELFDESTRUCT instruction to destroy this " "contract account. Review the transaction trace generated for this issue and make sure that " "appropriate security controls are in place to prevent unrestricted access." ) issue = Issue( contract=state.environment.active_account.contract_name, function_name=state.environment.active_function_name, address=instruction["address"], swc_id=UNPROTECTED_SELFDESTRUCT, bytecode=state.environment.code.bytecode, title="Unprotected Selfdestruct", severity="High", description_head=description_head, description_tail=description_tail, transaction_sequence=transaction_sequence, gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), ) state.annotate( IssueAnnotation( conditions=[And(*constraints)], issue=issue, detector=self ) ) return [issue] except UnsatError: log.debug("No model found") return []
detector = AccidentallyKillable()