Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
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"
Exemple #4
0
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.'
Exemple #5
0
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 == []
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
0
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)