示例#1
0
    def arbitrary_send(self, func):
        """
        """
        if func.is_protected():
            return []

        ret = []
        for node in func.nodes:
            for ir in node.irs:
                if isinstance(ir, SolidityCall):
                    if ir.function == SolidityFunction('ecrecover(bytes32,uint8,bytes32,bytes32)'):
                        return False
                if isinstance(ir, Index):
                    if ir.variable_right == SolidityVariableComposed('msg.sender'):
                        return False
                    if is_dependent(ir.variable_right, SolidityVariableComposed('msg.sender'), func.contract):
                        return False
                if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)):
                    if isinstance(ir, (HighLevelCall)):
                        if isinstance(ir.function, Function):
                            if ir.function.full_name == 'transferFrom(address,address,uint256)':
                                return False
                    if ir.call_value is None:
                        continue
                    if ir.call_value == SolidityVariableComposed('msg.value'):
                        continue
                    if is_dependent(ir.call_value, SolidityVariableComposed('msg.value'), func.contract):
                        continue

                    if is_tainted(ir.destination, func.contract, self.slither):
                        ret.append(node)


        return ret
示例#2
0
 def controlled_delegatecall(self, function):
     ret = []
     for node in function.nodes:
         for ir in node.irs:
             if isinstance(ir, LowLevelCall) and ir.function_name in ['delegatecall', 'codecall']:
                 if is_tainted(ir.destination, function.contract):
                     ret.append(node)
     return ret
示例#3
0
 def _node_taint(self, node):
     if node.high_level_calls or node.low_level_calls:
         for ir in node.irs:
             if hasattr(ir, 'destination'):
                 taintflag = is_tainted(ir.destination, node.function.contract)
                 if taintflag is True:
                     return True
     return False
    def _node_taint(self, node):

        if node.high_level_calls or node.low_level_calls:
            for highLevelCall in node.high_level_calls:
                contract, functionOrVariable = highLevelCall
                if isinstance(functionOrVariable, Function):
                    for ir in node.irs:
                        if hasattr(ir, 'destination'):
                            taintflag = is_tainted(ir.destination, node.function.contract)
                            if taintflag is True:
                                # print(str(node.expression) + '\t' + str(taintflag))
                                return True
        if node.low_level_calls:
            for ir in node.irs:
                if hasattr(ir, 'destination'):
                    taintflag = is_tainted(ir.destination, node.function.contract)
                    if taintflag is True:
                        # print(str(node.expression) + '\t' + str(taintflag))
                        return True
        return False
示例#5
0
 def isTaint(self, contract):
     for function in contract.functions_and_modifiers_declared:
         # print('{} -> {}'.format(type(function.visibility), function.visibility))
         #if function.visibility in ['public', 'external']:
         for node in function.nodes:
             taintRes = False
             if node.high_level_calls or node.low_level_calls:
                 for ir in node.irs:
                     if hasattr(ir, 'destination'):
                         taintRes = is_tainted(ir.destination,
                                               function.contract)
                         print('Function: {} dest: {}  isTaint {}'.format(
                             function.full_name, ir.destination, taintRes))
示例#6
0
    def call_in_loop(f, node, in_loop, visited, ret, loopsum):
        if node in visited:
            return
        # shared visited
        visited.append(node)

        if node.type == NodeType.STARTLOOP:
            loopsum.append('hasloop')
            # print('>>>>>>>>>>>>>begin loop')
            in_loop = True
            # is_tainted_by_arg, is_tainted_by_statevar, is_tained_by_local, has_transaction, has_lib_call, has_nested_loop = MultipleCallsInLoop.collect_summary(node, f)
            # print('Loop Summary----', 'has_nested_loop:', has_nested_loop, 'has_lib_call:', has_lib_call, 'has_transaction:', has_transaction,
            #             'is_tained_by_local:', is_tained_by_local, 'is_tainted_by_arg:', is_tainted_by_arg, 'is_tainted_by_statevar:', is_tainted_by_statevar )

        elif node.type == NodeType.ENDLOOP:
            # print('<<<<<<<<<<<<<exit loop')
            in_loop = False

        if in_loop:
            has_nested_loop = any(
                (son.type == NodeType.STARTLOOP) for son in node.sons)
            if has_nested_loop:
                loopsum.append('nested_loop')
            for ir in node.irs:
                if isinstance(ir,
                              (LowLevelCall, HighLevelCall, Send, Transfer)):
                    if isinstance(ir, LibraryCall):
                        has_lib_call = True
                        loopsum.append('lib_call')
                    else:
                        has_transaction = True
                        loopsum.append('transaction')

                if isinstance(ir, Condition):
                    is_tainted_by_arg = is_tainted(ir.value, f)
                    is_tainted_by_statevar = any(
                        is_dependent(ir.value, t, f)
                        for t in f.contract.state_variables)
                    is_tained_by_local = not (is_tainted_by_arg
                                              or is_tainted_by_statevar)
                    # print(is_tainted_by_arg, is_tainted_by_statevar, is_tained_by_local, node, type(node))
                    if is_tainted_by_arg:
                        loopsum.append('tainted_by_arg')
                    if is_tainted_by_statevar:
                        loopsum.append('tainted_by_statevar')
                    if is_tained_by_local:
                        loopsum.append('tained_by_local')

        for son in node.sons:
            MultipleCallsInLoop.call_in_loop(f, son, in_loop, visited, ret,
                                             loopsum)
示例#7
0
def node_taint(node):
    if node.internal_calls:
        for internalCall in node.internal_calls:
            if isinstance(internalCall, Function):
                node.callee.append(internalCall)
    if node.high_level_calls or node.low_level_calls:
        for highLevelCall in node.high_level_calls:
            contract, functionOrVariable = highLevelCall
            if isinstance(functionOrVariable, Function):
                node.callee.append(functionOrVariable)
                for ir in node.irs:
                    if hasattr(ir, 'destination'):
                        taintflag = is_tainted(ir.destination,
                                               node.function.contract)
                        if taintflag is True:
                            return True
    if node.low_level_calls:
        for ir in node.irs:
            if hasattr(ir, 'destination'):
                taintflag = is_tainted(ir.destination, node.function.contract)
                if taintflag is True:
                    return True
    return False
示例#8
0
    def _detect_missing_zero_address_validation(self, contract):
        """
        Detects if addresses are zero address validated before use.
        :param contract: The contract to check
        :return: Functions with nodes where addresses used are not zero address validated earlier
        """
        results = []

        for function in contract.functions_entry_points:
            var_nodes = defaultdict(list)

            for node in function.nodes:
                sv_addrs_written = [
                    sv
                    for sv in node.state_variables_written
                    if sv.type == ElementaryType("address")
                ]

                addr_calls = False
                for ir in node.irs:
                    if isinstance(ir, (Send, Transfer, LowLevelCall)):
                        addr_calls = True

                # Continue if no address-typed state variables are written and if no send/transfer/call
                if not sv_addrs_written and not addr_calls:
                    continue

                # Check local variables used in such nodes
                for var in node.local_variables_read:
                    # Check for address types that are tainted but not by msg.sender
                    if var.type == ElementaryType("address") and is_tainted(
                        var, function, ignore_generic_taint=True
                    ):
                        # Check for zero address validation of variable
                        # in the context of modifiers used or prior function context
                        if not (
                            self._zero_address_validation_in_modifier(
                                var, function.modifiers_statements
                            )
                            or self._zero_address_validation(var, node, [])
                        ):
                            # Report a variable only once per function
                            var_nodes[var].append(node)
            if var_nodes:
                results.append((function, var_nodes))
        return results
示例#9
0
def detect_array_length_assignment(contract):
    """
    Detects and returns all nodes which assign array length.
    :param contract: Contract to detect assignment within.
    :return: A list of tuples with (Variable, node) where Variable references an array whose length was set by node.
    """

    # Create our result set.
    results = set()

    # Loop for each function and modifier.
    # pylint: disable=too-many-nested-blocks
    for function in contract.functions_and_modifiers_declared:
        # Define a set of reference variables which refer to array length.
        array_length_refs = set()

        # Loop for every node in this function, looking for expressions where array length references are made,
        # and subsequent expressions where array length references are assigned to.
        for node in function.nodes:
            if node.type == NodeType.EXPRESSION:
                for ir in node.irs:

                    # First we look for the member access for 'length', for which a reference is created.
                    # We add the reference to our list of array length references.
                    if isinstance(ir, Length):  # a
                        #                            if ir.variable_right == "length":
                        array_length_refs.add(ir.lvalue)

                    # If we have an assignment/binary operation, verify the left side refers to a reference variable
                    # which is in our list or array length references. (Array length is being assigned to).
                    elif isinstance(ir, (Assignment, Binary)):
                        if isinstance(ir.lvalue, ReferenceVariable):
                            if ir.lvalue in array_length_refs and any(
                                    is_tainted(v, contract) for v in ir.read):
                                # the taint is not precise enough yet
                                # as a result, REF_0 = REF_0 + 1
                                # where REF_0 points to a LENGTH operation
                                # is considered as tainted
                                if ir.lvalue in ir.read:
                                    continue
                                results.add(node)
                                break

    # Return the resulting set of nodes which set array length.
    return results
示例#10
0
    def _externalCallLinkparse(self, node):
        externalCallLink_parse_Result = 0  # 证明这个调用链的dest不脏
        """
        :param node: 含有外部调用的node(跨合约)
        :return: 如果确实是脏数据则返回1
        遇到外部调用需要进行的分析
        1:先进行外部调用的脏数据分析:
            若确定为脏数据,打印‘reentrance’并返回1
            否则, 进入这个干净外部函数内得到他的所有node,再次分析调用链self._analyzerCallLink(calledExternalFunctionNode)
        """
        print("进入外部调用链分析")
        print('开始分析的节点是', node.type)
        taintflag = False
        if node.high_level_calls or node.low_level_calls:
            # if node.low_level_calls:   # 这块仅仅是模拟没有任何参考价值
            #     taintflag = True
            print('进行脏数据分析...')
            for ir in node.irs:
                if hasattr(ir, 'destination'):
                    taintflag = is_tainted(ir.destination,
                                           node.function.contract)
            if taintflag:  # 如果数据脏则打印Reentrance
                print('脏')
                externalCallLink_parse_Result = 1
                return externalCallLink_parse_Result

            else:  # 如果数据干净,跳入external call的Function.
                print('不脏')
                high_level_calls = []
                for high_level_calls_tuple in node.high_level_calls:
                    high_level_calls.append(high_level_calls_tuple[1])
                    # for external_calls in high_level_calls:  # node.low_level_calls暂不考虑,因为根据node.low_level_call目前还跳不进去这个called外部调用函数
                    for external_call in high_level_calls:
                        calledExternalFunction = external_call  # 得到called外部调用函数对象实例
                        print('准备跳转到外部调用函数中:',
                              calledExternalFunction.full_name)
                        calledExternalFunctionNodeList = self._getAllNodes(
                            calledExternalFunction)
                        for calledExternalFunctionNode in calledExternalFunctionNodeList:
                            externalCallLink_parse_Result = self._analyzerCallLink(
                                calledExternalFunctionNode)
                            if externalCallLink_parse_Result == 1:
                                return externalCallLink_parse_Result

        return externalCallLink_parse_Result
    def _detect_missing_events(self, contract):
        """
        Detects if critical contract parameters set by owners and used in arithmetic are missing events
        :param contract: The contract to check
        :return: Functions with nodes of critical operations but no events
        """
        results = []

        for function in contract.functions_entry_points:
            nodes = []

            # Check for any events in the function and skip if found
            # Note: not checking if event corresponds to critical parameter
            if any(ir for node in function.nodes for ir in node.irs if isinstance(ir, EventCall)):
                continue

            # Ignore constructors and private/internal functions
            # Heuristic-1: functions writing to critical parameters are typically "protected".
            # Skip unprotected functions.
            if function.is_constructor or not function.is_protected():
                continue

            # Heuristic-2: Critical operations are where state variables are written and tainted
            # Heuristic-3: Variables of interest are int/uint types that are used (mostly in arithmetic)
            # in other unprotected functions
            # Heuristic-4: Critical operations present but no events in the function is not a good practice
            for node in function.nodes:
                for sv in node.state_variables_written:
                    if (
                        is_tainted(sv, function)
                        and isinstance(sv.type, ElementaryType)
                        and sv.type.type in Int + Uint
                    ):
                        used_nodes = self._detect_unprotected_use(contract, sv)
                        if used_nodes:
                            nodes.append((node, used_nodes))

            if nodes:
                results.append((function, nodes))
        return results
def arbitrary_send(func: Function):
    if func.is_protected():
        return []

    ret: List[Node] = []
    for node in func.nodes:
        for ir in node.irs:
            if isinstance(ir, SolidityCall):
                if ir.function == SolidityFunction("ecrecover(bytes32,uint8,bytes32,bytes32)"):
                    return False
            if isinstance(ir, Index):
                if ir.variable_right == SolidityVariableComposed("msg.sender"):
                    return False
                if is_dependent(
                    ir.variable_right,
                    SolidityVariableComposed("msg.sender"),
                    func.contract,
                ):
                    return False
            if isinstance(ir, (HighLevelCall, LowLevelCall, Transfer, Send)):
                if isinstance(ir, (HighLevelCall)):
                    if isinstance(ir.function, Function):
                        if ir.function.full_name == "transferFrom(address,address,uint256)":
                            return False
                if ir.call_value is None:
                    continue
                if ir.call_value == SolidityVariableComposed("msg.value"):
                    continue
                if is_dependent(
                    ir.call_value,
                    SolidityVariableComposed("msg.value"),
                    func.contract,
                ):
                    continue

                if is_tainted(ir.destination, func.contract):
                    ret.append(node)

    return ret
    def _detect_missing_events(contract):
        """
        Detects if critical contract parameters set by owners and used in access control are missing events
        :param contract: The contract to check
        :return: Functions with nodes of critical operations but no events
        """
        results = []

        # pylint: disable=too-many-nested-blocks
        for function in contract.functions_entry_points:
            nodes = []

            # Check for any events in the function and skip if found
            # Note: not checking if event corresponds to critical parameter
            if any(ir for node in function.nodes for ir in node.irs
                   if isinstance(ir, EventCall)):
                continue

            # Ignore constructors and private/internal functions
            # Heuristic-1: functions with critical operations are typically "protected". Skip unprotected functions.
            if function.is_constructor or not function.is_protected():
                continue

            # Heuristic-2: Critical operations are where state variables are written and tainted
            # Heuristic-3: Variables of interest are address type that are used in modifiers i.e. access control
            # Heuristic-4: Critical operations present but no events in the function is not a good practice
            for node in function.nodes:
                for sv in node.state_variables_written:
                    if is_tainted(
                            sv,
                            function) and sv.type == ElementaryType("address"):
                        for mod in function.contract.modifiers:
                            if sv in mod.state_variables_read:
                                nodes.append((node, sv, mod))
            if nodes:
                results.append((function, nodes))
        return results
示例#14
0
from slither.core.declarations.solidity_variables import SolidityVariableComposed

slither = Slither('data_dependency.sol')

contract = slither.get_contract_from_name('Simple')

destination = contract.get_state_variable_from_name('destination')
source = contract.get_state_variable_from_name('source')

print('{} is dependent of {}: {}'.format(
    source, destination, is_dependent(source, destination, contract)))
assert not is_dependent(source, destination, contract)
print('{} is dependent of {}: {}'.format(
    destination, source, is_dependent(destination, source, contract)))
assert is_dependent(destination, source, contract)
print('{} is tainted {}'.format(source, is_tainted(source, contract, slither)))
assert not is_tainted(source, contract, slither)
print('{} is tainted {}'.format(destination,
                                is_tainted(destination, contract, slither)))
assert is_tainted(destination, contract, slither)

contract = slither.get_contract_from_name('Reference')

destination = contract.get_state_variable_from_name('destination')
source = contract.get_state_variable_from_name('source')

print('Reference contract')
print('{} is dependent of {}: {}'.format(
    source, destination, is_dependent(source, destination, contract)))
assert not is_dependent(source, destination, contract)
print('{} is dependent of {}: {}'.format(
示例#15
0
    def detect_reentrancy(self, contract, callGraph, dangerFunctionList):
        '''
        得到taintFunctionNode 对应 的function得到function所有的taintNode,append到taintFunction.taintNodes属性中
        '''
        for taintFunctionNode in callGraph.taintFunctionNodes:
            taintFunction = taintFunctionNode.function
            for node in taintFunction.nodes:
                if node.high_level_calls or node.low_level_calls:
                    for ir in node.irs:
                        if hasattr(ir, 'destination'):
                            taintflag = is_tainted(ir.destination,
                                                   node.function.contract)
                            if taintflag:
                                taintFunction.taintNodes.append(node)
                                taintFunction.directTaintNodes.append(node)

        for function in contract.functions:
            # callGraph.test(function)
            if function.is_implemented:
                dm = DM(function)  # 准备DM
                callPath = []
                fatherFunctionLayerCount = 0  # 回溯调用记录的层数
                eth_nodes = []  # 存储本函数含有转帐功能的cfg节点
                advanceUpdateFlag = False
                taint_nodes = []
                isReentrancy = False  # False代表没有检测到reentrance
                after_ethNodeList = []  # 用于存储转账节点的所有后续节点
                afer_taintNodeList = []
                # 往 eth_nodes列表中append值
                nodes = function.nodes  # 得到函数中所有的节点
                for node in nodes:
                    if self._can_send_eth(node.irs):  # 如果这个节点可以发送eth
                        function.set_canEth(True)
                        eth_nodes.append(node)
                function.ethNodes = eth_nodes

                # for ir in node.irs:
                # if isinstance(ir, Transfer):
                #     transferORsendNodes.append(node)
                # result = self._can_send_eth(node.irs)
                # if result:
                #     self._retrospect(node)
                # afterNodeList = []      # 用于存储每一个函数中的transfer或send所有后续节点
                # for transferORsendNode in transferORsendNodes:
                #     self._getAllbehindNode(transferORsendNode, afterNodeList)  #此时afterNodeList中存入了一个函数中的transfer或send所有后续节点
                #
                # for afterNode in afterNodeList:  # 找出后续是internal call的节点
                #     self._analyzerCallLink(afterNode)
                #

                # 得到每一个eth_node的后续节点并进行存储到after_ethNodeList列表中
                if function.canEth == False:
                    print('合约{}.函数{} 不含有直接转张功能,跳过此函数的分析'.format(
                        function.contract.name, function.full_name))
                    continue

                for eth_cfg_node in eth_nodes:
                    for taint_cfg_Node in function.directTaintNodes:  # function.directTaintNodes !!!
                        ethCFGnode_To_taintCFGnode = []
                        ethCFGnode_To_taintCFGnode.append(eth_cfg_node)
                        ethCFGnode_To_taintCFGnode.extend(
                            list(
                                set(function.nodes) -
                                set([eth_cfg_node, taint_cfg_Node])))
                        ethCFGnode_To_taintCFGnode.append(taint_cfg_Node)
                        allPaths = getCfgAllPath(ethCFGnode_To_taintCFGnode)
                        allPathsNode = allPaths_intToNode(
                            allPaths, ethCFGnode_To_taintCFGnode)
                        if allPathsNode:  # 如果当前eth_node 和 当前taintNode之间至少有一条路径
                            advanceUpdateFlag = dm.advancedUpdateEth(function)
                            human_allPathsNode = []
                            for path in allPathsNode:
                                temp = []
                                for node in reversed(path):
                                    temp.append(str(node.expression))
                                human_allPathsNode.append(temp)
                            privateVisibility = dm.privateVisibility(
                                function)  # 检查function是否为private

                            if privateVisibility is True:  # 如果function 可见性为private
                                havePublicCaller = callerVisibilityHavePublic(
                                    function, callGraph)  # 看是否有public caller
                                if havePublicCaller is True:
                                    isReentrancy = True
                                    print(
                                        '合约{}.函数{}: 本身就有Reentrancy路径结构 | 可见性是private但有publicCaller | 钱更新/锁: {} | paths: {}'
                                        .format(function.contract.name,
                                                function.full_name,
                                                privateVisibility,
                                                advanceUpdateFlag,
                                                havePublicCaller,
                                                human_allPathsNode))
                            else:
                                isReentrancy = True
                                print(
                                    '合约{}.函数{}: 本身就有Reentrancy路径结构 | 且可见性是public | 钱更新/锁: {} | paths: {}'
                                    .format(function.contract.name,
                                            function.full_name,
                                            advanceUpdateFlag,
                                            human_allPathsNode))
                if isReentrancy is True:
                    print('合约{}.函数{}: 是个危险函数!'.format(function.contract.name,
                                                      function.full_name))
                    continue
                '''
                for eth_node in eth_nodes:
                    after_ethNodeList.append(
                        eth_node)  # !!!在得到传送eth节点的所有后续节点列表之前,先把负责传送eth节点的本身添加进来,因为.call.value()类型的node本身也是外部调用!!!
                    self._getAllbehindNode(eth_node, after_ethNodeList)

                # 从after_ethNodeList列表中取出所有的节点(记为afterEthNode), 然后进行调用链的分析
                if after_ethNodeList:
                    print('开始分析 合约{}.函数{}'.format(function.contract.name, function.full_name))
                directTaintReentrancy = False
                for node_afterEthNode in after_ethNodeList:
                    # taintflag = False
                    if node_afterEthNode.high_level_calls or node_afterEthNode.low_level_calls:
                        print('进行脏数据分析...')
                        for ir in node_afterEthNode.irs:
                            if hasattr(ir, 'destination'):
                                result = is_tainted(ir.destination, node_afterEthNode.function.contract)
                                if result == True:
                                    directTaintReentrancy = True
                                    break
                        if directTaintReentrancy == True:
                            break
                if directTaintReentrancy == True:   #待检测函数内部直接taint出Reentrancy
                    advanceUpdateFlag = dm.advancedUpdateEth(function)
                    privateVisibility = dm.privateVisibility(function) # 检查function是否为private
                    if privateVisibility is True:   # 如果function 可见性为private
                        havePublicCaller = callerVisibilityHavePublic(function, callGraph)  # 看是否有public caller
                        if havePublicCaller is True:    # 如果有publice caller
                              # 钱是否提前更新/锁(本质是条件控制的全局变量是否提前更新)
                            print('{}.{} 从本身分析就得到了reentrance结果, 就不用forward call graph了, 钱提前更新/锁:{}, 可见性为private但存在public_Caller'.format(
                                function.contract.name, function.full_name, advanceUpdateFlag))
                            continue
                    else:   # 如果function 可见性为public
                        print(
                            '{}.{} 从本身分析就得到了reentrance结果, 就不用forward call graph了, 钱提前更新/锁:{}, 且可见性不是private'.format(
                                function.contract.name, function.full_name, advanceUpdateFlag))
                        continue
                        # taintflag = True
                    # if taintflag == True:
                    #     isReentrancy = True
                    #     break  # 如果只从本身分析就得到了reentrance结果, 就不用forward call graph了。
                    # else:
                    #     continue


                # advanceUpdateFlag = dm.advancedUpdateEth(function)
                # if isReentrancy == True:  # 到这里这个函数的所有afterEthNode就遍历分析完了,如果为True。输出reentrance,然后分析下一个函数
                #     privateVisibility = dm.privateVisibility(function)
                #     if privateVisibility is True:
                #         havePublicCaller = callerVisibilityHavePublic(function, callGraph)
                #         if havePublicCaller == False:
                #             continue
                #     print('{}.{} 从本身分析就得到了reentrance结果, 就不用forward call graph了, 钱提前更新:{}, 可见性为private但存在public_Caller: {}'.format(function.contract.name, function.full_name, advanceUpdateFlag, privateVisibility))
                #     continue  # 直接开始分析下一个函数
                '''
                if not isReentrancy and function.canEth is True:  # 进行forward call graph
                    print(function.full_name,
                          '可以传送eth,但自身函数体内没直接的reetrance的结构需要进行前向的call graph')
                    function_canEth_Node = callGraph.function_Map_node.get(
                        function)  # 得到这个函数的节点
                    # print(function_canEth_Node.function.full_name)
                    forwardDangerPath = self.forwardPath(
                        function_canEth_Node, after_ethNodeList, callGraph)
                    if forwardDangerPath:  # [[Vt,...Ve], [dangerPath2], [], ...]  # 前向路径存在,准备DM
                        advanceUpdateFlag = dm.advancedUpdateEth(function)
                        huamnlook_forwardDangerPath = []
                        for path in forwardDangerPath:
                            temp = []
                            for item in reversed(path):
                                temp.append(item.function.full_name)
                            huamnlook_forwardDangerPath.append(temp)

                        privateVisibility = dm.privateVisibility(function)
                        if privateVisibility is True:
                            havePublicCaller = callerVisibilityHavePublic(
                                function, callGraph)
                            if havePublicCaller == True:
                                isReentrancy = True
                                print(
                                    '合约{}.函数{} forward Reentrancy | 可见性是private但有publicCaller | 钱更新/锁: {} | paths: {}'
                                    .format(function.contract.name,
                                            function.full_name,
                                            advanceUpdateFlag,
                                            huamnlook_forwardDangerPath))
                                continue  #这个地方是否continue还得考虑
                        else:
                            isReentrancy = True
                            print(
                                '合约{}.函数{} forwardReentrancy | 且可见性是public | 钱更新/锁: {} | paths: {}e'
                                .format(function.contract.name,
                                        function.full_name, advanceUpdateFlag,
                                        huamnlook_forwardDangerPath))
                            continue
                    if isReentrancy is True:
                        print('合约{}.函数{}: 是个危险函数!'.format(
                            function.contract.name, function.full_name))
                        continue

                    backwardDangerPath = self.backwardPath(
                        function_canEth_Node, callGraph)
                    if backwardDangerPath:  # [[Ve,...Vt], [dangerPath2], [], ...]  # 后向路径存在,准备DM

                        afterDM_backwardDangerPaths = []
                        advanceUpdateFlag = dm.advancedUpdateEth(function)
                        huamnlook_backwardDangerPaths = []

                        for path in backwardDangerPath:  # 取出后向路径的每一条路径
                            finallCaller = path[-1]
                            finallCallerPrivateVisibility = dm.privateVisibility(
                                finallCaller)
                            if finallCallerPrivateVisibility is True:  # 如果最后的caller 是private
                                havePublicCaller = callerVisibilityHavePublic(
                                    function, finallCaller
                                )  # 判断finall caller是否有public caller
                                if havePublicCaller is True:
                                    afterDM_backwardDangerPaths.append(path)
                            else:  # 如果最后的caller 是public
                                afterDM_backwardDangerPaths.append(path)
                            # temp = []
                            # for item in path:
                            #     temp.append(item.function.full_name)
                            # huamnlook_backwardDangerPath.append(temp)
                        if afterDM_backwardDangerPaths:
                            isReentrancy = True
                            for afterDM_backwardDangerPath in afterDM_backwardDangerPaths:
                                temp_path = []
                                for item in reversed(
                                        afterDM_backwardDangerPath):
                                    temp_path.append(item.full_name)
                                huamnlook_backwardDangerPaths.append(temp_path)
                            print(
                                '合约{}.函数{} backwardReentrancy | 钱更新/锁: {} | Path:{}'
                                .format(function.contract.name,
                                        function.full_name, advanceUpdateFlag,
                                        huamnlook_backwardDangerPaths))
                    if isReentrancy is True:
                        benci_dangerFunctionList = set()
                        for path in huamnlook_backwardDangerPaths:
                            if path[-1] not in dangerFunctionList:
                                benci_dangerFunctionList.add(path[-1])
                        for dangerFunction in benci_dangerFunctionList:
                            print('合约{}.函数{} 是一个危险函数'.format(
                                dangerFunction.contract.name,
                                dangerFunction.full_name))
                        continue
示例#16
0
    sys.exit(-1)

slither = Slither(sys.argv[1])

contract = slither.get_contract_from_name("Simple")
assert contract
destination = contract.get_state_variable_from_name("destination")
source = contract.get_state_variable_from_name("source")

print("{} is dependent of {}: {}".format(
    source, destination, is_dependent(source, destination, contract)))
assert not is_dependent(source, destination, contract)
print("{} is dependent of {}: {}".format(
    destination, source, is_dependent(destination, source, contract)))
assert is_dependent(destination, source, contract)
print("{} is tainted {}".format(source, is_tainted(source, contract)))
assert not is_tainted(source, contract)
print("{} is tainted {}".format(destination, is_tainted(destination,
                                                        contract)))
assert is_tainted(destination, contract)

contract = slither.get_contract_from_name("Reference")
assert contract
destination = contract.get_state_variable_from_name("destination")
assert destination
source = contract.get_state_variable_from_name("source")
assert source

print("Reference contract")
print("{} is dependent of {}: {}".format(
    source, destination, is_dependent(source, destination, contract)))
    sys.exit(-1)

slither = Slither(sys.argv[1])

contracts = slither.get_contract_from_name("Simple")
assert len(contracts) == 1
contract = contracts[0]
destination = contract.get_state_variable_from_name("destination")
source = contract.get_state_variable_from_name("source")

print(f"{source} is dependent of {destination}: {is_dependent(source, destination, contract)}")
assert not is_dependent(source, destination, contract)
print(f"{destination} is dependent of {source}: {is_dependent(destination, source, contract)}")
assert is_dependent(destination, source, contract)
print(f"{source} is tainted {is_tainted(source, contract)}")
assert not is_tainted(source, contract)
print(f"{destination} is tainted {is_tainted(destination, contract)}")
assert is_tainted(destination, contract)

contracts = slither.get_contract_from_name("Reference")
assert len(contracts) == 1
contract = contracts[0]
destination = contract.get_state_variable_from_name("destination")
assert destination
source = contract.get_state_variable_from_name("source")
assert source

print("Reference contract")
print(f"{source} is dependent of {destination}: {is_dependent(source, destination, contract)}")
assert not is_dependent(source, destination, contract)
print(f"{destination} is dependent of {source}: {is_dependent(destination, source, contract)}")