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') environment = Environment(active_account, None, None, None, None, None) state = GlobalState(None, environment) 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 issues = execute(statespace) # assert assert concrete_mock.call_count == 1 assert sym_mock.call_count == 1
def test_execute_node(mocker): record = TaintRecord() record.stack = [True, True, False, False] state_1 = GlobalState(None, None) state_1.mstate.stack = [1, 2, 3] state_1.mstate.pc = 1 mocker.patch.object(state_1, 'get_current_instruction') state_1.get_current_instruction.return_value = {"opcode": "SWAP1"} state_2 = GlobalState(None, 1) state_2.mstate.stack = [1, 2, 4, 1] mocker.patch.object(state_2, 'get_current_instruction') state_2.get_current_instruction.return_value = {"opcode": "ADD"} node = Node("Test contract") node.states = [state_1, state_2] # Act records = TaintRunner.execute_node(node, record) # Assert assert len(records) == 2 assert records[0].stack == [True, True, False, False] assert records[1].stack == [True, True, False] assert state_2 in records[0].states assert state_1 in record.states
def test_concrete_call(): # arrange address = "0x10" state = GlobalState(None, 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 = _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.\n DELEGATECALL target: 0x1"
def test_symbolic_call_storage_to(mocker): # arrange address = "0x10" active_account = Account(address) environment = Environment(active_account, None, None, None, None, None) state = GlobalState(None, environment) 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 = _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_concrete_call_not_calldata(): # arrange state = GlobalState(None, None) state.mstate.memory = ["placeholder", "not_calldata"] meminstart = Variable(1, VarType.CONCRETE) # act issues = _concrete_call(None, state, None, meminstart) # assert assert issues == []
def test_execute(mocker): active_account = Account('0x00') environment = Environment(active_account, None, None, None, None, None) state_1 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_1.mstate.stack = [1, 2] mocker.patch.object(state_1, 'get_current_instruction') state_1.get_current_instruction.return_value = {"opcode": "PUSH"} state_2 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_2.mstate.stack = [1, 2, 3] mocker.patch.object(state_2, 'get_current_instruction') state_2.get_current_instruction.return_value = {"opcode": "ADD"} node_1 = Node("Test contract") node_1.states = [state_1, state_2] state_3 = GlobalState(None, environment, None, MachineState(gas=10000000)) state_3.mstate.stack = [1, 2] mocker.patch.object(state_3, 'get_current_instruction') state_3.get_current_instruction.return_value = {"opcode": "ADD"} node_2 = Node("Test contract") node_2.states = [state_3] edge = Edge(node_1.uid, node_2.uid) statespace = LaserEVM(None) statespace.edges = [edge] statespace.nodes[node_1.uid] = node_1 statespace.nodes[node_2.uid] = node_2 # Act result = TaintRunner.execute(statespace, node_1, state_1, [True, True]) # Assert print(result) assert len(result.records) == 3 assert result.records[2].states == [] assert state_3 in result.records[1].states
def test_result_no_state(): # arrange taint_result = TaintResult() record = TaintRecord() state = GlobalState(2, None, None) state.mstate.stack = [1, 2, 3] # act taint_result.add_records([record]) tainted = taint_result.check(state, 2) # assert assert tainted is None assert record in taint_result.records
def test_execute_state(mocker): record = TaintRecord() record.stack = [True, False, True] state = GlobalState(None, None) state.mstate.stack = [1, 2, 3] mocker.patch.object(state, 'get_current_instruction') state.get_current_instruction.return_value = {"opcode": "ADD"} # Act new_record = TaintRunner.execute_state(record, state) # Assert assert new_record.stack == [True, True] assert record.stack == [True, False, True]
def get_constr_glbstate(contract, address): mstate = MachineState(gas=10000000) minimal_const_byte_len = get_minimal_constructor_param_encoding_len( abi_json_to_abi(contract.abi)) # better would be to append symbolic params to the bytecode such that the codecopy instruction that copies the # params into memory takes care of placing them onto the memory with the respective size. for i in range(int(minimal_const_byte_len / 32)): mstate.mem_extend(128 + 32 * i, 32) mstate.memory.insert( 128 + 32 * i, BitVec('calldata_' + contract.name + '_' + str(i * 32), 256)) # Todo Replace pure placement of enough symbolic 32 Byte-words with placement of symbolic variables that contain # the name of the solidity variables accounts = { address: Account(address, contract.disassembly, contract_name=contract.name) } environment = Environment( accounts[address], BitVec("caller", 256), [], BitVec("gasprice", 256), BitVec("callvalue", 256), BitVec("origin", 256), calldata_type=CalldataType.SYMBOLIC, ) # Todo find source for account info, maybe the std statespace? return GlobalState(accounts, environment, mstate)