示例#1
0
        /// <summary>
        /// Method to create a common taint set from a list of functions
        /// </summary>
        /// <param name="functionList">The list of functions to analyze</param>
        /// <param name="argInfos">The argument ExpressionInfo to include in the analysis</param>
        /// <returns>A common worst-case TaintSets</returns>
        private ExpressionInfo CreateCommonTaintSets(IEnumerable <Function> functionList, IList <ExpressionInfo> argInfos)
        {
            //Create a common TaintSets that will be merged with the TaintSets from the found functions
            var exprInfo = new ExpressionInfo();

            if (functionList.Any())
            {
                AnalyzedFunctions.Add(functionList.First().Name);
                foreach (var func in functionList)
                {
                    var summary = MatchWithFunctionSummary(func, argInfos);

                    if (summary == null)
                    {
                        var taintSetsForFuncOrMethod = GetTaintSetsForFuncOrMethod(func, argInfos);
                        exprInfo = exprInfo.Merge(taintSetsForFuncOrMethod);

                        GenerateSummary(func, argInfos, taintSetsForFuncOrMethod);
                    }
                    else
                    {
                        exprInfo = exprInfo.Merge(summary.ReturnValue);
                    }
                }
            }
            else
            {
                // If function cannot be resolve, use the arguments taint values.
                exprInfo = argInfos.Aggregate(exprInfo, (current, arg) => current.Merge(arg));
            }
            return(exprInfo);
        }
示例#2
0
        /// <summary>
        /// Make sure that hardcoded callback functions are analyzed.
        /// </summary>
        private ExpressionInfo HandleHookCall(XmlNode node, ExpressionInfo exprInfo, IVariableStorage currentStorage, AnalysisStacks analysisStacks)
        {
            var functionCall = new FunctionCallExtractor().ExtractFunctionCall(node);
            var result       = new ExpressionInfo();

            foreach (var argument in functionCall.Arguments.Where(a => a.Value.LocalName == AstConstants.Nodes.Scalar_String))
            {
                var stringValue      = ScalarNode.GetStringValue(argument.Value);
                var functionAnalyzer = FunctionMethodAnalyzerFactory(currentStorage);
                var functions        = functionAnalyzer.FunctionsHandler.LookupFunction(stringValue);
                if (functions.Any())
                {
                    //Console.WriteLine("FOUND " + functions.Count() + " functions with name: " + stringValue);
                    var call = new FunctionCall(stringValue, null, AstNode.GetStartLine(node), AstNode.GetEndLine(node));

                    if (analysisStacks.CallStack.Any(c => c.Name == call.Name))
                    {
                        // Avoid recursive registrations.
                        continue;
                    }
                    analysisStacks.CallStack.Push(call);
                    var funcCallResult = functionAnalyzer.AnalyzeFunctionCall(call, new ExpressionInfo[0]);
                    analysisStacks.CallStack.Pop();

                    result = result.Merge(funcCallResult);
                }

                // https://codex.wordpress.org/Function_Reference/add_submenu_page
                // If a method is called, it is called with: array( $this, 'function_name' ) or array( __CLASS__, 'function_name' )
            }
            return(result);
        }
示例#3
0
        /// <summary>
        /// Analyses a custom function in for security issues, with the currenctly known taint for actual parameters.
        /// </summary>
        /// <returns>A TainSets for the custom function that is being analyzed</returns>
        /// <param name="customFunction">Custom function object to perform the analysis on</param>
        /// <param name="varStorage">The currently known variable storage (this is to included because of superglobals, globals etc.)</param>
        /// <param name="paramActualVals">Parameter actual values</param>
        /// <param name="resolver">File inclusion resolver</param>
        /// <param name="includeStack">Currently known includes</param>
        /// <param name="functionCalls">Currently known function calls</param>
        internal ExpressionInfo AnalyseCustomFunction(Function customFunction, ImmutableVariableStorage varStorage, IVulnerabilityStorage vulnerabilityStorage,
                                                      IList <ExpressionInfo> paramActualVals, IIncludeResolver resolver, AnalysisStacks stacks)
        {
            var stmts = customFunction.AstNode.GetSubNode(AstConstants.Subnode + ":" + AstConstants.Subnodes.Stmts).FirstChild;

            var traverser  = new XmlTraverser();
            var cfgcreator = new CFGCreator();

            traverser.AddVisitor(cfgcreator);
            traverser.Traverse(stmts);

            var cfgPruner = new CFGPruner();

            cfgPruner.Prune(cfgcreator.Graph);

            var initialTaint = varStorage.ToMutable();

            initialTaint.SuperGlobals.Clear();
            initialTaint.SuperGlobals.AddRange(varStorage.SuperGlobals);
            initialTaint.LocalVariables.Clear();
            initialTaint.LocalAccessibleGlobals.Clear();

            for (int i = 1; i <= paramActualVals.Count; i++)
            {
                var paramFormal = customFunction.Parameters.FirstOrDefault(x => x.Key.Item1 == i);
                if (paramFormal.Value == null)
                {
                    continue;
                }
                var @var = new Variable(paramFormal.Value.Name, VariableScope.Function)
                {
                    Info = paramActualVals[i - 1].ValueInfo
                };
                initialTaint.LocalVariables.Add(paramFormal.Value.Name, @var);
            }

            var blockAnalyzer = new TaintBlockAnalyzer(vulnerabilityStorage, resolver, AnalysisScope.Function, fileAnalyzer, stacks, subroutineAnalyzerFactory, _funcHandler);

            blockAnalyzer.AnalysisExtensions.AddRange(AnalysisExtensions);
            var condAnalyser     = new ConditionTaintAnalyser(AnalysisScope.Function, resolver, stacks.IncludeStack, _funcHandler);
            var cfgTaintAnalysis = new TaintAnalysis(blockAnalyzer, condAnalyser, ImmutableVariableStorage.CreateFromMutable(initialTaint));
            //var taintAnalysis = new CFGTraverser(new ForwardTraversal(), cfgTaintAnalysis, new QueueWorklist());
            var taintAnalysis = new CFGTraverser(new ForwardTraversal(), cfgTaintAnalysis, new ReversePostOrderWorkList(cfgcreator.Graph));

            taintAnalysis.Analyze(cfgcreator.Graph);

            var exprInfoAll = new ExpressionInfo();

            foreach (ExpressionInfo exprInfo in blockAnalyzer.ReturnInfos)
            {
                exprInfoAll = exprInfoAll.Merge(exprInfo);
            }

            return(exprInfoAll);
        }
示例#4
0
        public void ExpressionInfo_Merge()
        {
            var sqliTaint = new SQLITaintSet(SQLITaint.SQL_ALL);
            var xsstaint = new XSSTaintSet(XSSTaint.XSS_ALL);
            var ts1 = new TaintSets(sqliTaint, xsstaint);
            var exprInfo1 = new ExpressionInfo { ExpressionTaint = ts1 };
            var exprInfo2 = new ExpressionInfo();

            var exprInfo = exprInfo2.Merge(exprInfo1);

            Assert.AreEqual(sqliTaint, exprInfo.ExpressionTaint.SqliTaint.Single(), "SQL Taint was not the expected");
            Assert.AreEqual(xsstaint, exprInfo.ExpressionTaint.XssTaint.Single(), "XSS Taint was not the expected");
        }
示例#5
0
        /// <summary>
        /// Method to analyze a PHP method call with the class name included
        /// </summary>
        /// <param name="methodCall">The method call to analyze</param>
        /// <param name="argInfos">The argument infos to include in the analysis</param>
        /// <returns>The common TaintSets found</returns>
        public ExpressionInfo AnalyzeMethodCall(MethodCall methodCall, IList <ExpressionInfo> argInfos)
        {
            //In most cases there should be either 0 or 1 classes, but situations where functions are specified several places can happen.
            //Therefore, we support it and select the worst case.
            var exprInfo = new ExpressionInfo();

            //Try to find all the possible method calls, and create the worst case scenario of taints.
            foreach (string className in methodCall.ClassNames)
            {
                IList <Function> funclist = _funcHandler.LookupFunction(methodCall.CreateFullMethodName(className));
                exprInfo = exprInfo.Merge(CreateCommonTaintSets(funclist, argInfos));
            }

            return(exprInfo);
        }
示例#6
0
        public void ExpressionInfo_Merge()
        {
            var sqliTaint = new SQLITaintSet(SQLITaint.SQL_ALL);
            var xsstaint  = new XSSTaintSet(XSSTaint.XSS_ALL);
            var ts1       = new TaintSets(sqliTaint, xsstaint);
            var exprInfo1 = new ExpressionInfo {
                ExpressionTaint = ts1
            };
            var exprInfo2 = new ExpressionInfo();

            var exprInfo = exprInfo2.Merge(exprInfo1);

            Assert.AreEqual(sqliTaint, exprInfo.ExpressionTaint.SqliTaint.Single(), "SQL Taint was not the expected");
            Assert.AreEqual(xsstaint, exprInfo.ExpressionTaint.XssTaint.Single(), "XSS Taint was not the expected");
        }
示例#7
0
        /// <summary>
        /// Method to get the TaintSets for a single function.
        /// </summary>
        /// <param name="func">The function to find the TaintSets for</param>
        /// <param name="argInfos">The argument ExpressionInfo to include in the analysis</param>
        /// <returns>The found TaintSets for the function</returns>
        private ExpressionInfo GetTaintSetsForFuncOrMethod(Function func, IList <ExpressionInfo> argInfos)
        {
            //Start working from the bast case, and find worser cases.
            var tmp = new ExpressionInfo();

            //Try to cast the function to every possible function/method
            var xssSantizerFunc = CastToFunctionType <XSSSanitizer>(func);
            var sqlSantizerFunc = CastToFunctionType <SQLSanitizer>(func);

            //We have to find customFunctions explicitly as it can always be casted to a Function, as it is the base class.
            //However if we introduce a custom function class then it can be castet to this type, and work like the rest.
            Function customFunc = _funcHandler.FindCustomFunctionByName(func.Name);

            //If there exists a Source with the function name, then we select it.
            //But sources and be of several other types, like arrays etc.
            Source sourceFunc = _funcHandler.FindSourceByName(func.Name);

            //TODO: This should be changed to be dependent on parameters!!!
            if (xssSantizerFunc != null)
            {
                SQLITaintSet sqliTaintSet     = new SQLITaintSet();
                XSSTaintSet  xssts            = new XSSTaintSet();
                var          returnParameters = xssSantizerFunc.Parameters.Where(x => x.Value.IsReturn);
                try
                {
                    ExpressionInfo returnParameter = new ExpressionInfo();
                    foreach (var item in returnParameters)
                    {
                        var actualParam = argInfos.ElementAt((int)item.Key.Item1 - 1);
                        if (actualParam == null)
                        {
                            continue;
                        }
                        returnParameter = returnParameter.Merge(actualParam);
                    }
                    sqliTaintSet = returnParameter.ExpressionTaint.SqliTaint.Aggregate(sqliTaintSet, (current, taint) => current.Merge(taint));
                    xssts        = returnParameter.ExpressionTaint.XssTaint.Aggregate(xssts, (current, taint) => current.Merge(taint));
                }
                catch (NullReferenceException)
                {
                    Debug.WriteLine("Could not map actual parameter with formal parameter, using default");
                    sqliTaintSet = new SQLITaintSet();
                    xssts        = argInfos.Aggregate(xssts, (current1, info) => current1.Merge(info.ExpressionTaint.XssTaint.Aggregate(current1, (current, taint) => current.Merge(taint))));
                }
                tmp = new ExpressionInfo()
                {
                    ExpressionTaint = new TaintSets(
                        sqliTaintSet,
                        xssSantizerFunc.DefaultStatus < xssts.TaintTag ? new XSSTaintSet(xssSantizerFunc.DefaultStatus) : xssts.DeepClone())
                };
            }
            if (sqlSantizerFunc != null)
            {
                XSSTaintSet  xssts            = new XSSTaintSet();
                SQLITaintSet sqlts            = new SQLITaintSet();
                var          returnParameters = sqlSantizerFunc.Parameters.Where(x => x.Value.IsReturn);
                try
                {
                    ExpressionInfo returnParameter = new ExpressionInfo();
                    foreach (var item in returnParameters)
                    {
                        var actualParam = argInfos.ElementAt((int)item.Key.Item1 - 1);
                        if (actualParam == null)
                        {
                            continue;
                        }
                        returnParameter = returnParameter.Merge(actualParam);
                    }
                    xssts = returnParameter.ExpressionTaint.XssTaint.Aggregate(xssts, (current, taint) => current.Merge(taint));
                    sqlts = returnParameter.ExpressionTaint.SqliTaint.Aggregate(sqlts, (current, taint) => current.Merge(taint));
                }
                catch (NullReferenceException)
                {
                    Debug.WriteLine("Could not map actual parameter with formal parameter, using default");
                    xssts = new XSSTaintSet();
                    sqlts = argInfos.Aggregate(sqlts, (current1, info) => current1.Merge(info.ExpressionTaint.SqliTaint.Aggregate(current1, (current, taint) => current.Merge(taint))));
                }
                tmp = new ExpressionInfo()
                {
                    ExpressionTaint = new TaintSets(
                        sqlSantizerFunc.DefaultStatus < sqlts.TaintTag ? new SQLITaintSet(sqlSantizerFunc.DefaultStatus) : sqlts.DeepClone(),
                        xssts)
                };
            }
            if (customFunc != null)
            {
                _funcHandler.ScannedFunctions.Add(customFunc);
                tmp = this._customFunctionHandler.AnalyseCustomFunction(customFunc, this._varStorage, _vulnerabilityStorage, argInfos, this._incResolver, this._stacks);
            }
            if (sourceFunc != null)
            {
                tmp = new ExpressionInfo()
                {
                    ExpressionTaint = new TaintSets(sourceFunc.SqliTaint, sourceFunc.XssTaint)
                };
            }

            //If no matches were found the function is unknown and therefore we return the worst case of them all!
            return(tmp);
        }
示例#8
0
        private ExpressionInfo Node_MethodCall(XmlNode node)
        {
            var functionCallExtractor = new FunctionCallExtractor();
            var methodCall = functionCallExtractor.ExtractMethodCall(node, this._variableStorage, this._analysisScope);

            bool isAlreadyInStack = _analysisStacks.CallStack.Any(x => x.Name == methodCall.Name);
            _analysisStacks.CallStack.Push(methodCall);

            var argInfos = new List<ExpressionInfo>();

            //Actually analyze the arguments
            for (uint index = 1; index <= methodCall.Arguments.Count; index++)
            {
                var item = methodCall.Arguments.FirstOrDefault(x => x.Key == index);
                var exprInfo = this.Analyze(item.Value);
                if (_varResolver.IsResolvableNode(item.Value))
                {
                    var @var = _varResolver.ResolveVariable(item.Value);
                    exprInfo.ValueInfo = @var.Variable.Info;
                }
                argInfos.Add(exprInfo);
            }

            if (methodCall.Name == "")
            {
                var exprInfo = new ExpressionInfo();
                _analysisStacks.CallStack.Pop();
                return argInfos.Aggregate(exprInfo, (current, info) => current.Merge(info));
            }

            var customFunctionHandler = new CustomFunctionHandler(this._analyzer, _subroutineAnalyzerFactory);
            customFunctionHandler.AnalysisExtensions.AddRange(this.AnalysisExtensions);
            var functionMethodAnalyzer = _subroutineAnalyzerFactory.Create(ImmutableVariableStorage.CreateFromMutable(_variableStorage),
                _inclusionResolver, _analysisStacks, customFunctionHandler, _vulnerabilityStorage);

            var methodCallTaintSet = new ExpressionInfo();
            if(!isAlreadyInStack)
            {
                methodCallTaintSet = functionMethodAnalyzer.AnalyzeMethodCall(methodCall, argInfos);
            }

            FunctionsHandler fh = FunctionsHandler.Instance;
            var resultTaintSet = new ExpressionInfo();
            foreach (var className in methodCall.ClassNames.Distinct())
            {
                var tempResultTaintSet = methodCallTaintSet.AssignmentClone();
                var sqlSaniFunc = fh.FindSQLSanitizerByName(methodCall.CreateFullMethodName(className));
                var sqlSinkFunc = fh.FindSQLSinkByName(methodCall.CreateFullMethodName(className));
                var xssSaniFunc = fh.FindXSSSanitizerByName(methodCall.CreateFullMethodName(className));
                var xssSinkFunc = fh.FindXSSSinkByName(methodCall.CreateFullMethodName(className));

                if (sqlSaniFunc != null && sqlSaniFunc.DefaultStatus == SQLITaint.None)
                {
                    resultTaintSet.ExpressionTaint.SqliTaint.Clear();
                }
                if (xssSaniFunc != null && xssSaniFunc.DefaultStatus == XSSTaint.None)
                {
                    resultTaintSet.ExpressionTaint.XssTaint.Clear();
                }
                if (sqlSinkFunc != null || xssSinkFunc != null)
                {
                    if (sqlSinkFunc != null)
                    {
                        var vulnerableSqlParams = sqlSinkFunc.Parameters.Where(x => x.Value.IsSensitive)
                                                                        .ToDictionary(pair => pair.Key);
                        var parameters = methodCall.Arguments.Where(x => vulnerableSqlParams.Keys.Any(z => z.Item1 == x.Key));

                        foreach (var parameter in parameters)
                        {
                            //var argInfo = Analyze(parameter.Value);
                            var argInfo = argInfos.ElementAt((int)(parameter.Key - 1));
                            CheckForSQLVulnerabilities(argInfo, parameter.Value);
                        }
                        if (sqlSinkFunc.ReturnType == "object" || sqlSinkFunc.ReturnType == "mix")
                        {
                            resultTaintSet.ValueInfo.ClassNames.AddRange(sqlSinkFunc.Classnames);
                        }
                    }
                    if (xssSinkFunc != null)
                    {
                        var vulnerableXssParams = xssSinkFunc.Parameters.Where(x => x.Value.IsSensitive).ToDictionary(pair => pair.Key);
                        var param = methodCall.Arguments.Where(x => vulnerableXssParams.Keys.Any(z => z.Item1 == x.Key));

                        foreach (var parameter in param)
                        {
                            var argInfo = argInfos.ElementAt((int)(parameter.Key - 1));
                            CheckForXssVulnerabilities(argInfo, parameter.Value);
                        }
                    }
                    // Assuming sinks does not return taint.
                    resultTaintSet.ExpressionTaint.ClearTaint();
                    resultTaintSet.ExpressionStoredTaint.Taint.ClearTaint();
                }
                tempResultTaintSet = StoredMethodHandler(tempResultTaintSet, node);
                resultTaintSet = resultTaintSet.Merge(tempResultTaintSet);

                var methodNameWithClass = methodCall.CreateFullMethodName(className);
                bool isStoredProvider = FunctionsHandler.Instance.FindStoredProviderMethods(methodNameWithClass).Any();
                if (isStoredProvider)
                {
                    resultTaintSet.ExpressionStoredTaint = resultTaintSet.ExpressionStoredTaint.Merge(methodCall.Var.Info.PossibleStoredTaint);
                    //TODO: The following is not true in all cases.
                    // What cases?
                    var cloned = resultTaintSet.ExpressionStoredTaint.Taint.DeepClone();
                    resultTaintSet.ValueInfo.NestedVariablePossibleStoredDefaultTaintFactory = () => cloned;
                }
            }

            _analysisStacks.CallStack.Pop();
            return resultTaintSet;
        }
示例#9
0
        /// <summary>
        /// Analyses a custom function in for security issues, with the currenctly known taint for actual parameters.
        /// </summary>
        /// <returns>A TainSets for the custom function that is being analyzed</returns>
        /// <param name="customFunction">Custom function object to perform the analysis on</param>
        /// <param name="varStorage">The currently known variable storage (this is to included because of superglobals, globals etc.)</param>
        /// <param name="paramActualVals">Parameter actual values</param>
        /// <param name="resolver">File inclusion resolver</param>
        /// <param name="includeStack">Currently known includes</param>
        /// <param name="functionCalls">Currently known function calls</param>
        internal ExpressionInfo AnalyseCustomFunction(Function customFunction, ImmutableVariableStorage varStorage, IVulnerabilityStorage vulnerabilityStorage,
            IList<ExpressionInfo> paramActualVals, IIncludeResolver resolver, AnalysisStacks stacks)
        {
            var stmts = customFunction.AstNode.GetSubNode(AstConstants.Subnode + ":" + AstConstants.Subnodes.Stmts).FirstChild;

            var traverser = new XmlTraverser();
            var cfgcreator = new CFGCreator();
            traverser.AddVisitor(cfgcreator);
            traverser.Traverse(stmts);

            var cfgPruner = new CFGPruner();
            cfgPruner.Prune(cfgcreator.Graph);

            var initialTaint = varStorage.ToMutable();
            initialTaint.SuperGlobals.Clear();
            initialTaint.SuperGlobals.AddRange(varStorage.SuperGlobals);
            initialTaint.LocalVariables.Clear();
            initialTaint.LocalAccessibleGlobals.Clear();

            for(int i = 1; i <= paramActualVals.Count; i++)
            {
                var paramFormal = customFunction.Parameters.FirstOrDefault(x => x.Key.Item1 == i);
                if (paramFormal.Value == null)
                {
                    continue;
                }
                var @var = new Variable(paramFormal.Value.Name, VariableScope.Function) {Info = paramActualVals[i - 1].ValueInfo};
                initialTaint.LocalVariables.Add(paramFormal.Value.Name, @var);
            }

            var blockAnalyzer = new TaintBlockAnalyzer(vulnerabilityStorage, resolver, AnalysisScope.Function, fileAnalyzer, stacks, subroutineAnalyzerFactory);
            blockAnalyzer.AnalysisExtensions.AddRange(AnalysisExtensions);
            var condAnalyser = new ConditionTaintAnalyser(AnalysisScope.Function, resolver, stacks.IncludeStack);
            var cfgTaintAnalysis = new TaintAnalysis(blockAnalyzer, condAnalyser, ImmutableVariableStorage.CreateFromMutable(initialTaint));
            //var taintAnalysis = new CFGTraverser(new ForwardTraversal(), cfgTaintAnalysis, new QueueWorklist());
            var taintAnalysis = new CFGTraverser(new ForwardTraversal(), cfgTaintAnalysis, new ReversePostOrderWorkList(cfgcreator.Graph));
            taintAnalysis.Analyze(cfgcreator.Graph);

            var exprInfoAll = new ExpressionInfo();

            foreach (ExpressionInfo exprInfo in blockAnalyzer.ReturnInfos)
            {
                exprInfoAll = exprInfoAll.Merge(exprInfo);
            }

            return exprInfoAll;
        }
示例#10
0
        /// <summary>
        /// Make sure that hardcoded callback functions are analyzed.
        /// </summary>
        private ExpressionInfo HandleHookCall(XmlNode node, ExpressionInfo exprInfo, IVariableStorage currentStorage, AnalysisStacks analysisStacks)
        {
            var functionCall = new FunctionCallExtractor().ExtractFunctionCall(node);
            var result = new ExpressionInfo();

            foreach (var argument in functionCall.Arguments.Where(a => a.Value.LocalName == AstConstants.Nodes.Scalar_String))
            {
                var stringValue = ScalarNode.GetStringValue(argument.Value);
                var functions = FunctionsHandler.Instance.LookupFunction(stringValue);
                if (functions.Any())
                {
                    //Console.WriteLine("FOUND " + functions.Count() + " functions with name: " + stringValue);
                    var functionAnalyzer = this.FunctionMethodAnalyzerFactory(currentStorage);
                    var call = new FunctionCall(stringValue, null, AstNode.GetStartLine(node), AstNode.GetEndLine(node));

                    if (analysisStacks.CallStack.Any(c => c.Name == call.Name))
                    {
                        // Avoid recursive registrations.
                        continue;
                    }
                    analysisStacks.CallStack.Push(call);
                    var funcCallResult = functionAnalyzer.AnalyzeFunctionCall(call, new ExpressionInfo[0]);
                    analysisStacks.CallStack.Pop();

                    result = result.Merge(funcCallResult);
                }

                // https://codex.wordpress.org/Function_Reference/add_submenu_page
                // If a method is called, it is called with: array( $this, 'function_name' ) or array( __CLASS__, 'function_name' )

            }
            return result;
        }