Beispiel #1
0
        static void ScanDirectory(DirectoryInfo AppDirectory, string RelativeAppPath)
        {
            var ignoreExtensions = new[]
            {
                "png",
                "jpg",
                "jpeg",
                "gif",
                "ico",
                "js",
                "css",
            };

            var urlDictionary = CreateUrlDictionary(RelativeAppPath, AppDirectory);

            var urlCollections = new[]
            {
                urlDictionary.Select(x => x.Key).ToList(),
                new List <string>()
            };

            var           traceTable     = new TraceTable();
            var           report         = new StringBuilder();
            var           coverageReport = new StringBuilder();
            var           map            = new ApplicationMap();
            var           alerts         = new ScanAlertCollection();
            int           requestCount   = 0;
            MessageDumper messageDumper  = null;

            if (Config.DumpMessages)
            {
                messageDumper = new MessageDumper(_reportWriter.ReportPath.FullName);
            }

            for (int urlCollectionIndex = 0; urlCollectionIndex < 2; urlCollectionIndex++)
            {
                foreach (ScanPluginBase plugin in Config.ScanPlugins)
                {
                    if (Config.CodeCoverageReport > 0)
                    {
                        ScanMetrics.Default.Annotator.Reset();
                        ScanMetrics.Default.Annotator.AnnotationTable = ScanMetrics.Default.PluginAnnotations[plugin.ToString()];
                    }

                    if (!urlCollections[urlCollectionIndex].Any())
                    {
                        continue;
                    }

                    ScannerCli.DisplayScanPlugin(plugin);

                    foreach (var remotePath in urlCollections[urlCollectionIndex])
                    {
                        ScannerCli.DisplayResourcePath(remotePath);

                        IEnumerable <IEnumerable <TracedFunctionCall> > calls = null;
                        if (urlCollectionIndex == 0)
                        {
                            var key = urlDictionary[remotePath];

                            if (Program.PageFieldTable.ContainsKey(key))
                            {
                                calls = Program.PageFieldTable[key]
                                        .Select(x => x.Value.Select(y => new TracedFunctionCall()
                                {
                                    Name            = x.Key,
                                    ParameterValues = new List <string>()
                                    {
                                        y
                                    }
                                }));
                            }
                        }

                        for (int i = 0; i < plugin.ModeCount; i++)
                        {
                            foreach (var useStaticAnalysisInputs in new[]
                            {
                                false,
                                true
                            })
                            {
                                var trace = new FileTrace();

                                if (useStaticAnalysisInputs && calls != null)
                                {
                                    if (!calls.Any(x => x.Any()))
                                    {
                                        continue;
                                    }

                                    foreach (var c in calls)
                                    {
                                        trace.Calls.AddRange(c);
                                    }
                                }

                                bool discoveredVars = true;

                                while (discoveredVars)
                                {
                                    var traceFile = new FileInfo(TraceFileName);

                                    IOHelper.TryAction(traceFile.Delete);

                                    var client = new TcpClient()
                                    {
                                        ReceiveTimeout = Config.Timeout,
                                        SendTimeout    = Config.Timeout
                                    };

                                    while (!client.Connected)
                                    {
                                        try
                                        {
                                            client.Connect(Config.Server, Config.Port);
                                        }
                                        catch (SocketException ex)
                                        {
                                            ScannerCli.DisplayError(ex.Message);

                                            Thread.Sleep(5000);
                                        }
                                    }

                                    client.LingerState = new LingerOption(true, 0);
                                    HttpResponse resp = null;
                                    string       req, respString = "";

                                    using (var stream = client.GetStream())
                                    {
                                        req = plugin.BuildRequest(i, remotePath, trace);

                                        if (Config.DumpMessages)
                                        {
                                            messageDumper.Dump(req, requestCount, MessageType.Request);
                                        }

                                        var stopwatch = new Stopwatch();
                                        stopwatch.Start();
                                        stream.WriteString(req);

                                        try
                                        {
                                            var sgs = trace.Calls
                                                      .Superglobals()
                                                      .Select(x => new { x.Name, Value = x.ParameterValues.Count > 0 ? x.ParameterValues[0] : null })
                                                      .Distinct();

                                            var discoveredVarCount = sgs.Count();
                                            var reader             = new HttpResponseReader(stream);
                                            resp = reader.Read();
                                            stopwatch.Stop();
                                            respString = resp.CompleteResponse;

                                            ScannerCli.DisplayResponse(
                                                resp,
                                                i,
                                                discoveredVarCount,
                                                stopwatch.ElapsedMilliseconds,
                                                resp.CompleteResponse.Length);
                                        }
                                        catch (SocketException)
                                        {
                                            ScannerCli.DisplayResponseError(respString);
                                        }
                                        catch (IOException)
                                        {
                                            ScannerCli.DisplayResponseError(respString);
                                        }
                                    }

                                    if (urlCollectionIndex == 0 && resp != null)
                                    {
                                        var abs = "http://" + Config.Server + remotePath;

                                        var urls = new UriScraper()
                                        {
                                            Regex = new Regex(@"[/.]" + Config.Server + @"($|/)", RegexOptions.IgnoreCase | RegexOptions.Compiled),
                                        }
                                        .Parse(resp.Body, abs)
                                        .Select(x => new Uri(x).LocalPath);

                                        foreach (var url in urls)
                                        {
                                            if (!ignoreExtensions.Any(x => url.ToLower().EndsWith("." + x)) &&
                                                !urlCollections[0].Contains(url) &&
                                                !urlCollections[1].Contains(url))
                                            {
                                                urlCollections[1].Add(url);

                                                ScannerCli.DisplayDiscoveredUrl(url);
                                            }
                                        }
                                    }

                                    client.Close();

                                    if (Config.DumpMessages)
                                    {
                                        messageDumper.Dump(respString, requestCount, MessageType.Response);
                                    }

                                    requestCount++;
                                    traceFile = new FileInfo(TraceFileName);
                                    FileTrace newTrace = null;

                                    IOHelper.TryAction(() =>
                                    {
                                        if (traceFile.Exists)
                                        {
                                            using (var reader = traceFile.OpenText())
                                                newTrace = FileTrace.Parse(reader);
                                        }
                                    });

                                    if (newTrace == null)
                                    {
                                        newTrace = new FileTrace();
                                    }

                                    newTrace.Request  = req;
                                    newTrace.Response = respString;
                                    newTrace.File     = remotePath;

                                    var alert = plugin.ScanTrace(newTrace);

                                    if (alert != null)
                                    {
                                        if (Config.BeepOnAlert)
                                        {
                                            Console.Beep();
                                        }

                                        ScannerCli.DisplayAlert(alert);

                                        alerts.Add(alert);
                                        report.Append(alert.ToString());
                                    }

                                    discoveredVars = false;

                                    foreach (TracedFunctionCall c in newTrace.Calls
                                             .Superglobals()
                                             .Where(x => x.ParameterValues.Any()))
                                    {
                                        var oldCalls = trace.Calls.Where(x =>
                                                                         x.Name == c.Name &&
                                                                         x.ParameterValues.SequenceEqual(c.ParameterValues));
                                        if (!oldCalls.Any())
                                        {
                                            discoveredVars = true;
                                            break;
                                        }
                                    }

                                    var orphanedInputs = trace.Calls
                                                         .Superglobals()
                                                         .Where(x => !newTrace.Calls
                                                                .Any(y => x.Name == y.Name && x.ParameterValues
                                                                     .SequenceEqual(y.ParameterValues)))
                                                         .ToArray();

                                    newTrace.Calls.AddRange(orphanedInputs);
                                    trace = newTrace;
                                }

                                var superglobals = trace.Calls.Superglobals();

                                map.AddTrace(trace);

                                if (Config.DiscoveryReport)
                                {
                                    if (!traceTable.ContainsKey(plugin))
                                    {
                                        traceTable.Add(plugin, new Dictionary <int, Dictionary <string, FileTrace> >());
                                    }

                                    if (!traceTable[plugin].ContainsKey(i))
                                    {
                                        traceTable[plugin].Add(i, new Dictionary <string, FileTrace>());
                                    }

                                    if (!traceTable[plugin][i].ContainsKey(trace.File))
                                    {
                                        traceTable[plugin][i].Add(trace.File, trace);
                                    }
                                    else
                                    {
                                        traceTable[plugin][i][trace.File] = trace;
                                    }
                                }
                            }
                        }
                    }

                    if (Config.CodeCoverageReport > 0 && urlCollectionIndex == 0)
                    {
                        Cli.WriteLine("Calculating code coverage...");
                        CodeCoverageTable coverage = null;

                        IOHelper.TryAction(() =>
                        {
                            var calculator = new CodeCoverageCalculator(
                                ScanMetrics.Default.Annotator.AnnotationFile,
                                ScanMetrics.Default.PluginAnnotations[plugin.ToString()]);
                            coverage = calculator.CalculateCoverage();
                        });

                        coverage.Plugin = plugin.ToString();
                        coverageReport.AppendLine(coverage.ToString() + "\r\n");
                    }

                    Cli.WriteLine();
                }
            }

            _reportWriter.Write("Vulnerability Report", report.ToString());
            _reportWriter.Write("Input Map Report", map.ToXml(), "xml");

            if (alerts.Any())
            {
                _reportWriter.Write("Vulnerability Report",
                                    alerts.ToXml(), "pxml");
            }

            if (Config.DiscoveryReport)
            {
                _reportWriter.Write("Scan Overview Report",
                                    DiscoveryReport.Create(traceTable));
            }

            if (Config.CodeCoverageReport > 0)
            {
                _reportWriter.Write("Code Coverage Report", coverageReport.ToString());
                var annotationXml = ScanMetrics.Default.PluginAnnotations.ToXml();

                var annotationFile = _reportWriter.Write(
                    "Annotation",
                    annotationXml,
                    "axml");

                Cli.WriteLine();
                var commenter = new CoverageCommenter(ScanMetrics.Default.PluginAnnotations);
                commenter.LoadTable(annotationFile);
                commenter.WriteCommentedFiles(_reportWriter.ReportPath.FullName);

                _reportWriter.ReportFiles.Add(
                    new ReportFile(
                        "Coverage Comments",
                        Path.Combine("Code Coverage", "index.html")));
            }
        }
Beispiel #2
0
        static void ScanDirectory(DirectoryInfo AppDirectory, string RelativeAppPath)
        {
            var ignoreExtensions = new[]
            {
                "png",
                "jpg",
                "jpeg",
                "gif",
                "ico",
                "js",
                "css",
            };

            var urlDictionary = CreateUrlDictionary(RelativeAppPath, AppDirectory);

            var urlCollections = new[]
            {
                urlDictionary.Select(x => x.Key).ToList(),
                new List<string>()
            };

            var traceTable = new TraceTable();
            var report = new StringBuilder();
            var coverageReport = new StringBuilder();
            var map = new ApplicationMap();
            var alerts = new ScanAlertCollection();
            int requestCount = 0;
            MessageDumper messageDumper = null;

            if (Config.DumpMessages)
            {
                messageDumper = new MessageDumper(_reportWriter.ReportPath.FullName);
            }

            for (int urlCollectionIndex = 0; urlCollectionIndex < 2; urlCollectionIndex++)
                foreach (ScanPluginBase plugin in Config.ScanPlugins)
                {
                    if (Config.CodeCoverageReport > 0)
                    {
                        ScanMetrics.Default.Annotator.Reset();
                        ScanMetrics.Default.Annotator.AnnotationTable = ScanMetrics.Default.PluginAnnotations[plugin.ToString()];
                    }

                    if (!urlCollections[urlCollectionIndex].Any())
                        continue;

                    ScannerCli.DisplayScanPlugin(plugin);

                    foreach (var remotePath in urlCollections[urlCollectionIndex])
                    {
                        ScannerCli.DisplayResourcePath(remotePath);

                        IEnumerable<IEnumerable<TracedFunctionCall>> calls = null;
                        if (urlCollectionIndex == 0)
                        {
                            var key = urlDictionary[remotePath];

                            if (Program.PageFieldTable.ContainsKey(key))
                                calls = Program.PageFieldTable[key]
                                    .Select(x => x.Value.Select(y => new TracedFunctionCall()
                                    {
                                        Name = x.Key,
                                        ParameterValues = new List<string>() { y }
                                    }));
                        }

                        for (int i = 0; i < plugin.ModeCount; i++)
                        {
                            foreach (var useStaticAnalysisInputs in new[]
                        {
                            false,
                            true
                        })
                            {
                                var trace = new FileTrace();

                                if (useStaticAnalysisInputs && calls != null)
                                {
                                    if (!calls.Any(x => x.Any()))
                                        continue;

                                    foreach (var c in calls)
                                        trace.Calls.AddRange(c);
                                }

                                bool discoveredVars = true;

                                while (discoveredVars)
                                {
                                    var traceFile = new FileInfo(TraceFileName);

                                    IOHelper.TryAction(traceFile.Delete);

                                    var client = new TcpClient()
                                    {
                                        ReceiveTimeout = Config.Timeout,
                                        SendTimeout = Config.Timeout
                                    };

                                    while (!client.Connected)
                                        try
                                        {
                                            client.Connect(Config.Server, Config.Port);
                                        }
                                        catch (SocketException ex)
                                        {
                                            ScannerCli.DisplayError(ex.Message);

                                            Thread.Sleep(5000);
                                        }

                                    client.LingerState = new LingerOption(true, 0);
                                    HttpResponse resp = null;
                                    string req, respString = "";

                                    using (var stream = client.GetStream())
                                    {
                                        req = plugin.BuildRequest(i, remotePath, trace);

                                        if (Config.DumpMessages)
                                        {
                                            messageDumper.Dump(req, requestCount, MessageType.Request);
                                        }

                                        var stopwatch = new Stopwatch();
                                        stopwatch.Start();
                                        stream.WriteString(req);

                                        try
                                        {
                                            var sgs = trace.Calls
                                                .Superglobals()
                                                .Select(x => new { x.Name, Value = x.ParameterValues.Count > 0 ? x.ParameterValues[0] : null })
                                                .Distinct();

                                            var discoveredVarCount = sgs.Count();
                                            var reader = new HttpResponseReader(stream);
                                            resp = reader.Read();
                                            stopwatch.Stop();
                                            respString = resp.CompleteResponse;

                                            ScannerCli.DisplayResponse(
                                                resp,
                                                i,
                                                discoveredVarCount,
                                                stopwatch.ElapsedMilliseconds,
                                                resp.CompleteResponse.Length);
                                        }
                                        catch (SocketException)
                                        {
                                            ScannerCli.DisplayResponseError(respString);
                                        }
                                        catch (IOException)
                                        {
                                            ScannerCli.DisplayResponseError(respString);
                                        }
                                    }

                                    if (urlCollectionIndex == 0 && resp != null)
                                    {
                                        var abs = "http://" + Config.Server + remotePath;

                                        var urls = new UriScraper()
                                        {
                                            Regex = new Regex(@"[/.]" + Config.Server + @"($|/)", RegexOptions.IgnoreCase | RegexOptions.Compiled),
                                        }
                                        .Parse(resp.Body, abs)
                                        .Select(x => new Uri(x).LocalPath);

                                        foreach (var url in urls)
                                        {
                                            if (!ignoreExtensions.Any(x => url.ToLower().EndsWith("." + x)) &&
                                                !urlCollections[0].Contains(url) &&
                                                !urlCollections[1].Contains(url))
                                            {
                                                urlCollections[1].Add(url);

                                                ScannerCli.DisplayDiscoveredUrl(url);
                                            }
                                        }
                                    }

                                    client.Close();

                                    if (Config.DumpMessages)
                                    {
                                        messageDumper.Dump(respString, requestCount, MessageType.Response);
                                    }

                                    requestCount++;
                                    traceFile = new FileInfo(TraceFileName);
                                    FileTrace newTrace = null;

                                    IOHelper.TryAction(() =>
                                    {
                                        if (traceFile.Exists)
                                            using (var reader = traceFile.OpenText())
                                                newTrace = FileTrace.Parse(reader);
                                    });

                                    if (newTrace == null)
                                    {
                                        newTrace = new FileTrace();
                                    }

                                    newTrace.Request = req;
                                    newTrace.Response = respString;
                                    newTrace.File = remotePath;

                                    var alert = plugin.ScanTrace(newTrace);

                                    if (alert != null)
                                    {
                                        if (Config.BeepOnAlert)
                                            Console.Beep();

                                        ScannerCli.DisplayAlert(alert);

                                        alerts.Add(alert);
                                        report.Append(alert.ToString());
                                    }

                                    discoveredVars = false;

                                    foreach (TracedFunctionCall c in newTrace.Calls
                                        .Superglobals()
                                        .Where(x => x.ParameterValues.Any()))
                                    {
                                        var oldCalls = trace.Calls.Where(x =>
                                            x.Name == c.Name &&
                                            x.ParameterValues.SequenceEqual(c.ParameterValues));
                                        if (!oldCalls.Any())
                                        {
                                            discoveredVars = true;
                                            break;
                                        }
                                    }

                                    var orphanedInputs = trace.Calls
                                        .Superglobals()
                                        .Where(x => !newTrace.Calls
                                            .Any(y => x.Name == y.Name && x.ParameterValues
                                                .SequenceEqual(y.ParameterValues)))
                                        .ToArray();

                                    newTrace.Calls.AddRange(orphanedInputs);
                                    trace = newTrace;
                                }

                                var superglobals = trace.Calls.Superglobals();

                                map.AddTrace(trace);

                                if (Config.DiscoveryReport)
                                {
                                    if (!traceTable.ContainsKey(plugin))
                                    {
                                        traceTable.Add(plugin, new Dictionary<int, Dictionary<string, FileTrace>>());
                                    }

                                    if (!traceTable[plugin].ContainsKey(i))
                                    {
                                        traceTable[plugin].Add(i, new Dictionary<string, FileTrace>());
                                    }

                                    if (!traceTable[plugin][i].ContainsKey(trace.File))
                                    {
                                        traceTable[plugin][i].Add(trace.File, trace);
                                    }
                                    else
                                    {
                                        traceTable[plugin][i][trace.File] = trace;
                                    }
                                }
                            }
                        }
                    }

                    if (Config.CodeCoverageReport > 0 && urlCollectionIndex == 0)
                    {
                        Cli.WriteLine("Calculating code coverage...");
                        CodeCoverageTable coverage = null;

                        IOHelper.TryAction(() =>
                        {
                            var calculator = new CodeCoverageCalculator(
                                ScanMetrics.Default.Annotator.AnnotationFile,
                                ScanMetrics.Default.PluginAnnotations[plugin.ToString()]);
                            coverage = calculator.CalculateCoverage();
                        });

                        coverage.Plugin = plugin.ToString();
                        coverageReport.AppendLine(coverage.ToString() + "\r\n");
                    }

                    Cli.WriteLine();
                }

            _reportWriter.Write("Vulnerability Report", report.ToString());
            _reportWriter.Write("Input Map Report", map.ToXml(), "xml");

            if (alerts.Any())
            {
                _reportWriter.Write("Vulnerability Report",
                    alerts.ToXml(), "pxml");
            }

            if (Config.DiscoveryReport)
            {
                _reportWriter.Write("Scan Overview Report",
                    DiscoveryReport.Create(traceTable));
            }

            if (Config.CodeCoverageReport > 0)
            {
                _reportWriter.Write("Code Coverage Report", coverageReport.ToString());
                var annotationXml = ScanMetrics.Default.PluginAnnotations.ToXml();

                var annotationFile = _reportWriter.Write(
                    "Annotation",
                    annotationXml,
                    "axml");

                Cli.WriteLine();
                var commenter = new CoverageCommenter(ScanMetrics.Default.PluginAnnotations);
                commenter.LoadTable(annotationFile);
                commenter.WriteCommentedFiles(_reportWriter.ReportPath.FullName);

                _reportWriter.ReportFiles.Add(
                    new ReportFile(
                        "Coverage Comments",
                        Path.Combine("Code Coverage", "index.html")));
            }
        }