Example #1
0
def execute(statespace):
    """
    Executes analysis module for delegate call analysis module
    :param statespace: Statespace to analyse
    :return: Found issues
    """
    issues = []

    for call in statespace.calls:

        if call.type is not "DELEGATECALL":
            continue
        if call.node.function_name is not "fallback":
            continue

        state = call.state
        address = state.get_current_instruction()['address']
        meminstart = get_variable(state.mstate.stack[-3])

        if meminstart.type == VarType.CONCRETE:
            issues += _concrete_call(call, state, address, meminstart)

        if call.to.type == VarType.SYMBOLIC:
            issues += _symbolic_call(call, state, address, statespace)

    return issues
Example #2
0
def _analyze_states(state: GlobalState) -> List[Issue]:
    """
    :param state: the current state
    :return: returns the issues for that corresponding state
    """
    call = get_call_from_state(state)
    if call is None:
        return []
    issues = []  # type: List[Issue]

    if call.type is not "DELEGATECALL":
        return []
    if call.node.function_name is not "fallback":
        return []

    state = call.state
    address = state.get_current_instruction()["address"]
    meminstart = get_variable(state.mstate.stack[-3])

    if meminstart.type == VarType.CONCRETE:
        issues += _concrete_call(call, state, address, meminstart)

    return issues
Example #3
0
def get_call_from_state(state: GlobalState) -> Union[Call, None]:
    """

    :param state:
    :return:
    """
    instruction = state.get_current_instruction()

    op = instruction["opcode"]
    stack = state.mstate.stack

    if op in ("CALL", "CALLCODE", "STATICCALL"):
        gas, to, value, meminstart, meminsz, memoutstart, memoutsz = (
            get_variable(stack[-1]),
            get_variable(stack[-2]),
            get_variable(stack[-3]),
            get_variable(stack[-4]),
            get_variable(stack[-5]),
            get_variable(stack[-6]),
            get_variable(stack[-7]),
        )

        if to.type == VarType.CONCRETE and 0 < to.val < 5:
            return None

        if meminstart.type == VarType.CONCRETE and meminsz.type == VarType.CONCRETE:
            return Call(
                state.node,
                state,
                None,
                op,
                to,
                gas,
                value,
                state.mstate.memory[meminstart.val : meminsz.val * 4],
            )
        else:
            return Call(state.node, state, None, op, to, gas, value)

    else:
        gas, to, meminstart, meminsz, memoutstart, memoutsz = (
            get_variable(stack[-1]),
            get_variable(stack[-2]),
            get_variable(stack[-3]),
            get_variable(stack[-4]),
            get_variable(stack[-5]),
            get_variable(stack[-6]),
        )

        return Call(state.node, state, None, op, to, gas)
Example #4
0
def execute(statespace):

    issues = []

    for call in statespace.calls:

        if (call.type == "DELEGATECALL"):

            state = call.state
            address = state.get_current_instruction()['address']

            if (call.node.function_name == "fallback"):

                stack = 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, "Call data forwarded with delegatecall()",
                            "Informational")

                        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"

                        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):
                            idx = 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(
                                idx
                            ) + ". This storage slot can be written to by calling the function '" + func + "'. "

                        else:
                            logging.debug(
                                "[DELEGATECALL] No storage writes to index " +
                                str(idx))

                        issue.description += "Be aware that the called contract gets unrestricted access to this contract's state."
                        issues.append(issue)

    return issues