mirror of https://github.com/ConsenSys/mythril
parent
2175ee7b1a
commit
e001b2d5e7
@ -0,0 +1,100 @@ |
||||
import logging |
||||
|
||||
from mythril.analysis.solver import get_model |
||||
from mythril.analysis.report import Issue |
||||
from mythril.laser.ethereum.state.annotation import StateAnnotation |
||||
from mythril.laser.ethereum.state.global_state import GlobalState |
||||
from mythril.laser.smt import get_variables_from_constraints |
||||
from mythril.analysis.swc_data import TX_ORDER_DEPENDENCE |
||||
from mythril.analysis.modules.base import DetectionModule |
||||
from mythril.exceptions import UnsatError |
||||
|
||||
|
||||
log = logging.getLogger(__name__) |
||||
|
||||
|
||||
class StorageAnnotation(StateAnnotation): |
||||
def __init__(self, storage_state: GlobalState): |
||||
self.storage_state = storage_state |
||||
|
||||
|
||||
def get_transitive_annotations(value, constraints): |
||||
queue = [value] |
||||
visited = set() |
||||
visited.add(value) |
||||
annotations = [] |
||||
for value in queue: |
||||
annotations += value.annotations |
||||
for constraint in constraints: |
||||
var_list = list(get_variables_from_constraints(constraint)) |
||||
if value not in var_list: |
||||
continue |
||||
for var in var_list: |
||||
if var not in queue: |
||||
continue |
||||
visited.add(var) |
||||
queue.append(var) |
||||
return annotations |
||||
|
||||
|
||||
class TxOrderDependenceModule(DetectionModule): |
||||
def __init__(self): |
||||
super().__init__( |
||||
name="Transaction Order Dependence", |
||||
swc_id=TX_ORDER_DEPENDENCE, |
||||
pre_hooks=["CALL", "STATICCALL", "CALLCODE", "SSTORE"], |
||||
entrypoint="callback", |
||||
description=( |
||||
"This module finds the existance of transaction order dependence " |
||||
"vulnerabilities. The following webpage contains an extensive description " |
||||
"of the vulnerability: " |
||||
"https://consensys.github.io/smart-contract-best-practices/known_attacks/#transaction-ordering-dependence-tod-front-running" |
||||
), |
||||
) |
||||
|
||||
def execute(self, state: GlobalState): |
||||
""" Executes the analysis module""" |
||||
log.debug("Executing module: TOD") |
||||
opcode = state.get_current_instruction()["opcode"] |
||||
if opcode == "SSTORE": |
||||
value = state.mstate.stack[-2] |
||||
value.annotate(StorageAnnotation(state)) |
||||
state.mstate.stack[-2] = value |
||||
value = state.mstate.stack[-3] |
||||
annotations = get_transitive_annotations(value, state.mstate.constraints) |
||||
for annotation in annotations: |
||||
if not isinstance(annotation, StorageAnnotation): |
||||
continue |
||||
if int(annotation.storage_state.current_transaction.id) >= int( |
||||
state.current_transaction.id |
||||
): |
||||
continue |
||||
try: |
||||
get_model( |
||||
state.mstate.constraints |
||||
+ [ |
||||
state.current_transaction.caller |
||||
!= annotation.storage_state.current_transaction.caller |
||||
] |
||||
) |
||||
except UnsatError: |
||||
continue |
||||
description_tail = "A transaction order dependence vulnerability may exist in this contract. The value or target of the call statement is loaded from a writable storage location." |
||||
|
||||
issue = Issue( |
||||
contract=state.environment.active_account.contract_name, |
||||
function_name=state.environment.active_function_name, |
||||
address=annotation.storage_state.environment.active_function_address, |
||||
title="Transaction Order Dependence", |
||||
bytecode=state.environment.code.bytecode, |
||||
swc_id=TX_ORDER_DEPENDENCE, |
||||
severity="Medium", |
||||
description_head="The call outcome may depend on transaction order.", |
||||
description_tail=description_tail, |
||||
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), |
||||
) |
||||
self.issues.append(issue) |
||||
return self.issues |
||||
|
||||
|
||||
detector = TxOrderDependenceModule() |
Loading…
Reference in new issue