mirror of https://github.com/ConsenSys/mythril
commit
1016af10d7
@ -0,0 +1,114 @@ |
|||||||
|
from z3 import * |
||||||
|
from mythril.analysis.ops import * |
||||||
|
from mythril.analysis import solver |
||||||
|
from mythril.analysis.report import Issue |
||||||
|
from mythril.exceptions import UnsatError |
||||||
|
import re |
||||||
|
import logging |
||||||
|
|
||||||
|
|
||||||
|
''' |
||||||
|
MODULE DESCRIPTION: |
||||||
|
|
||||||
|
Check for CALLs that send >0 Ether to either the transaction sender, or to an address provided as a function argument. |
||||||
|
If msg.sender is checked against a value in storage, check whether that storage index is tainted (i.e. there's an unconstrained write |
||||||
|
to that index). |
||||||
|
''' |
||||||
|
|
||||||
|
def execute(statespace): |
||||||
|
|
||||||
|
issues = [] |
||||||
|
|
||||||
|
for call in statespace.calls: |
||||||
|
|
||||||
|
if ("callvalue" in str(call.value)): |
||||||
|
logging.debug("[ETHER_SEND] Skipping refund function") |
||||||
|
continue |
||||||
|
|
||||||
|
# We're only interested in calls that send Ether |
||||||
|
|
||||||
|
if call.value.type == VarType.CONCRETE: |
||||||
|
if call.value.val == 0: |
||||||
|
continue |
||||||
|
|
||||||
|
logging.debug("[SEND_WITH_GAS]: ") |
||||||
|
|
||||||
|
# Check the CALL target |
||||||
|
|
||||||
|
if re.search(r'caller', str(call.to)): |
||||||
|
issue.description += "a non-zero amount of Ether is sent to msg.sender.\n" |
||||||
|
interesting = True |
||||||
|
|
||||||
|
if re.search(r'calldata', str(call.to)): |
||||||
|
issue.description += "a non-zero amount of Ether is sent to an address taken from function arguments.\n" |
||||||
|
interesting = True |
||||||
|
|
||||||
|
if interesting: |
||||||
|
|
||||||
|
issue = Issue("Ether send", "Warning") |
||||||
|
issue.description = "In the function '" + call.node.function_name +"' " |
||||||
|
issue.description += "Call value is " + str(call.value) + "\n" |
||||||
|
|
||||||
|
node = call.node |
||||||
|
|
||||||
|
constrained = False |
||||||
|
can_solve = True |
||||||
|
|
||||||
|
index = 0 |
||||||
|
|
||||||
|
while(can_solve and index < len(node.constraints)): |
||||||
|
|
||||||
|
constraint = node.constraints[index] |
||||||
|
index += 1 |
||||||
|
logging.debug("[ETHER_SEND] Constraint: " + str(constraint)) |
||||||
|
|
||||||
|
m = re.search(r'storage_([a-z0-9_&^]+)', str(constraint)) |
||||||
|
|
||||||
|
overwrite = False |
||||||
|
|
||||||
|
if (m): |
||||||
|
constrained = True |
||||||
|
index = m.group(1) |
||||||
|
|
||||||
|
try: |
||||||
|
|
||||||
|
for s in statespace.sstors[index]: |
||||||
|
|
||||||
|
if s.tainted: |
||||||
|
issue.description += "\nThere is a check on storage index " + str(index) + ". This storage index can be written to by calling the function '" + s.node.function_name + "'." |
||||||
|
break |
||||||
|
|
||||||
|
if not overwrite: |
||||||
|
logging.debug("[ETHER_SEND] No storage writes to index " + str(index)) |
||||||
|
can_solve = False |
||||||
|
break |
||||||
|
|
||||||
|
except KeyError: |
||||||
|
logging.debug("[ETHER_SEND] No storage writes to index " + str(index)) |
||||||
|
can_solve = False |
||||||
|
break |
||||||
|
|
||||||
|
|
||||||
|
# CALLER may also be constrained to hardcoded address. I.e. 'caller' and some integer |
||||||
|
|
||||||
|
elif (re.search(r"caller", str(constraint)) and re.search(r'[0-9]{20}', str(constraint))): |
||||||
|
can_solve = False |
||||||
|
break |
||||||
|
|
||||||
|
|
||||||
|
if not constrained: |
||||||
|
issue.description += "\nIt seems that this function can be called without restrictions." |
||||||
|
|
||||||
|
if can_solve: |
||||||
|
|
||||||
|
try: |
||||||
|
model = solver.get_model(node.constraints) |
||||||
|
logging.debug("[ETHER_SEND] MODEL: " + str(model)) |
||||||
|
issues.append(issue) |
||||||
|
|
||||||
|
for d in model.decls(): |
||||||
|
logging.debug("[ETHER_SEND] main model: %s = 0x%x" % (d.name(), model[d].as_long())) |
||||||
|
except UnsatError: |
||||||
|
logging.debug("[ETHER_SEND] no model found") |
||||||
|
|
||||||
|
return issues |
Loading…
Reference in new issue