First implementation of blockhash handling

pull/1029/head
Bernhard Mueller 6 years ago
parent c8aad25921
commit 9175a1975f
  1. 34
      mythril/analysis/modules/dependence_on_predictable_vars.py
  2. 2
      mythril/laser/ethereum/instructions.py
  3. 1
      mythril/laser/ethereum/state/environment.py

@ -4,14 +4,23 @@ import logging
from mythril.analysis.modules.base import DetectionModule from mythril.analysis.modules.base import DetectionModule
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.exceptions import UnsatError
from mythril.analysis import solver
from mythril.laser.smt import ULT
from mythril.analysis.swc_data import TIMESTAMP_DEPENDENCE, WEAK_RANDOMNESS from mythril.analysis.swc_data import TIMESTAMP_DEPENDENCE, WEAK_RANDOMNESS
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.state.annotation import StateAnnotation
import traceback
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
predictable_ops = ["COINBASE", "GASLIMIT", "TIMESTAMP", "NUMBER"] predictable_ops = ["COINBASE", "GASLIMIT", "TIMESTAMP", "NUMBER"]
def is_prehook():
return "pre_hook" in traceback.format_stack()[-2]
class PredictableValueAnnotation: class PredictableValueAnnotation:
""" Symbol Annotation used if a variable is initialized from a predictable environment variable""" """ Symbol Annotation used if a variable is initialized from a predictable environment variable"""
@ -19,6 +28,12 @@ class PredictableValueAnnotation:
self.opcode = opcode self.opcode = opcode
class TaintBlockHashAnnotation(StateAnnotation):
def __init__(self) -> None:
pass
class PredictableDependenceModule(DetectionModule): class PredictableDependenceModule(DetectionModule):
"""This module detects whether control flow decisions are made using predictable """This module detects whether control flow decisions are made using predictable
parameters.""" parameters."""
@ -33,8 +48,8 @@ class PredictableDependenceModule(DetectionModule):
"block.gaslimit, block.timestamp or block.number." "block.gaslimit, block.timestamp or block.number."
), ),
entrypoint="callback", entrypoint="callback",
pre_hooks=["JUMPI"], pre_hooks=["BLOCKHASH", "JUMPI"],
post_hooks=predictable_ops, post_hooks=["BLOCKHASH"] + predictable_ops,
) )
def execute(self, state: GlobalState) -> list: def execute(self, state: GlobalState) -> list:
@ -86,6 +101,21 @@ def _analyze_states(state: GlobalState) -> list:
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
) )
issues.append(issue) issues.append(issue)
elif state.get_current_instruction()["opcode"] == "BLOCKHASH":
if is_prehook():
param = state.mstate.stack[-1]
try:
solver.get_model(ULT(param, state.environment.block_number))
state.annotate(TaintBlockHashAnnotation)
except UnsatError:
pass
else:
for annotation in state.annotations:
if isinstance(annotation, TaintBlockHashAnnotation):
state.mstate.stack[-1].annotate(PredictableValueAnnotation("BLOCKHASH"))
else: else:
# we're in post hook # we're in post hook

@ -1243,7 +1243,7 @@ class Instruction:
:param global_state: :param global_state:
:return: :return:
""" """
global_state.mstate.stack.append(global_state.new_bitvec("block_number", 256)) global_state.mstate.stack.append(global_state.environment.block_number)
return [global_state] return [global_state]
@StateTransition() @StateTransition()

@ -40,6 +40,7 @@ class Environment:
self.active_function_name = "" self.active_function_name = ""
self.address = symbol_factory.BitVecVal(int(active_account.address, 16), 256) self.address = symbol_factory.BitVecVal(int(active_account.address, 16), 256)
self.block_number = symbol_factory.BitVecSym("block_number", 256)
# Ib # Ib
self.code = active_account.code if code is None else code self.code = active_account.code if code is None else code

Loading…
Cancel
Save