mirror of https://github.com/ConsenSys/mythril
commit
6128931242
@ -1,2 +1,5 @@ |
|||||||
tests/testdata/* linguist-detectable=false |
tests/testdata/* linguist-detectable=false |
||||||
static/* linguist-documentation |
static/* linguist-documentation |
||||||
|
|
||||||
|
# Solidity |
||||||
|
*.sol linguist-language=Solidity |
||||||
|
@ -1,2 +1,2 @@ |
|||||||
include mythril/disassembler/signatures.json |
include mythril/disassembler/signatures.db |
||||||
include mythril/analysis/templates/* |
include mythril/analysis/templates/* |
||||||
|
@ -1,47 +0,0 @@ |
|||||||
import re |
|
||||||
from typing import List |
|
||||||
from z3 import * |
|
||||||
from mythril.laser.ethereum.transaction import ContractCreationTransaction |
|
||||||
from mythril.laser.ethereum.state.global_state import GlobalState |
|
||||||
|
|
||||||
|
|
||||||
def get_non_creator_constraints(state: GlobalState) -> (List, bool): |
|
||||||
""" |
|
||||||
Get constraints which say that the caller isn't the creator of the contract |
|
||||||
:param state: The state |
|
||||||
:return: tuple of (constraints, bool) where the bool says whether the caller is constrained or not |
|
||||||
""" |
|
||||||
not_creator_constraints = [] |
|
||||||
creator = None |
|
||||||
if isinstance( |
|
||||||
state.world_state.transaction_sequence[0], ContractCreationTransaction |
|
||||||
): |
|
||||||
creator = state.world_state.transaction_sequence[0].caller |
|
||||||
if creator is not None: |
|
||||||
for transaction in state.world_state.transaction_sequence[1:]: |
|
||||||
not_creator_constraints.append( |
|
||||||
Not(Extract(159, 0, transaction.caller) == Extract(159, 0, creator)) |
|
||||||
) |
|
||||||
not_creator_constraints.append( |
|
||||||
Not(Extract(159, 0, transaction.caller) == 0) |
|
||||||
) |
|
||||||
else: |
|
||||||
for transaction in state.world_state.transaction_sequence: |
|
||||||
not_creator_constraints.append( |
|
||||||
Not(Extract(159, 0, transaction.caller) == 0) |
|
||||||
) |
|
||||||
if not has_caller_check_constraint(state.mstate.constraints): |
|
||||||
return [], True |
|
||||||
return not_creator_constraints, False |
|
||||||
|
|
||||||
|
|
||||||
def has_caller_check_constraint(constraints: List) -> bool: |
|
||||||
""" |
|
||||||
Checks whether the caller is constrained to a value or not |
|
||||||
""" |
|
||||||
for constraint in constraints: |
|
||||||
if re.search(r"caller", str(constraint)) and re.search( |
|
||||||
r"[0-9]{20}", str(constraint) |
|
||||||
): |
|
||||||
return False |
|
||||||
return True |
|
@ -1,218 +1,111 @@ |
|||||||
from z3 import * |
from z3 import * |
||||||
from mythril.analysis.ops import * |
|
||||||
from mythril.analysis.report import Issue |
from mythril.analysis.report import Issue |
||||||
from mythril.analysis import solver |
from mythril.analysis import solver |
||||||
from mythril.analysis.swc_data import REENTRANCY |
from mythril.analysis.swc_data import REENTRANCY |
||||||
from mythril.analysis.modules.base import DetectionModule |
from mythril.analysis.modules.base import DetectionModule |
||||||
import re |
from mythril.laser.ethereum.state.global_state import GlobalState |
||||||
|
from mythril.exceptions import UnsatError |
||||||
import logging |
import logging |
||||||
from mythril.laser.ethereum.cfg import JumpType |
|
||||||
|
|
||||||
|
DESCRIPTION = """ |
||||||
|
|
||||||
class ExternalCallModule(DetectionModule): |
Search for low level calls (e.g. call.value()) that forward all gas to the callee. |
||||||
def __init__(self, max_search_depth=64): |
Report a warning if the callee address can be set by the sender, otherwise create |
||||||
super().__init__( |
an informational issue. |
||||||
name="External Calls", |
|
||||||
swc_id=REENTRANCY, |
|
||||||
hooks=["CALL"], |
|
||||||
description="Check for call.value()() to external addresses", |
|
||||||
) |
|
||||||
self.max_search_depth = max_search_depth |
|
||||||
self.calls_visited = [] |
|
||||||
|
|
||||||
def search_children( |
""" |
||||||
self, statespace, node, transaction_id, start_index=0, depth=0, results=None |
|
||||||
): |
|
||||||
if results is None: |
|
||||||
results = [] |
|
||||||
logging.debug("SEARCHING NODE %d", node.uid) |
|
||||||
|
|
||||||
if depth < self.max_search_depth: |
|
||||||
|
|
||||||
n_states = len(node.states) |
def _analyze_state(state): |
||||||
|
|
||||||
if n_states > start_index: |
|
||||||
|
|
||||||
for j in range(start_index, n_states): |
|
||||||
if ( |
|
||||||
node.states[j].get_current_instruction()["opcode"] == "SSTORE" |
|
||||||
and node.states[j].current_transaction.id == transaction_id |
|
||||||
): |
|
||||||
results.append( |
|
||||||
node.states[j].get_current_instruction()["address"] |
|
||||||
) |
|
||||||
children = [] |
|
||||||
|
|
||||||
for edge in statespace.edges: |
|
||||||
if edge.node_from == node.uid and edge.type != JumpType.Transaction: |
|
||||||
children.append(statespace.nodes[edge.node_to]) |
|
||||||
|
|
||||||
if len(children): |
|
||||||
for node in children: |
|
||||||
results += self.search_children( |
|
||||||
statespace, |
|
||||||
node, |
|
||||||
transaction_id, |
|
||||||
depth=depth + 1, |
|
||||||
results=results, |
|
||||||
) |
|
||||||
|
|
||||||
return results |
node = state.node |
||||||
|
gas = state.mstate.stack[-1] |
||||||
|
to = state.mstate.stack[-2] |
||||||
|
|
||||||
def execute(self, statespace): |
|
||||||
|
|
||||||
issues = [] |
|
||||||
|
|
||||||
for call in statespace.calls: |
|
||||||
|
|
||||||
state = call.state |
|
||||||
address = state.get_current_instruction()["address"] |
address = state.get_current_instruction()["address"] |
||||||
|
|
||||||
if call.type == "CALL": |
try: |
||||||
|
constraints = node.constraints |
||||||
logging.debug( |
transaction_sequence = solver.get_transaction_sequence( |
||||||
"[EXTERNAL_CALLS] Call to: %s, value = %s, gas = %s" |
state, constraints + [UGT(gas, 2300)] |
||||||
% (str(call.to), str(call.value), str(call.gas)) |
|
||||||
) |
|
||||||
|
|
||||||
if ( |
|
||||||
call.to.type == VarType.SYMBOLIC |
|
||||||
and (call.gas.type == VarType.CONCRETE and call.gas.val > 2300) |
|
||||||
or ( |
|
||||||
call.gas.type == VarType.SYMBOLIC |
|
||||||
and "2300" not in str(call.gas) |
|
||||||
) |
) |
||||||
): |
|
||||||
|
|
||||||
description = "This contract executes a message call to " |
# Check whether we can also set the callee address |
||||||
|
|
||||||
target = str(call.to) |
try: |
||||||
user_supplied = False |
constraints += [to == 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF] |
||||||
|
transaction_sequence = solver.get_transaction_sequence(state, constraints) |
||||||
|
|
||||||
if "calldata" in target or "caller" in target: |
debug = str(transaction_sequence) |
||||||
|
description = ( |
||||||
if "calldata" in target: |
"The contract executes a function call with high gas to a user-supplied address. " |
||||||
description += ( |
"Note that the callee can contain arbitrary code and may re-enter any function in this contract. " |
||||||
"an address provided as a function argument. " |
"Review the business logic carefully to prevent unanticipated effects on the contract state." |
||||||
) |
|
||||||
else: |
|
||||||
description += "the address of the transaction sender. " |
|
||||||
|
|
||||||
user_supplied = True |
|
||||||
else: |
|
||||||
m = re.search(r"storage_([a-z0-9_&^]+)", str(call.to)) |
|
||||||
|
|
||||||
if m: |
|
||||||
idx = m.group(1) |
|
||||||
|
|
||||||
func = statespace.find_storage_write( |
|
||||||
state.environment.active_account.address, idx |
|
||||||
) |
|
||||||
|
|
||||||
if func: |
|
||||||
|
|
||||||
description += ( |
|
||||||
"an address found at storage slot " |
|
||||||
+ str(idx) |
|
||||||
+ ". " |
|
||||||
+ "This storage slot can be written to by calling the function `" |
|
||||||
+ func |
|
||||||
+ "`. " |
|
||||||
) |
|
||||||
user_supplied = True |
|
||||||
|
|
||||||
if user_supplied: |
|
||||||
|
|
||||||
description += ( |
|
||||||
"Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. " |
|
||||||
"Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state." |
|
||||||
) |
) |
||||||
|
|
||||||
issue = Issue( |
issue = Issue( |
||||||
contract=call.node.contract_name, |
contract=node.contract_name, |
||||||
function_name=call.node.function_name, |
function_name=node.function_name, |
||||||
address=address, |
address=address, |
||||||
title="Message call to external contract", |
swc_id=REENTRANCY, |
||||||
|
title="External call to user-supplied address", |
||||||
_type="Warning", |
_type="Warning", |
||||||
description=description, |
|
||||||
bytecode=state.environment.code.bytecode, |
bytecode=state.environment.code.bytecode, |
||||||
swc_id=REENTRANCY, |
|
||||||
gas_used=( |
|
||||||
state.mstate.min_gas_used, |
|
||||||
state.mstate.max_gas_used, |
|
||||||
), |
|
||||||
) |
|
||||||
|
|
||||||
else: |
|
||||||
|
|
||||||
description += "to another contract. Make sure that the called contract is trusted and does not execute user-supplied code." |
|
||||||
|
|
||||||
issue = Issue( |
|
||||||
contract=call.node.contract_name, |
|
||||||
function_name=call.node.function_name, |
|
||||||
address=address, |
|
||||||
title="Message call to external contract", |
|
||||||
_type="Informational", |
|
||||||
description=description, |
description=description, |
||||||
bytecode=state.environment.code.bytecode, |
debug=debug, |
||||||
swc_id=REENTRANCY, |
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) |
except UnsatError: |
||||||
|
|
||||||
if address not in self.calls_visited: |
|
||||||
self.calls_visited.append(address) |
|
||||||
|
|
||||||
logging.debug( |
logging.debug( |
||||||
"[EXTERNAL_CALLS] Checking for state changes starting from " |
"[EXTERNAL_CALLS] Callee address cannot be modified. Reporting informational issue." |
||||||
+ call.node.function_name |
|
||||||
) |
) |
||||||
|
|
||||||
# Check for SSTORE in remaining instructions in current node & nodes down the CFG |
debug = str(transaction_sequence) |
||||||
|
|
||||||
state_change_addresses = self.search_children( |
|
||||||
statespace, |
|
||||||
call.node, |
|
||||||
call.state.current_transaction.id, |
|
||||||
call.state_index + 1, |
|
||||||
depth=0, |
|
||||||
results=[], |
|
||||||
) |
|
||||||
|
|
||||||
logging.debug( |
|
||||||
"[EXTERNAL_CALLS] Detected state changes at addresses: " |
|
||||||
+ str(state_change_addresses) |
|
||||||
) |
|
||||||
|
|
||||||
if len(state_change_addresses): |
|
||||||
for address in state_change_addresses: |
|
||||||
description = ( |
description = ( |
||||||
"The contract account state is changed after an external call. " |
"The contract executes a function call to an external address. " |
||||||
"Consider that the called contract could re-enter the function before this " |
"Verify that the code at this address is trusted and immutable." |
||||||
"state change takes place. This can lead to business logic vulnerabilities." |
|
||||||
) |
) |
||||||
|
|
||||||
issue = Issue( |
issue = Issue( |
||||||
contract=call.node.contract_name, |
contract=node.contract_name, |
||||||
function_name=call.node.function_name, |
function_name=state.node.function_name, |
||||||
address=address, |
address=address, |
||||||
title="State change after external call", |
swc_id=REENTRANCY, |
||||||
_type="Warning", |
title="External call", |
||||||
description=description, |
_type="Informational", |
||||||
bytecode=state.environment.code.bytecode, |
bytecode=state.environment.code.bytecode, |
||||||
|
description=description, |
||||||
|
debug=debug, |
||||||
|
gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used), |
||||||
|
) |
||||||
|
|
||||||
|
except UnsatError: |
||||||
|
logging.debug("[EXTERNAL_CALLS] No model found.") |
||||||
|
return [] |
||||||
|
|
||||||
|
return [issue] |
||||||
|
|
||||||
|
|
||||||
|
class ExternalCalls(DetectionModule): |
||||||
|
def __init__(self): |
||||||
|
super().__init__( |
||||||
|
name="External calls", |
||||||
swc_id=REENTRANCY, |
swc_id=REENTRANCY, |
||||||
gas_used=( |
hooks=["CALL"], |
||||||
state.mstate.min_gas_used, |
description=(DESCRIPTION), |
||||||
state.mstate.max_gas_used, |
entrypoint="callback", |
||||||
), |
|
||||||
) |
) |
||||||
issues.append(issue) |
self._issues = [] |
||||||
|
|
||||||
|
def execute(self, state: GlobalState): |
||||||
|
self._issues.extend(_analyze_state(state)) |
||||||
|
return self.issues |
||||||
|
|
||||||
return issues |
@property |
||||||
|
def issues(self): |
||||||
|
return self._issues |
||||||
|
|
||||||
|
|
||||||
detector = ExternalCallModule() |
detector = ExternalCalls() |
||||||
|
@ -1,3 +0,0 @@ |
|||||||
import time |
|
||||||
|
|
||||||
start_time = time.time() |
|
@ -1,65 +0,0 @@ |
|||||||
from ethereum import vm, messages, transactions |
|
||||||
from ethereum.state import State |
|
||||||
from ethereum.slogging import get_logger |
|
||||||
from mythril.ether import util |
|
||||||
from logging import StreamHandler |
|
||||||
from io import StringIO |
|
||||||
import re |
|
||||||
|
|
||||||
|
|
||||||
def trace(code, calldata=""): |
|
||||||
log_handlers = [ |
|
||||||
"eth.vm.op", |
|
||||||
"eth.vm.op.stack", |
|
||||||
"eth.vm.op.memory", |
|
||||||
"eth.vm.op.storage", |
|
||||||
] |
|
||||||
output = StringIO() |
|
||||||
stream_handler = StreamHandler(output) |
|
||||||
|
|
||||||
for handler in log_handlers: |
|
||||||
log_vm_op = get_logger(handler) |
|
||||||
log_vm_op.setLevel("TRACE") |
|
||||||
log_vm_op.addHandler(stream_handler) |
|
||||||
|
|
||||||
addr = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF01234567") |
|
||||||
state = State() |
|
||||||
|
|
||||||
ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr, 0, addr)) |
|
||||||
message = vm.Message(addr, addr, 0, 21000, calldata) |
|
||||||
vm.vm_execute(ext, message, util.safe_decode(code)) |
|
||||||
stream_handler.flush() |
|
||||||
ret = output.getvalue() |
|
||||||
lines = ret.split("\n") |
|
||||||
|
|
||||||
state_trace = [] |
|
||||||
for line in lines: |
|
||||||
m = re.search(r"pc=b\'(\d+)\'.*op=([A-Z0-9]+)", line) |
|
||||||
if m: |
|
||||||
pc = m.group(1) |
|
||||||
op = m.group(2) |
|
||||||
m = re.match(r".*stack=(\[.*?\])", line) |
|
||||||
|
|
||||||
if m: |
|
||||||
stackitems = re.findall(r"b\'(\d+)\'", m.group(1)) |
|
||||||
stack = "[" |
|
||||||
|
|
||||||
if len(stackitems): |
|
||||||
for i in range(0, len(stackitems) - 1): |
|
||||||
stack += hex(int(stackitems[i])) + ", " |
|
||||||
stack += hex(int(stackitems[-1])) |
|
||||||
|
|
||||||
stack += "]" |
|
||||||
else: |
|
||||||
stack = "[]" |
|
||||||
|
|
||||||
if re.match(r"^PUSH.*", op): |
|
||||||
val = re.search(r"pushvalue=(\d+)", line).group(1) |
|
||||||
pushvalue = hex(int(val)) |
|
||||||
state_trace.append( |
|
||||||
{"pc": pc, "op": op, "stack": stack, "pushvalue": pushvalue} |
|
||||||
) |
|
||||||
else: |
|
||||||
state_trace.append({"pc": pc, "op": op, "stack": stack}) |
|
||||||
|
|
||||||
return state_trace |
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,15 @@ |
|||||||
|
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract HashForEther { |
contract HashForEther { |
||||||
|
|
||||||
function withdrawWinnings() { |
function withdrawWinnings() public { |
||||||
// Winner if the last 8 hex characters of the address are 0. |
// Winner if the last 8 hex characters of the address are 0. |
||||||
require(uint32(msg.sender) == 0); |
require(uint32(msg.sender) == 0); |
||||||
_sendWinnings(); |
_sendWinnings(); |
||||||
} |
} |
||||||
|
|
||||||
function _sendWinnings() { |
function _sendWinnings() public { |
||||||
msg.sender.transfer(this.balance); |
msg.sender.transfer(address(this).balance); |
||||||
} |
} |
||||||
} |
} |
@ -1,13 +1,17 @@ |
|||||||
|
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract ReturnValue { |
contract ReturnValue { |
||||||
|
|
||||||
address callee = 0xE0F7e56e62b4267062172495D7506087205A4229; |
address public callee = 0xE0f7e56E62b4267062172495D7506087205A4229; |
||||||
|
|
||||||
function callnotchecked() { |
function callnotchecked() public { |
||||||
callee.call(); |
callee.call(""); |
||||||
} |
} |
||||||
|
|
||||||
function callchecked() { |
function callchecked() public { |
||||||
require(callee.call()); |
(bool success, bytes memory data) = callee.call(""); |
||||||
|
require(success); |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
@ -1,6 +1,9 @@ |
|||||||
|
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract Suicide { |
contract Suicide { |
||||||
|
|
||||||
function kill(address addr) { |
function kill(address payable addr) public { |
||||||
selfdestruct(addr); |
selfdestruct(addr); |
||||||
} |
} |
||||||
|
|
||||||
|
@ -1,268 +0,0 @@ |
|||||||
from mythril.analysis.modules.delegatecall import detector |
|
||||||
from mythril.analysis.ops import Call, Variable, VarType |
|
||||||
from mythril.analysis.symbolic import SymExecWrapper |
|
||||||
from mythril.laser.ethereum.cfg import Node |
|
||||||
from mythril.laser.ethereum.state.environment import Environment |
|
||||||
from mythril.laser.ethereum.state.account import Account |
|
||||||
from mythril.laser.ethereum.state.global_state import GlobalState |
|
||||||
import pytest |
|
||||||
from unittest.mock import MagicMock, patch |
|
||||||
import pytest_mock |
|
||||||
from mythril.disassembler.disassembly import Disassembly |
|
||||||
|
|
||||||
|
|
||||||
def test_concrete_call(): |
|
||||||
# arrange |
|
||||||
address = "0x10" |
|
||||||
active_account = Account(address) |
|
||||||
active_account.code = Disassembly("00") |
|
||||||
environment = Environment(active_account, None, None, None, None, None) |
|
||||||
|
|
||||||
state = GlobalState(None, environment, None) |
|
||||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
|
||||||
|
|
||||||
node = Node("example") |
|
||||||
node.contract_name = "the contract name" |
|
||||||
node.function_name = "the function name" |
|
||||||
|
|
||||||
to = Variable(1, VarType.CONCRETE) |
|
||||||
meminstart = Variable(1, VarType.CONCRETE) |
|
||||||
call = Call(node, state, None, None, to, None) |
|
||||||
|
|
||||||
# act |
|
||||||
issues = detector._concrete_call(call, state, address, meminstart) |
|
||||||
|
|
||||||
# assert |
|
||||||
issue = issues[0] |
|
||||||
assert issue.address == address |
|
||||||
assert issue.contract == node.contract_name |
|
||||||
assert issue.function == node.function_name |
|
||||||
assert issue.title == "Call data forwarded with delegatecall()" |
|
||||||
assert issue.type == "Informational" |
|
||||||
assert ( |
|
||||||
issue.description |
|
||||||
== "This contract forwards its call data 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.\nDELEGATECALL target: 0x1" |
|
||||||
) |
|
||||||
|
|
||||||
|
|
||||||
def test_concrete_call_symbolic_to(): |
|
||||||
# arrange |
|
||||||
address = "0x10" |
|
||||||
|
|
||||||
active_account = Account(address) |
|
||||||
active_account.code = Disassembly("00") |
|
||||||
environment = Environment(active_account, None, None, None, None, None) |
|
||||||
state = GlobalState(None, environment, None) |
|
||||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
|
||||||
|
|
||||||
node = Node("example") |
|
||||||
node.contract_name = "the contract name" |
|
||||||
node.function_name = "the function name" |
|
||||||
|
|
||||||
to = Variable("calldata_3", VarType.SYMBOLIC) |
|
||||||
meminstart = Variable(1, VarType.CONCRETE) |
|
||||||
call = Call(node, state, None, None, to, None) |
|
||||||
|
|
||||||
# act |
|
||||||
issues = detector._concrete_call(call, state, address, meminstart) |
|
||||||
|
|
||||||
# assert |
|
||||||
issue = issues[0] |
|
||||||
assert issue.address == address |
|
||||||
assert issue.contract == node.contract_name |
|
||||||
assert issue.function == node.function_name |
|
||||||
assert issue.title == "Call data forwarded with delegatecall()" |
|
||||||
assert issue.type == "Informational" |
|
||||||
assert issue.description == ( |
|
||||||
"This contract forwards its call data 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.\nDELEGATECALL target: calldata_3" |
|
||||||
) |
|
||||||
|
|
||||||
|
|
||||||
def test_concrete_call_not_calldata(): |
|
||||||
# arrange |
|
||||||
state = GlobalState(None, None, None) |
|
||||||
state.mstate.memory = ["placeholder", "not_calldata"] |
|
||||||
meminstart = Variable(1, VarType.CONCRETE) |
|
||||||
|
|
||||||
# act |
|
||||||
issues = detector._concrete_call(None, state, None, meminstart) |
|
||||||
|
|
||||||
# assert |
|
||||||
assert issues == [] |
|
||||||
|
|
||||||
|
|
||||||
def test_symbolic_call_storage_to(mocker): |
|
||||||
# arrange |
|
||||||
address = "0x10" |
|
||||||
|
|
||||||
active_account = Account(address) |
|
||||||
active_account.code = Disassembly("00") |
|
||||||
environment = Environment(active_account, None, None, None, None, None) |
|
||||||
state = GlobalState(None, environment, None) |
|
||||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
|
||||||
|
|
||||||
node = Node("example") |
|
||||||
node.contract_name = "the contract name" |
|
||||||
node.function_name = "the function name" |
|
||||||
|
|
||||||
to = Variable("storage_1", VarType.SYMBOLIC) |
|
||||||
call = Call(node, state, None, "Type: ", to, None) |
|
||||||
|
|
||||||
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None) |
|
||||||
statespace = SymExecWrapper(1) |
|
||||||
|
|
||||||
mocker.patch.object(statespace, "find_storage_write") |
|
||||||
statespace.find_storage_write.return_value = "Function name" |
|
||||||
|
|
||||||
# act |
|
||||||
issues = detector._symbolic_call(call, state, address, statespace) |
|
||||||
|
|
||||||
# assert |
|
||||||
issue = issues[0] |
|
||||||
assert issue.address == address |
|
||||||
assert issue.contract == node.contract_name |
|
||||||
assert issue.function == node.function_name |
|
||||||
assert issue.title == "Type: to a user-supplied address" |
|
||||||
assert issue.type == "Informational" |
|
||||||
assert issue.description == ( |
|
||||||
"This contract delegates execution to a contract address in storage slot 1." |
|
||||||
" This storage slot can be written to by calling the function `Function name`." |
|
||||||
" Be aware that the called contract gets unrestricted access to this contract's state." |
|
||||||
) |
|
||||||
|
|
||||||
|
|
||||||
def test_symbolic_call_calldata_to(mocker): |
|
||||||
# arrange |
|
||||||
address = "0x10" |
|
||||||
|
|
||||||
active_account = Account(address) |
|
||||||
active_account.code = Disassembly("00") |
|
||||||
environment = Environment(active_account, None, None, None, None, None) |
|
||||||
state = GlobalState(None, environment, None) |
|
||||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
|
||||||
|
|
||||||
node = Node("example") |
|
||||||
node.contract_name = "the contract name" |
|
||||||
node.function_name = "the function name" |
|
||||||
|
|
||||||
to = Variable("calldata", VarType.SYMBOLIC) |
|
||||||
call = Call(node, state, None, "Type: ", to, None) |
|
||||||
|
|
||||||
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None) |
|
||||||
statespace = SymExecWrapper(1) |
|
||||||
|
|
||||||
mocker.patch.object(statespace, "find_storage_write") |
|
||||||
statespace.find_storage_write.return_value = "Function name" |
|
||||||
|
|
||||||
# act |
|
||||||
issues = detector._symbolic_call(call, state, address, statespace) |
|
||||||
|
|
||||||
# assert |
|
||||||
issue = issues[0] |
|
||||||
assert issue.address == address |
|
||||||
assert issue.contract == node.contract_name |
|
||||||
assert issue.function == node.function_name |
|
||||||
assert issue.title == "Type: to a user-supplied address" |
|
||||||
assert issue.type == "Informational" |
|
||||||
assert issue.description == ( |
|
||||||
"This contract delegates execution to a contract address obtained from calldata." |
|
||||||
" Be aware that the called contract gets unrestricted access to this contract's state." |
|
||||||
) |
|
||||||
|
|
||||||
|
|
||||||
@patch("mythril.laser.ethereum.state.global_state.GlobalState.get_current_instruction") |
|
||||||
@patch("mythril.analysis.modules.delegatecall.detector._concrete_call") |
|
||||||
@patch("mythril.analysis.modules.delegatecall.detector._symbolic_call") |
|
||||||
def test_delegate_call(sym_mock, concrete_mock, curr_instruction): |
|
||||||
# arrange |
|
||||||
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call") |
|
||||||
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call") |
|
||||||
sym_mock.return_value = [] |
|
||||||
concrete_mock.return_value = [] |
|
||||||
curr_instruction.return_value = {"address": "0x10"} |
|
||||||
|
|
||||||
active_account = Account("0x10") |
|
||||||
active_account.code = Disassembly("00") |
|
||||||
|
|
||||||
environment = Environment(active_account, None, None, None, None, None) |
|
||||||
state = GlobalState(None, environment, Node) |
|
||||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
|
||||||
state.mstate.stack = [1, 2, 3] |
|
||||||
assert state.get_current_instruction() == {"address": "0x10"} |
|
||||||
|
|
||||||
node = Node("example") |
|
||||||
node.contract_name = "the contract name" |
|
||||||
node.function_name = "fallback" |
|
||||||
|
|
||||||
to = Variable("storage_1", VarType.SYMBOLIC) |
|
||||||
call = Call(node, state, None, "DELEGATECALL", to, None) |
|
||||||
|
|
||||||
statespace = MagicMock() |
|
||||||
statespace.calls = [call] |
|
||||||
|
|
||||||
# act |
|
||||||
detector.execute(statespace) |
|
||||||
|
|
||||||
# assert |
|
||||||
assert concrete_mock.call_count == 1 |
|
||||||
assert sym_mock.call_count == 1 |
|
||||||
|
|
||||||
|
|
||||||
@patch("mythril.analysis.modules.delegatecall.detector._concrete_call") |
|
||||||
@patch("mythril.analysis.modules.delegatecall.detector._symbolic_call") |
|
||||||
def test_delegate_call_not_delegate(sym_mock, concrete_mock): |
|
||||||
# arrange |
|
||||||
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call") |
|
||||||
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call") |
|
||||||
sym_mock.return_value = [] |
|
||||||
concrete_mock.return_value = [] |
|
||||||
|
|
||||||
node = Node("example") |
|
||||||
node.function_name = "fallback" |
|
||||||
|
|
||||||
to = Variable("storage_1", VarType.SYMBOLIC) |
|
||||||
call = Call(node, None, None, "NOT_DELEGATECALL", to, None) |
|
||||||
|
|
||||||
statespace = MagicMock() |
|
||||||
statespace.calls = [call] |
|
||||||
|
|
||||||
# act |
|
||||||
issues = detector.execute(statespace) |
|
||||||
|
|
||||||
# assert |
|
||||||
assert issues == [] |
|
||||||
assert concrete_mock.call_count == 0 |
|
||||||
assert sym_mock.call_count == 0 |
|
||||||
|
|
||||||
|
|
||||||
@patch("mythril.analysis.modules.delegatecall.detector._concrete_call") |
|
||||||
@patch("mythril.analysis.modules.delegatecall.detector._symbolic_call") |
|
||||||
def test_delegate_call_not_fallback(sym_mock, concrete_mock): |
|
||||||
# arrange |
|
||||||
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call") |
|
||||||
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call") |
|
||||||
sym_mock.return_value = [] |
|
||||||
concrete_mock.return_value = [] |
|
||||||
|
|
||||||
node = Node("example") |
|
||||||
node.function_name = "not_fallback" |
|
||||||
|
|
||||||
to = Variable("storage_1", VarType.SYMBOLIC) |
|
||||||
call = Call(node, None, None, "DELEGATECALL", to, None) |
|
||||||
|
|
||||||
statespace = MagicMock() |
|
||||||
statespace.calls = [call] |
|
||||||
|
|
||||||
# act |
|
||||||
issues = detector.execute(statespace) |
|
||||||
|
|
||||||
# assert |
|
||||||
assert issues == [] |
|
||||||
assert concrete_mock.call_count == 0 |
|
||||||
assert sym_mock.call_count == 0 |
|
@ -1,41 +1,42 @@ |
|||||||
import unittest |
from mythril.ethereum.evmcontract import EVMContract |
||||||
from mythril.ether.ethcontract import ETHContract |
from tests import BaseTestCase |
||||||
|
|
||||||
|
|
||||||
class ETHContractTestCase(unittest.TestCase): |
class EVMContractTestCase(BaseTestCase): |
||||||
def setUp(self): |
def setUp(self): |
||||||
|
super().setUp() |
||||||
self.code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" |
self.code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" |
||||||
self.creation_code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" |
self.creation_code = "0x60606040525b603c5b60006010603e565b9050593681016040523660008237602060003683856040603f5a0204f41560545760206000f35bfe5b50565b005b73c3b2ae46792547a96b9f84405e36d0e07edcd05c5b905600a165627a7a7230582062a884f947232ada573f95940cce9c8bfb7e4e14e21df5af4e884941afb55e590029" |
||||||
|
|
||||||
|
|
||||||
class Getinstruction_listTestCase(ETHContractTestCase): |
class Getinstruction_listTestCase(EVMContractTestCase): |
||||||
def runTest(self): |
def runTest(self): |
||||||
contract = ETHContract(self.code, self.creation_code) |
contract = EVMContract(self.code, self.creation_code) |
||||||
|
|
||||||
disassembly = contract.disassembly |
disassembly = contract.disassembly |
||||||
|
|
||||||
self.assertEqual( |
self.assertEqual( |
||||||
len(disassembly.instruction_list), |
len(disassembly.instruction_list), |
||||||
53, |
53, |
||||||
"Error disassembling code using ETHContract.get_instruction_list()", |
"Error disassembling code using EVMContract.get_instruction_list()", |
||||||
) |
) |
||||||
|
|
||||||
|
|
||||||
class GetEASMTestCase(ETHContractTestCase): |
class GetEASMTestCase(EVMContractTestCase): |
||||||
def runTest(self): |
def runTest(self): |
||||||
contract = ETHContract(self.code) |
contract = EVMContract(self.code) |
||||||
|
|
||||||
instruction_list = contract.get_easm() |
instruction_list = contract.get_easm() |
||||||
|
|
||||||
self.assertTrue( |
self.assertTrue( |
||||||
"PUSH1 0x60" in instruction_list, |
"PUSH1 0x60" in instruction_list, |
||||||
"Error obtaining EASM code through ETHContract.get_easm()", |
"Error obtaining EASM code through EVMContract.get_easm()", |
||||||
) |
) |
||||||
|
|
||||||
|
|
||||||
class MatchesExpressionTestCase(ETHContractTestCase): |
class MatchesExpressionTestCase(EVMContractTestCase): |
||||||
def runTest(self): |
def runTest(self): |
||||||
contract = ETHContract(self.code) |
contract = EVMContract(self.code) |
||||||
|
|
||||||
self.assertTrue( |
self.assertTrue( |
||||||
contract.matches_expression("code#PUSH1# or code#PUSH1#"), |
contract.matches_expression("code#PUSH1# or code#PUSH1#"), |
@ -0,0 +1,4 @@ |
|||||||
|
[defaults] |
||||||
|
leveldb_dir = /Users/bernhardmueller/Library/Ethereum/geth/chaindata |
||||||
|
dynamic_loading = infura |
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@ |
|||||||
pragma solidity ^0.4.24; |
pragma solidity 0.5.0; |
||||||
|
|
||||||
contract AssertFail { |
|
||||||
|
|
||||||
constructor(uint8 var1){ |
contract AssertFail { |
||||||
|
constructor(uint8 var1) public { |
||||||
assert(var1 > 0); |
assert(var1 > 0); |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,16 +1,19 @@ |
|||||||
|
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract D { |
contract D { |
||||||
uint public n; |
uint public n; |
||||||
address public sender; |
address public sender; |
||||||
|
|
||||||
function callSetN(address _e, uint _n) { |
function callSetN(address _e, uint _n) public { |
||||||
_e.call(bytes4(sha3("setN(uint256)")), _n); |
_e.call(abi.encode(bytes4(keccak256("setN(uint256)")), _n)); |
||||||
} |
} |
||||||
|
|
||||||
function callcodeSetN(address _e, uint _n) { |
function callcodeSetN(address _e, uint _n) public view { |
||||||
_e.callcode(bytes4(sha3("setN(uint256)")), _n); |
_e.staticcall(abi.encode(bytes4(keccak256("setN(uint256)")), _n)); |
||||||
} |
} |
||||||
|
|
||||||
function delegatecallSetN(address _e, uint _n) { |
function delegatecallSetN(address _e, uint _n) public { |
||||||
_e.delegatecall(bytes4(sha3("setN(uint256)")), _n); |
_e.delegatecall(abi.encode(bytes4(keccak256("setN(uint256)")), _n)); |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,17 +1,16 @@ |
|||||||
pragma solidity ^0.4.17; |
pragma solidity 0.5.0; |
||||||
|
|
||||||
contract Transfer1 { |
|
||||||
|
|
||||||
function transfer() { |
contract Transfer1 { |
||||||
|
function transfer() public { |
||||||
msg.sender.transfer(1 ether); |
msg.sender.transfer(1 ether); |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
contract Transfer2 { |
|
||||||
|
|
||||||
function transfer() { |
contract Transfer2 { |
||||||
|
function transfer() public { |
||||||
msg.sender.transfer(2 ether); |
msg.sender.transfer(2 ether); |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,6 +1,8 @@ |
|||||||
pragma solidity ^0.4.22; |
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract nonAscii { |
contract nonAscii { |
||||||
function renderNonAscii () public pure returns (string) { |
function renderNonAscii () public pure returns (string memory) { |
||||||
return "Хэллоу Ворлд"; |
return "Хэллоу Ворлд"; |
||||||
} |
} |
||||||
} |
} |
@ -1,20 +1,23 @@ |
|||||||
|
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract Over { |
contract Over { |
||||||
|
|
||||||
mapping(address => uint) balances; |
mapping(address => uint) balances; |
||||||
uint public totalSupply; |
uint public totalSupply; |
||||||
|
|
||||||
function Token(uint _initialSupply) { |
constructor(uint _initialSupply) public { |
||||||
balances[msg.sender] = totalSupply = _initialSupply; |
balances[msg.sender] = totalSupply = _initialSupply; |
||||||
} |
} |
||||||
|
|
||||||
function sendeth(address _to, uint _value) public returns (bool) { |
function sendeth(address _to, uint _value) public returns (bool) { |
||||||
require(balances[msg.sender] - _value >= 0); |
// require(balances[msg.sender] - _value >= 0); |
||||||
balances[msg.sender] -= _value; |
balances[msg.sender] -= _value; |
||||||
balances[_to] += _value; |
balances[_to] += _value; |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
|
|
||||||
function balanceOf(address _owner) public constant returns (uint balance) { |
function balanceOf(address _owner) public view returns (uint balance) { |
||||||
return balances[_owner]; |
return balances[_owner]; |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,13 +1,17 @@ |
|||||||
|
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract ReturnValue { |
contract ReturnValue { |
||||||
|
|
||||||
address callee = 0xE0F7e56e62b4267062172495D7506087205A4229; |
address public callee = 0xE0f7e56E62b4267062172495D7506087205A4229; |
||||||
|
|
||||||
function callnotchecked() { |
function callnotchecked() public { |
||||||
callee.call(); |
callee.call(""); |
||||||
} |
} |
||||||
|
|
||||||
function callchecked() { |
function callchecked() public { |
||||||
require(callee.call()); |
(bool success, bytes memory data) = callee.call(""); |
||||||
|
require(success); |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
@ -1,6 +1,9 @@ |
|||||||
|
pragma solidity 0.5.0; |
||||||
|
|
||||||
|
|
||||||
contract Suicide { |
contract Suicide { |
||||||
|
|
||||||
function kill(address addr) { |
function kill(address payable addr) public { |
||||||
selfdestruct(addr); |
selfdestruct(addr); |
||||||
} |
} |
||||||
|
|
||||||
|
@ -1,126 +1 @@ |
|||||||
{ |
{"error": null, "issues": [{"address": 661, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "thisisfine()", "max_gas_used": 1254, "min_gas_used": 643, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 666, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "thisisfine()", "max_gas_used": 35963, "min_gas_used": 1352, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 779, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "callstoredaddress()", "max_gas_used": 1298, "min_gas_used": 687, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 784, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "callstoredaddress()", "max_gas_used": 36007, "min_gas_used": 1396, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 858, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call to an external address. Verify that the code at this address is trusted and immutable.", "function": "reentrancy()", "max_gas_used": 1320, "min_gas_used": 709, "swc-id": "107", "title": "External call", "type": "Informational"}, {"address": 871, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "reentrancy()", "max_gas_used": 61043, "min_gas_used": 6432, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 912, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.", "function": "calluseraddress(address)", "max_gas_used": 616, "min_gas_used": 335, "swc-id": "107", "title": "External call to user-supplied address", "type": "Warning"}, {"address": 918, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "calluseraddress(address)", "max_gas_used": 35327, "min_gas_used": 1046, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true} |
||||||
"error": null, |
|
||||||
"issues": [ |
|
||||||
{ |
|
||||||
"address": 661, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", |
|
||||||
"function": "thisisfine()", |
|
||||||
"swc-id": "107", |
|
||||||
"min_gas_used": 643, |
|
||||||
"max_gas_used": 1254, |
|
||||||
"title": "Message call to external contract", |
|
||||||
"type": "Informational" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 666, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", |
|
||||||
"function": "thisisfine()", |
|
||||||
"swc-id": "104", |
|
||||||
"min_gas_used": 1352, |
|
||||||
"max_gas_used": 35963, |
|
||||||
"title": "Unchecked CALL return value", |
|
||||||
"type": "Informational" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 779, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `setstoredaddress(address)`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", |
|
||||||
"function": "callstoredaddress()", |
|
||||||
"swc-id": "107", |
|
||||||
"min_gas_used": 687, |
|
||||||
"max_gas_used": 1298, |
|
||||||
"title": "Message call to external contract", |
|
||||||
"type": "Warning" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 779, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "Possible transaction order dependence vulnerability: The value or direction of the call statement is determined from a tainted storage location.", |
|
||||||
"function": "callstoredaddress()", |
|
||||||
"swc-id": "114", |
|
||||||
"min_gas_used": 687, |
|
||||||
"max_gas_used": 1298, |
|
||||||
"title": "Transaction order dependence", |
|
||||||
"type": "Warning" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 784, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", |
|
||||||
"function": "callstoredaddress()", |
|
||||||
"swc-id": "104", |
|
||||||
"min_gas_used": 1396, |
|
||||||
"max_gas_used": 36007, |
|
||||||
"title": "Unchecked CALL return value", |
|
||||||
"type": "Informational" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 858, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", |
|
||||||
"function": "_function_0xe11f493e", |
|
||||||
"swc-id": "107", |
|
||||||
"min_gas_used": 709, |
|
||||||
"max_gas_used": 1320, |
|
||||||
"title": "Message call to external contract", |
|
||||||
"type": "Informational" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 869, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.", |
|
||||||
"function": "_function_0xe11f493e", |
|
||||||
"swc-id": "107", |
|
||||||
"min_gas_used": 709, |
|
||||||
"max_gas_used": 1320, |
|
||||||
"title": "State change after external call", |
|
||||||
"type": "Warning" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 871, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", |
|
||||||
"function": "_function_0xe11f493e", |
|
||||||
"swc-id": "104", |
|
||||||
"min_gas_used": 6432, |
|
||||||
"max_gas_used": 61043, |
|
||||||
"title": "Unchecked CALL return value", |
|
||||||
"type": "Informational" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 912, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", |
|
||||||
"function": "calluseraddress(address)", |
|
||||||
"swc-id": "107", |
|
||||||
"min_gas_used": 335, |
|
||||||
"max_gas_used": 616, |
|
||||||
"title": "Message call to external contract", |
|
||||||
"type": "Warning" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 918, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", |
|
||||||
"function": "calluseraddress(address)", |
|
||||||
"swc-id": "104", |
|
||||||
"min_gas_used": 1046, |
|
||||||
"max_gas_used": 35327, |
|
||||||
"title": "Unchecked CALL return value", |
|
||||||
"type": "Informational" |
|
||||||
} |
|
||||||
], |
|
||||||
"success": true |
|
||||||
} |
|
@ -1,30 +1,5 @@ |
|||||||
{ |
{ |
||||||
"error": null, |
"error": null, |
||||||
"issues": [ |
"issues": [], |
||||||
{ |
|
||||||
"address": 722, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability.", |
|
||||||
"function": "withdrawfunds()", |
|
||||||
"max_gas_used": 1749, |
|
||||||
"min_gas_used": 1138, |
|
||||||
"swc-id": "105", |
|
||||||
"title": "Ether thief", |
|
||||||
"type": "Warning" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 883, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "This binary add operation can result in integer overflow.\n", |
|
||||||
"function": "invest()", |
|
||||||
"max_gas_used": 1856, |
|
||||||
"min_gas_used": 1571, |
|
||||||
"swc-id": "101", |
|
||||||
"title": "Integer Overflow", |
|
||||||
"type": "Warning" |
|
||||||
} |
|
||||||
], |
|
||||||
"success": true |
"success": true |
||||||
} |
} |
||||||
|
@ -1,25 +1,3 @@ |
|||||||
# Analysis results for test-filename.sol |
# Analysis results for None |
||||||
|
|
||||||
## Ether thief |
The analysis was completed successfully. No issues were detected. |
||||||
- SWC ID: 105 |
|
||||||
- Type: Warning |
|
||||||
- Contract: Unknown |
|
||||||
- Function name: `withdrawfunds()` |
|
||||||
- PC address: 722 |
|
||||||
- Estimated Gas Usage: 1138 - 1749 |
|
||||||
|
|
||||||
### Description |
|
||||||
|
|
||||||
Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability. |
|
||||||
|
|
||||||
## Integer Overflow |
|
||||||
- SWC ID: 101 |
|
||||||
- Type: Warning |
|
||||||
- Contract: Unknown |
|
||||||
- Function name: `invest()` |
|
||||||
- PC address: 883 |
|
||||||
- Estimated Gas Usage: 1571 - 1856 |
|
||||||
|
|
||||||
### Description |
|
||||||
|
|
||||||
This binary add operation can result in integer overflow. |
|
||||||
|
@ -1,21 +1 @@ |
|||||||
==== Ether thief ==== |
The analysis was completed successfully. No issues were detected. |
||||||
SWC ID: 105 |
|
||||||
Type: Warning |
|
||||||
Contract: Unknown |
|
||||||
Function name: withdrawfunds() |
|
||||||
PC address: 722 |
|
||||||
Estimated Gas Usage: 1138 - 1749 |
|
||||||
Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability. |
|
||||||
-------------------- |
|
||||||
|
|
||||||
==== Integer Overflow ==== |
|
||||||
SWC ID: 101 |
|
||||||
Type: Warning |
|
||||||
Contract: Unknown |
|
||||||
Function name: invest() |
|
||||||
PC address: 883 |
|
||||||
Estimated Gas Usage: 1571 - 1856 |
|
||||||
This binary add operation can result in integer overflow. |
|
||||||
|
|
||||||
-------------------- |
|
||||||
|
|
||||||
|
@ -1,54 +1 @@ |
|||||||
{ |
{"error": null, "issues": [{"address": 626, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x141f32ff", "max_gas_used": 35856, "min_gas_used": 1104, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 857, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x9b58bc26", "max_gas_used": 35919, "min_gas_used": 1167, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 1038, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The contract executes a function call with high gas to a user-supplied address. Note that the callee can contain arbitrary code and may re-enter any function in this contract. Review the business logic carefully to prevent unanticipated effects on the contract state.", "function": "_function_0xeea4c864", "max_gas_used": 1229, "min_gas_used": 477, "swc-id": "107", "title": "External call to user-supplied address", "type": "Warning"}, {"address": 1046, "contract": "Unknown", "debug": "<DEBUG-DATA>", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xeea4c864", "max_gas_used": 35944, "min_gas_used": 1192, "swc-id": "104", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true} |
||||||
"error": null, |
|
||||||
"issues": [ |
|
||||||
{ |
|
||||||
"address": 626, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", |
|
||||||
"function": "_function_0x141f32ff", |
|
||||||
"swc-id": "104", |
|
||||||
"min_gas_used": 1104, |
|
||||||
"max_gas_used": 35856, |
|
||||||
"title": "Unchecked CALL return value", |
|
||||||
"type": "Informational" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 857, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", |
|
||||||
"function": "_function_0x9b58bc26", |
|
||||||
"swc-id": "104", |
|
||||||
"min_gas_used": 1167, |
|
||||||
"max_gas_used": 35919, |
|
||||||
"title": "Unchecked CALL return value", |
|
||||||
"type": "Informational" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 1038, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", |
|
||||||
"function": "_function_0xeea4c864", |
|
||||||
"swc-id": "107", |
|
||||||
"min_gas_used": 477, |
|
||||||
"max_gas_used": 1229, |
|
||||||
"title": "Message call to external contract", |
|
||||||
"type": "Warning" |
|
||||||
}, |
|
||||||
{ |
|
||||||
"address": 1046, |
|
||||||
"contract": "Unknown", |
|
||||||
"debug": "<DEBUG-DATA>", |
|
||||||
"description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", |
|
||||||
"function": "_function_0xeea4c864", |
|
||||||
"swc-id": "104", |
|
||||||
"min_gas_used": 1192, |
|
||||||
"max_gas_used": 35944, |
|
||||||
"title": "Unchecked CALL return value", |
|
||||||
"type": "Informational" |
|
||||||
} |
|
||||||
], |
|
||||||
"success": true |
|
||||||
} |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue