def analyser(self):
        
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Tainted Variables >>>>>>>>>>")
        
        externalFunctions = AnalyseFunctionDefinition.getAllFunctionDefinitionsWithExternalVisibility()
        publicFunctions = AnalyseFunctionDefinition.getAllFunctionDefinitionsWithPublicVisibility()
        taintedFunctions = externalFunctions + publicFunctions

        taintedVariables = defaultdict(list)
        for function in taintedFunctions:
            taintFlow = TaintPropagate.getTaintPropagationForFunction(function)            
            for item in taintFlow:
                _in = MySet()
                _out = []
                if(item["in"] is not None):
                    for var in item["in"]._set:
                        if(AnalyseVariable.getVariableNameForId(var) != "Error"):
                            _in.add(AnalyseVariable.getVariableNameForId(var), item["in"].idToNodeMapping[var].src)
                if(item["out"] is not None):
                    for var in item["out"]._set:
                        if(AnalyseVariable.getVariableNameForId(var) != "Error"):
                            _out.append(AnalyseVariable.getVariableNameForId(var))

                print("At line: " + str(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0]))))

                for var in _in._set:
                    print(" Incoming tainted variable: " + var + " defined at line:" + str(mapASTSourceToLineNumbers.getLine(int(_in.idToNodeMapping[var].split(":",)[0]))))
                print(" Outgoing tainted variables: " + str(_out))
                self.statsTaintedVariables.append({
                    "line":str(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0]))),
                    "info":_out,
                })
Exemplo n.º 2
0
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Unchecked Calls >>>>>>>>>>")

        calls = AnalyseExpression.getAllCalls()
        for call in calls:
            print("call() at line:" + str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))))
            node = call.parent
            checked = False
            while(node.nodeType != "ContractDefinition"):
                if(node.nodeType == "FunctionCall" and (node.name == "assert" or node.name == "require")):
                    self.statsAssertCheckedCalls.append({
                        "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))),
                        "info":"assert checked call"
                    })
                    print("call checked with assert() or require()")
                    checked = True
                    break
                if((node.nodeType == "UnaryOperation" or node.nodeType == "BinaryOperation") and node.type == "ifStatementCondition"):
                    self.statsConditionalCheckedCalls.append({
                        "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))),
                        "info":"conditional checked call"
                    })
                    print("call checked with conditional if()")
                    checked = True
                    break
                node = node.parent
            if(checked):
                continue
            else:
                self.statsUncheckedCalls.append({
                    "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))),
                    "info":"Unchecked call"
                })
                print("Unchecked call()")
 def analyser(self):
     mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
     print("\n<<<<<<<<<< Analyser: Contract Features >>>>>>>>>>")
     
     contracts = AnalyseContract.getAllContracts()
     for contract in contracts:
         self.statsContractDefinitions.append({
             "line":str(mapASTSourceToLineNumbers.getLine(int(contract.src.split(":",)[0]))),
             "info":"contract definition"
         })
         print("\n********** Contract Features **********")
         print("Contract definition: " + contract.name  + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(contract.src.split(":",)[0]))))
     
     functionDefinitions = AnalyseFunctionDefinition.getAllFunctionDefinitions()
     for function in functionDefinitions:
         self.statsFunctionDefinitions.append({
             "line":str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))),
             "info":"function definition"
         })
         print("\n********** Function Features **********")
         print("Function definition: " + function.name  + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))))
         if (function.isConstructor):
             self.statsConstructors.append({
                 "line":str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))),
                 "info":"constructor definition"
             })
             print("Constructor")
         print("Visibility: " + function.visibility)
         print("State Mutability: " + function.stateMutability)
         if (AnalyseFunctionDefinition.isFallbackFunction(function)):
             self.statsFallbackFunctions.append({
                 "line":str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))),
                 "info":"fallback definition"
             })
             print("Fallback function")
         if (AnalyseFunctionDefinition.isPayableFallbackFunction(function)):
             print("Payable Fallback function")
         modifiers = function.modifiers
         for modifier in modifiers:
             print("Modifier: " + modifier['modifierName']['name'])
                 
     variableDeclarations = AnalyseVariable.getAllVariables()
     for variable in variableDeclarations:
         self.statsVariableDeclarations.append({
             "line":str(mapASTSourceToLineNumbers.getLine(int(variable.src.split(":",)[0]))),
             "info":"variable declaration"
         })
         print("\n********** Variable Features **********")
         print("Variable declaration: " + variable.name  + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(variable.src.split(":",)[0]))))
         if (variable.stateVariable):
             self.statsStateVariables.append({
                 "line":str(mapASTSourceToLineNumbers.getLine(int(variable.src.split(":",)[0]))),
                 "info":"state variable declaration"
             })
             print("State variable")
         else:
             if (variable.parent.nodeType == "FunctionDefinition"):
                 print("Function parameter")
             else:
                 print("Local variable")
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Default Visibility >>>>>>>>>>")

        functionDefinitions = AnalyseFunctionDefinition.getAllFunctionDefinitions(
        )
        for function in functionDefinitions:
            if (function.visibility == "public"):
                # Determine if "public" visibility was explicitly specified or implicitly inferred
                # Check if "public" keyword is present between input parameters and return parameters
                parametersSrc = function.parameters.get("src")
                returnParametersSrc = function.returnParameters.get("src")
                found = mapASTSourceToLineNumbers.chkStringPresent(
                    "public", parametersSrc, returnParametersSrc)
                if (not found):
                    self.statsDefaultVisibilityForFunction.append({
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(function.src.split(":", )[0]))),
                        "info":
                        "default public visibility for function"
                    })
                    print("Default public visibility for Function: " +
                          function.name + " at line:" + str(
                              mapASTSourceToLineNumbers.getLine(
                                  int(function.src.split(":", )[0]))))

        variableDeclarations = AnalyseVariable.getAllVariables()
        for variable in variableDeclarations:
            if (variable.visibility == "internal" and
                (not (variable.parent.nodeType == "FunctionDefinition"))):
                # Determine if "internal" visibility was explicitly specified or implicitly inferred
                # Check if "internal" keyword is present between type and variable name
                variableSrc = variable.src
                typeSrc = variable.typeName.get("src")
                found = mapASTSourceToLineNumbers.chkStringPresentVariableVisibility(
                    "internal", typeSrc, variableSrc)
                if (not found):
                    self.statsDefaultVisibilityForVariable.append({
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(variable.src.split(":", )[0]))),
                        "info":
                        "default public visibility for variable"
                    })
                    print("Default internal visibility for Variable: " +
                          variable.name + " at line:" + str(
                              mapASTSourceToLineNumbers.getLine(
                                  int(variable.src.split(":", )[0]))))
Exemplo n.º 5
0
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Control Flow Graph >>>>>>>>>>")

        functionCalls = AnalyseFunctionCall.getAllFunctionCalls()
        for functionCall in functionCalls:
            found = True
            if (functionCall.name is not None):
                logging.debug("functionCall: " + functionCall.name)
                node = functionCall.parent
                while (node.nodeType != "FunctionDefinition"):
                    node = node.parent
                    if (isinstance(node, AST)):
                        found = False
                        break
                if (found):
                    self.controlFlowGraph.append({
                        "callerName":
                        node.name,
                        "calleeName":
                        functionCall.name,
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(functionCall.src.split(":", )[0])))
                    })

        for item in self.controlFlowGraph:
            print(item)
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Unchecked Selfdestructs >>>>>>>>>>")

        functionCalls = AnalyseFunctionCall.getAllFunctionCalls()
        for functionCall in functionCalls:
            if (functionCall.name == "selfdestruct"):
                print("selfdestruct() at line:" + str(
                    mapASTSourceToLineNumbers.getLine(
                        int(functionCall.src.split(":", )[0]))))
                node = functionCall.parent
                checked = False
                while (node.nodeType != "ContractDefinition"):
                    if (
                            node.nodeType == "IfStatement"
                    ):  # Add check for ifStatementCondition containing ownership check via msg.sender
                        self.statsConditionalCheckedSelfdestructs.append({
                            "line":
                            str(
                                mapASTSourceToLineNumbers.getLine(
                                    int(functionCall.src.split(":", )[0]))),
                            "info":
                            "conditional checked selfdestruct"
                        })
                        print(
                            "selfdestruct likely checked with conditional if()"
                        )
                        checked = True
                        break
                    # Add check for Function Definition containing ownership check in a modifer via msg.sender
                    node = node.parent
                if (checked):
                    continue
                else:
                    self.statsUncheckedSelfdestructs.append({
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(functionCall.src.split(":", )[0]))),
                        "info":
                        "Unchecked selfdestruct"
                    })
                    print("Unchecked selfdestruct()")
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Unchecked Deprecated Constructs >>>>>>>>>>")

        print("\n********** Use of tx.origin **********")
        constructs = AnalyseExpression.getAllTxOrigins()
        for construct in constructs:
            self.statsTxOrigin.append({
                "line":str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0]))),
                "info":"tx.origin"
            })
            print("tx.origin at line:" + str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0]))))


        print("\n********** Use of block.<member> where member is number/hash/gaslimit/coinbase/timestamp **********")
        constructs = AnalyseExpression.getAllBlockMembers()
        for construct in constructs:
            self.statsBlockMembers.append({
                "line":str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0]))),
                "info":"block.<member>"
            })
            print("Predictable block member at line:" + str(mapASTSourceToLineNumbers.getLine(int(construct.src.split(":",)[0]))))
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print(
            "\n<<<<<<<<<< Analyser: Uninitialised Storage Variables >>>>>>>>>>"
        )

        variables = AnalyseVariable.getAllVariables()

        for variable in variables:
            logging.debug("Variable: " + str(variable))
            logging.debug("stateVariable: " + str(variable.stateVariable))
            logging.debug("storageLocation: " + variable.storageLocation)
            logging.debug("type: " +
                          variable.typeDescriptions.get("typeIdentifier"))
            isVariableUninitialised = True
            parent = variable.parent
            if ((parent.nodeType == "VariableDeclarationStatement"
                 and parent.initialValue != None)
                    or parent.nodeType == "FunctionDefinition"):
                isVariableUninitialised = False
            if (variable.stateVariable is False and isVariableUninitialised and
                (variable.storageLocation == "storage" or
                 (variable.storageLocation == "default" and
                  ("struct" in variable.typeDescriptions.get("typeIdentifier")
                   or "array" in variable.typeDescriptions.get(
                       "typeIdentifier") or "mapping"
                   in variable.typeDescriptions.get("typeIdentifier"))))):
                self.statsUninitialisedStoragePointers.append({
                    "line":
                    str(
                        mapASTSourceToLineNumbers.getLine(
                            int(variable.src.split(":", )[0]))),
                    "info":
                    "uninitialised storage pointer"
                })
                print("Uninitialised storage pointer " + variable.name +
                      " at line:" + str(
                          mapASTSourceToLineNumbers.getLine(
                              int(variable.src.split(":", )[0]))))
 def analyser(self):
     expressions = AnalyseExpression.getAllExpressions()
     mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
     print("\n<<<<<<<<<< Analyser: Reentrancy >>>>>>>>>>")
     
     calls = AnalyseExpression.getAllCalls()
     for call in calls:
         logging.debug("Call at line:" + str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))))
         parent = call.parent
         found = False
         defs = []
         while(True):
             if (parent.nodeType == "ExpressionStatement"):
                 logging.debug("Found ExpressionStatement: " + str(parent.id))
                 found = True
                 break
             if (parent.nodeType == "ContractDefinition"):
                 break
             parent = parent.parent
         if (found):
             defs = DefUseAnalysis.getAllDefintionsAfterStatement(parent)
         defsOfStateVariables = []
         for _def in defs:
             logging.debug("_def: " + str(_def))
             logging.debug("Def: " + _def["name"] + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(_def["src"].split(":",)[0]))))
             variableID = _def["referencedDeclaration"]
             variables = AnalyseVariable.getAllVariables()
             for variable in variables:
                 if (variableID == variable.id and variable.stateVariable):
                     defsOfStateVariables.append(_def)
         if (len(defsOfStateVariables) != 0):
             self.statsPotentialReentrancy.append({
                 "line":str(mapASTSourceToLineNumbers.getLine(int(call.src.split(":",)[0]))),
                 "info":"potential reentrancy: state change after call()"
             })
             print("Potential Reentrancy: State change after call()")
         else:
             print("No Reentrancy: No state change after call()")
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Exceptions >>>>>>>>>>")

        requires = AnalyseFunctionCall.getAllRequires()
        print("Number of require(): " + str(len(requires)))
        for require in requires:
            print("require() " + " at line:" + str(
                mapASTSourceToLineNumbers.getLine(
                    int(require.src.split(":", )[0]))))
            self.statsRequires.append({
                "line":
                str(
                    mapASTSourceToLineNumbers.getLine(
                        int(require.src.split(":", )[0]))),
                "info":
                "require"
            })

        asserts = AnalyseFunctionCall.getAllAsserts()
        print("Number of assert(): " + str(len(asserts)))
        for _assert in asserts:
            print("assert() " + " at line:" + str(
                mapASTSourceToLineNumbers.getLine(
                    int(_assert.src.split(":", )[0]))))
            self.statsAsserts.append({
                "line":
                str(
                    mapASTSourceToLineNumbers.getLine(
                        int(_assert.src.split(":", )[0]))),
                "info":
                "assert"
            })

        reverts = AnalyseFunctionCall.getAllReverts()
        print("Number of revert(): " + str(len(reverts)))
        for revert in reverts:
            print("revert() " + " at line:" + str(
                mapASTSourceToLineNumbers.getLine(
                    int(revert.src.split(":", )[0]))))
            self.statsReverts.append({
                "line":
                str(
                    mapASTSourceToLineNumbers.getLine(
                        int(revert.src.split(":", )[0]))),
                "info":
                "revert"
            })
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: DoS Patterns >>>>>>>>>>")

        print("\n********** DoS Patterns with send()/transfer() **********")
        sends = AnalyseExpression.getAllSends()
        for send in sends:
            print("send() at line:" + str(mapASTSourceToLineNumbers.getLine(int(send.src.split(":",)[0]))))
            node = send.parent
            while(node.nodeType != "ContractDefinition"):
                if(node.nodeType == "WhileStatement" or node.nodeType == "ForStatement"):
                    self.statsDoSWithBlockGasLimit.append({
                        "line":str(mapASTSourceToLineNumbers.getLine(int(send.src.split(":",)[0]))),
                        "info":"send"
                    })
                    print("send() within loops are susceptible to DoS with block gas limit")
                    break
                if((node.nodeType == "FunctionCall" and node.name == "require")):
                    self.statsDoSWithUnexpectedRevert.append({
                        "line":str(mapASTSourceToLineNumbers.getLine(int(send.src.split(":",)[0]))),
                        "info":"send"
                    })
                    print("Potential DoS with (unexpected) revert")
                    break
                node = node.parent
        transfers = AnalyseExpression.getAllTransfers()
        for transfer in transfers:
            print("transfer() at line:" + str(mapASTSourceToLineNumbers.getLine(int(transfer.src.split(":",)[0]))))
            self.statsDoSWithUnexpectedRevert.append({
                "line":str(mapASTSourceToLineNumbers.getLine(int(transfer.src.split(":",)[0]))),
                "info":"transfer"
            })
            print("Potential DoS with (unexpected) revert")
            node = transfer.parent
            while(node.nodeType != "ContractDefinition"):
                if(node.nodeType == "WhileStatement" or node.nodeType == "ForStatement"):
                    self.statsDoSWithBlockGasLimit.append({
                        "line":str(mapASTSourceToLineNumbers.getLine(int(transfer.src.split(":",)[0]))),
                        "info":"transfer"
                    })
                    print("transfer() within loops are susceptible to DoS with block gas limit")
                    break
                node = node.parent
Exemplo n.º 12
0
    def analyser(self):
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print("\n<<<<<<<<<< Analyser: Defs and Uses >>>>>>>>>>")
        
        functionDefinitions = AnalyseFunctionDefinition.getAllFunctionDefinitions()

        for function in functionDefinitions:
            print("\n********** Function Defs/Uses **********")
            print("Function definition: " + function.name  + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(function.src.split(":",)[0]))))
            dataflow = DefUseAnalysis.getDataflowForFunction(function)
            if (self.loggingLevel == "DEBUG"):
                print("Dataflow length: " + str(len(dataflow)))
                for item in dataflow:
                    _gen = []
                    _kill = []
                    _in = MySet()
                    _out = []
                    if(item["gen"] is not None and item["gen"]._set is not None):
                        for var in item["gen"]._set:
                            if(AnalyseVariable.getVariableNameForId(var) != "Error"):
                                _gen.append(AnalyseVariable.getVariableNameForId(var))
                    if(item["kill"] is not None):
                        for var in item["kill"]._set:
                            if(AnalyseVariable.getVariableNameForId(var) != "Error"):
                                _kill.append(AnalyseVariable.getVariableNameForId(var))
                    if(item["in"] is not None):
                        for var in item["in"]._set:
                            if(AnalyseVariable.getVariableNameForId(var) != "Error"):
                                _in.add(AnalyseVariable.getVariableNameForId(var), item["in"].idToNodeMapping[var].src)
                    if(item["out"] is not None):
                        for var in item["out"]._set:
                            if(AnalyseVariable.getVariableNameForId(var) != "Error"):
                                _out.append(AnalyseVariable.getVariableNameForId(var))
                    print("Node Id: " +
                          str(item["id"]) + 
                          " at line:" +
                          str(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0]))) +
                          " gen: " + str(_gen) +
                          " kill: " + str(_kill)
                    )
                
                for var in _in._set:
                    print("in: " + var + " defined at line:" + str(mapASTSourceToLineNumbers.getLine(int(_in.idToNodeMapping[var].split(":",)[0]))))
                print(" out: " + str(_out))


            defs = []
            defs = DefUseAnalysis.getAllDefsAtNode(function, defs)
            for _def in defs:
                self.statsDefs.append({
                    "line":str(mapASTSourceToLineNumbers.getLine(int(_def["src"].split(":",)[0]))),
                    "info":_def["name"]
                })
                if(self.loggingLevel == "DEBUG"):
                    print("Def: " + _def["name"] + " at line:" + str(mapASTSourceToLineNumbers.getLine(int(_def["src"].split(":",)[0]))))
            
            uses = []
            uses = DefUseAnalysis.getAllUsesAtNode(function, uses)
            for use in uses:
                self.statsUses.append({
                    "line":str(mapASTSourceToLineNumbers.getLine(int(use["src"].split(":",)[0]))),
                    "info":use["name"]
                })
                print("Use: " +
                      use["name"] +
                      " at line:" + str(mapASTSourceToLineNumbers.getLine(int(use["src"].split(":",)[0]))))
                print(" > Using value from definition on line: ",end='')
                line = mapASTSourceToLineNumbers.getLine(int(use["src"].split(":",)[0]))
                varRef = use["referencedDeclaration"]
                found = False
                for item in dataflow:
                    if(mapASTSourceToLineNumbers.getLine(int(item["src"].split(":",)[0])) == line):
                        if(item["in"] and varRef in item["in"]._set):
                            print(mapASTSourceToLineNumbers.getLine(int(item["in"].idToNodeMapping[varRef].src.split(":",)[0])))
                            found = True
                            break
                if(not found):
                    print("Not Found")
    def analyser(self):
        expressions = AnalyseExpression.getAllExpressions()
        mapASTSourceToLineNumbers = MapASTSourceToLineNumbers()
        print(
            "\n<<<<<<<<<< Analyser: External Contract Interactions >>>>>>>>>>")

        transfers = AnalyseExpression.getAllTransfers()
        for transfer in transfers:
            for child in transfer.children:
                if (child.nodeType == "Identifier"):
                    self.statsTransfers.append({
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(child.src.split(":", )[0]))),
                        "info":
                        "transfer"
                    })
                    print("Transfer to " + child.name + " at line:" + str(
                        mapASTSourceToLineNumbers.getLine(
                            int(child.src.split(":", )[0]))))

        sends = AnalyseExpression.getAllSends()
        for send in sends:
            for child in send.children:
                if (child.nodeType == "Identifier"):
                    self.statsSends.append({
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(child.src.split(":", )[0]))),
                        "info":
                        "send"
                    })
                    print("Send to " + child.name + " at line:" + str(
                        mapASTSourceToLineNumbers.getLine(
                            int(child.src.split(":", )[0]))))

        calls = AnalyseExpression.getAllCalls()
        for call in calls:
            for child in call.children:
                if (child.nodeType == "Identifier"):
                    self.statsCalls.append({
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(child.src.split(":", )[0]))),
                        "info":
                        "call"
                    })
                    print("Call to " + child.name + " at line:" + str(
                        mapASTSourceToLineNumbers.getLine(
                            int(child.src.split(":", )[0]))))

        delegateCalls = AnalyseExpression.getAllDelegateCalls()
        for delegateCall in delegateCalls:
            for child in delegateCall.children:
                if (child.nodeType == "Identifier"):
                    self.statsDelegateCalls.append({
                        "line":
                        str(
                            mapASTSourceToLineNumbers.getLine(
                                int(child.src.split(":", )[0]))),
                        "info":
                        "delegateCall"
                    })
                    print("DelegateCall to " + child.name + " at line:" + str(
                        mapASTSourceToLineNumbers.getLine(
                            int(child.src.split(":", )[0]))))