mirror of https://github.com/ConsenSys/mythril
parent
226aecff14
commit
3d0447dbb8
@ -0,0 +1,78 @@ |
||||
from z3 import * |
||||
import re |
||||
from mythril.analysis.ops import * |
||||
from mythril.analysis.report import Issue |
||||
import logging |
||||
|
||||
|
||||
''' |
||||
MODULE DESCRIPTION: |
||||
|
||||
Check for invocations of delegatecall(msg.data) in the fallback function. |
||||
''' |
||||
|
||||
|
||||
def execute(statespace): |
||||
|
||||
logging.debug("Executing module: DELEGATECALL") |
||||
|
||||
issues = [] |
||||
visited = [] |
||||
|
||||
for call in statespace.calls: |
||||
|
||||
state = call.state |
||||
address = state.get_current_instruction()['address'] |
||||
|
||||
if (call.type == "DELEGATECALL"): |
||||
|
||||
if (call.node.function_name == "fallback"): |
||||
|
||||
stack = call.state.mstate.stack |
||||
|
||||
meminstart = get_variable(stack[-3]) |
||||
|
||||
if meminstart.type == VarType.CONCRETE: |
||||
|
||||
if (re.search(r'calldata.*_0', str(state.mstate.memory[meminstart.val]))): |
||||
|
||||
issue = Issue(call.node.contract_name, call.node.function_name, address, "CALLDATA forwarded with delegatecall()", "Informational") |
||||
|
||||
issue.description = \ |
||||
"This contract forwards its calldata via DELEGATECALL in its fallback function. " \ |
||||
"This means that any function in the called contract can be executed. Note that the callee contract will have access to the storage of the calling contract.\n" |
||||
|
||||
if (call.to.type == VarType.CONCRETE): |
||||
issue.description += ("DELEGATECALL target: " + hex(call.to.val)) |
||||
else: |
||||
issue.description += "DELEGATECALL target: " + str(call.to) |
||||
|
||||
issues.append(issue) |
||||
|
||||
if (call.to.type == VarType.SYMBOLIC): |
||||
|
||||
issue = Issue(call.node.contract_name, call.node.function_name, address, call.type + " to a user-supplied address") |
||||
|
||||
if ("calldata" in str(call.to)): |
||||
|
||||
issue.description = \ |
||||
"This contract delegates execution to a contract address obtained from calldata. " |
||||
|
||||
else: |
||||
m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to)) |
||||
|
||||
if (m): |
||||
index = m.group(1) |
||||
|
||||
func = statespace.find_storage_write(idx) |
||||
|
||||
if (func): |
||||
issue.description = "This contract delegates execution to a contract address in storage slot " + str(index) + ". This storage slot can be written to by calling the function '" + func + "'. " |
||||
|
||||
else: |
||||
logging.debug("[DELEGATECALL] No storage writes to index " + str(index)) |
||||
|
||||
issue.description += "Be aware that the called contract gets unrestricted access to this contract's state." |
||||
issues.append(issue) |
||||
|
||||
return issues |
@ -1,57 +0,0 @@ |
||||
from z3 import * |
||||
import re |
||||
from mythril.analysis.ops import * |
||||
from mythril.analysis.report import Issue |
||||
import logging |
||||
|
||||
|
||||
''' |
||||
MODULE DESCRIPTION: |
||||
|
||||
Check for invocations of delegatecall(msg.data) in the fallback function. |
||||
''' |
||||
|
||||
|
||||
def execute(statespace): |
||||
|
||||
logging.debug("Executing module: DELEGATECALL_FORWARD") |
||||
|
||||
issues = [] |
||||
visited = [] |
||||
|
||||
for call in statespace.calls: |
||||
|
||||
state = call.state |
||||
address = state.get_current_instruction()['address'] |
||||
|
||||
# Only needs to be checked once per call instructions (essentially just static analysis) |
||||
|
||||
if address in visited: |
||||
continue |
||||
else: |
||||
visited.append(address) |
||||
|
||||
if (call.type == "DELEGATECALL") and (call.node.function_name == "fallback"): |
||||
|
||||
stack = call.state.mstate.stack |
||||
|
||||
meminstart = get_variable(stack[-3]) |
||||
|
||||
if meminstart.type == VarType.CONCRETE: |
||||
|
||||
if (re.search(r'calldata.*_0', str(state.mstate.memory[meminstart.val]))): |
||||
|
||||
issue = Issue(call.node.contract_name, call.node.function_name, address, "CALLDATA forwarded with delegatecall()", "Informational") |
||||
|
||||
issue.description = \ |
||||
"This contract forwards its calldata via DELEGATECALL in its fallback function. " \ |
||||
"This means that any function in the called contract can be executed. Note that the callee contract will have access to the storage of the calling contract.\n" |
||||
|
||||
if (call.to.type == VarType.CONCRETE): |
||||
issue.description += ("DELEGATECALL target: " + hex(call.to.val)) |
||||
else: |
||||
issue.description += "DELEGATECALL target: " + str(call.to) |
||||
|
||||
issues.append(issue) |
||||
|
||||
return issues |
@ -1,71 +0,0 @@ |
||||
from z3 import * |
||||
from mythril.analysis.ops import * |
||||
from mythril.analysis.report import Issue |
||||
import re |
||||
import logging |
||||
|
||||
|
||||
''' |
||||
MODULE DESCRIPTION: |
||||
|
||||
Check for invocations of delegatecall/callcode to a user-supplied address |
||||
''' |
||||
|
||||
|
||||
def execute(statespace): |
||||
|
||||
logging.debug("Executing module: DELEGATECALL_TO_DYNAMIC") |
||||
|
||||
issues = [] |
||||
|
||||
for call in statespace.calls: |
||||
|
||||
state = call.state |
||||
address = state.get_current_instruction()['address'] |
||||
|
||||
if (call.type == "DELEGATECALL" or call.type == "CALLCODE"): |
||||
|
||||
if (call.to.type == VarType.SYMBOLIC): |
||||
|
||||
if ("calldata" in str(call.to)): |
||||
issue = Issue(call.node.contract_name, call.node.function_name, address, call.type + " to dynamic address") |
||||
|
||||
issue.description = \ |
||||
"The function " + call.node.function_name + " delegates execution to a contract address obtained from calldata.\n" \ |
||||
"Recipient address: " + str(call.to) |
||||
|
||||
issues.append(issue) |
||||
else: |
||||
m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to)) |
||||
|
||||
if (m): |
||||
index = m.group(1) |
||||
logging.debug("DELEGATECALL to contract address in storage") |
||||
|
||||
try: |
||||
|
||||
for s in statespace.sstors[index]: |
||||
|
||||
if s.tainted: |
||||
issue = Issue(call.type + " to dynamic address in storage", "Warning") |
||||
issue.description = \ |
||||
"The function " + call.node.function_name + " in contract '" + call.node.contract_name + " delegates execution to a contract address stored in a state variable. " \ |
||||
"There is a check on storage index " + str(index) + ". This storage index can be written to by calling the function '" + s.node.function_name + "'.\n" \ |
||||
"Make sure that the contract address cannot be set by untrusted users." |
||||
issues.append(issue) |
||||
break |
||||
|
||||
except KeyError: |
||||
logging.debug("[ETHER_SEND] No storage writes to index " + str(index)) |
||||
|
||||
else: |
||||
|
||||
issue = Issue(call.node.contract_name, call.node.function_name, address, "DELEGATECALL to dynamic address", "Informational") |
||||
|
||||
issue.description = \ |
||||
"The function " + call.node.function_name + " in contract '" + call.node.contract_name + " delegates execution to a contract with a dynamic address." \ |
||||
"To address:" + str(call.to) |
||||
|
||||
issues.append(issue) |
||||
|
||||
return issues |
Loading…
Reference in new issue