Beispiel #1
0
        /// <summary>
        ///     Main entrypoint for the download program.
        /// </summary>
        /// <param name="args"> parameters passed in from the user </param>
        private static async Task Main(string[] args)
        {
            DetectCryptographyTool detectCryptographyTool = new DetectCryptographyTool();

            Logger.Info($"Microsoft OSS Gadget - {TOOL_NAME} {VERSION}");

            detectCryptographyTool.ParseOptions(args);

            // select output destination and format
            detectCryptographyTool.SelectOutput((string?)detectCryptographyTool.Options["output-file"] ?? "");
            IOutputBuilder outputBuilder = detectCryptographyTool.SelectFormat((string?)detectCryptographyTool.Options["format"] ?? "text");

            if (detectCryptographyTool.Options["target"] is IList <string> targetList && targetList.Count > 0)
            {
                var sb = new StringBuilder();
                foreach (var target in targetList)
                {
                    sb.Clear();
                    try
                    {
                        List <IssueRecord>?results = null;
                        if (target.StartsWith("pkg:", StringComparison.InvariantCulture))
                        {
                            var purl = new PackageURL(target);
                            results = await(detectCryptographyTool.AnalyzePackage(purl,
                                                                                  (string?)detectCryptographyTool.Options["download-directory"] ?? string.Empty,
                                                                                  (bool?)detectCryptographyTool.Options["use-cache"] == true) ??
                                            Task.FromResult(new List <IssueRecord>()));
                        }
                        else if (Directory.Exists(target))
                        {
                            results = await(detectCryptographyTool.AnalyzeDirectory(target) ??
                                            Task.FromResult(new List <IssueRecord>()));
                        }
                        else if (File.Exists(target))
                        {
                            string?targetDirectoryName = null;
                            while (targetDirectoryName == null || Directory.Exists(targetDirectoryName))
                            {
                                targetDirectoryName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                            }
                            var projectManager = ProjectManagerFactory.CreateBaseProjectManager(targetDirectoryName);

#pragma warning disable SCS0018 // Path traversal: injection possible in {1} argument passed to '{0}'
                            var path = await projectManager.ExtractArchive("temp", File.ReadAllBytes(target));

#pragma warning restore SCS0018 // Path traversal: injection possible in {1} argument passed to '{0}'

                            results = await(detectCryptographyTool.AnalyzeDirectory(path) ??
                                            Task.FromResult(new List <IssueRecord>()));;

                            // Clean up after ourselves
                            try
                            {
                                if (targetDirectoryName != null)
                                {
                                    Directory.Delete(targetDirectoryName, true);
                                }
                            }
                            catch (Exception ex)
                            {
                                Logger.Warn("Unable to delete {0}: {1}", targetDirectoryName, ex.Message);
                            }
                        }

                        if (results == null)
                        {
                            Logger.Warn("Error generating results, was null.");
                        }
                        else if (!results.Any())
                        {
                            sb.AppendLine($"[ ] {target} - This software package does NOT appear to implement cryptography.");
                        }
                        else
                        {
                            var shortTags = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>())
                                            .Distinct()
                                            .Where(t => t.StartsWith("Cryptography.Implementation."))
                                            .Select(t => t.Replace("Cryptography.Implementation.", ""));
                            var otherTags = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>())
                                            .Distinct()
                                            .Where(t => !t.StartsWith("Cryptography.Implementation."));

                            if (shortTags.Any())
                            {
                                sb.AppendLine($"[X] {target} - This software package appears to implement {string.Join(", ", shortTags)}.");
                            }

                            if (otherTags.Contains("Cryptography.GenericImplementation.HighDensityOperators"))
                            {
                                sb.AppendLine($"[X] {target} - This software package has a high-density of cryptographic operators.");
                            }
                            else
                            {
                                sb.AppendLine($"[ ] {target} - This software package does NOT have a high-density of cryptographic operators.");
                            }

                            if (otherTags.Contains("Cryptography.GenericImplementation.CryptographicWords"))
                            {
                                sb.AppendLine($"[X] {target} - This software package contains words that suggest cryptography.");
                            }
                            else
                            {
                                sb.AppendLine($"[ ] {target} - This software package does NOT contains words that suggest cryptography.");
                            }

                            if ((bool?)detectCryptographyTool.Options["verbose"] == true)
                            {
                                var items = results.GroupBy(k => k.Issue.Rule.Name).OrderByDescending(k => k.Count());
                                foreach (var item in items)
                                {
                                    sb.AppendLine();
                                    sb.AppendLine($"There were {item.Count()} finding(s) of type [{item.Key}].");

                                    foreach (var result in results)
                                    {
                                        if (result.Issue.Rule.Name == item.Key)
                                        {
                                            sb.AppendLine($" {result.Filename}:");
                                            if (result.Issue.Rule.Id == "_CRYPTO_DENSITY")
                                            {
                                                // No excerpt for cryptogrpahic density
                                                // TODO: We stuffed the density in the unused 'Description' field. This is code smell.
                                                sb.AppendLine($"  | The maximum cryptographic density is {result.Issue.Rule.Description}.");
                                            }
                                            else
                                            {
                                                // Show the excerpt
                                                foreach (var line in result.TextSample.Split(new char[] { '\n', '\r' }))
                                                {
                                                    if (!string.IsNullOrWhiteSpace(line))
                                                    {
                                                        sb.AppendLine($"  | {line.Trim()}");
                                                    }
                                                }
                                            }
                                            sb.AppendLine();
                                        }
                                    }
                                }
                            }

                            if (Logger.IsDebugEnabled)
                            {
                                foreach (var result in results)
                                {
                                    Logger.Debug($"Result: {result.Filename} {result.Issue.Rule.Name} {result.TextSample}");
                                }
                            }
                        }
                        Console.WriteLine(sb.ToString());
                    }
                    catch (Exception ex)
                    {
                        Logger.Warn(ex, "Error processing {0}: {1}", target, ex.Message);
                        Logger.Warn(ex.StackTrace);
                    }
                }
            }
            else
            {
                Logger.Warn("No target provided; nothing to analyze.");
                DetectCryptographyTool.ShowUsage();
                Environment.Exit(1);
            }
        }
        /// <summary>
        /// Main entrypoint for the download program.
        /// </summary>
        /// <param name="args">parameters passed in from the user</param>
        private static async Task Main(string[] args)
        {
            ShowToolBanner();

            DetectCryptographyTool detectCryptographyTool = new DetectCryptographyTool();

            detectCryptographyTool.ParseOptions(args);

            // select output destination and format
            detectCryptographyTool.SelectOutput((string?)detectCryptographyTool.Options["output-file"] ?? "");
            IOutputBuilder outputBuilder = detectCryptographyTool.SelectFormat((string?)detectCryptographyTool.Options["format"] ?? "text");

            if (detectCryptographyTool.Options["target"] is IList <string> targetList && targetList.Count > 0)
            {
                StringBuilder?sb = new StringBuilder();
                foreach (string?target in targetList)
                {
                    sb.Clear();
                    try
                    {
                        List <IssueRecord>?results = null;
                        if (target.StartsWith("pkg:", StringComparison.InvariantCulture))
                        {
                            PackageURL?purl = new PackageURL(target);
                            results = await(detectCryptographyTool.AnalyzePackage(purl,
                                                                                  (string?)detectCryptographyTool.Options["download-directory"] ?? string.Empty,
                                                                                  (bool?)detectCryptographyTool.Options["use-cache"] == true) ??
                                            Task.FromResult(new List <IssueRecord>()));
                        }
                        else if (System.IO.Directory.Exists(target))
                        {
                            results = await(detectCryptographyTool.AnalyzeDirectory(target) ??
                                            Task.FromResult(new List <IssueRecord>()));
                        }
                        else if (File.Exists(target))
                        {
                            string?targetDirectoryName = null;
                            while (targetDirectoryName == null || System.IO.Directory.Exists(targetDirectoryName))
                            {
                                targetDirectoryName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                            }

                            string?path = await ArchiveHelper.ExtractArchiveAsync(targetDirectoryName, Path.GetFileName(target), File.OpenRead(target));

                            results = await detectCryptographyTool.AnalyzeDirectory(path);

                            // Clean up after ourselves
                        }
                        else
                        {
                            Logger.Warn($"{target} was neither a Package URL, directory, nor a file.");
                            continue;
                        }

                        if (results == null)
                        {
                            Logger.Warn("No results were generated.");
                            continue;
                        }
                        else
                        {
                            sb.AppendLine("Summary Results:");

                            sb.AppendLine(Blue("Cryptographic Implementations:"));
                            IOrderedEnumerable <string>?implementations = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>())
                                                                          .Distinct()
                                                                          .Where(t => t.StartsWith("Cryptography.Implementation."))
                                                                          .Select(t => t.Replace("Cryptography.Implementation.", ""))
                                                                          .OrderBy(s => s);
                            if (implementations.Any())
                            {
                                foreach (string?tag in implementations)
                                {
                                    sb.AppendLine(Bright.Blue($" * {tag}"));
                                }
                            }
                            else
                            {
                                sb.AppendLine(Bright.Black("  No implementations found."));
                            }

                            sb.AppendLine();
                            sb.AppendLine(Red("Cryptographic Library References:"));
                            IOrderedEnumerable <string>?references = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>())
                                                                     .Distinct()
                                                                     .Where(t => t.StartsWith("Cryptography.Reference."))
                                                                     .Select(t => t.Replace("Cryptography.Reference.", ""))
                                                                     .OrderBy(s => s);

                            if (references.Any())
                            {
                                foreach (string?tag in references)
                                {
                                    sb.AppendLine(Bright.Red($" * {tag}"));
                                }
                            }
                            else
                            {
                                sb.AppendLine(Bright.Black("  No library references found."));
                            }

                            sb.AppendLine();
                            sb.AppendLine(Green("Other Cryptographic Characteristics:"));
                            IOrderedEnumerable <string>?characteristics = results.SelectMany(r => r.Issue.Rule.Tags ?? Array.Empty <string>())
                                                                          .Distinct()
                                                                          .Where(t => t.Contains("Crypto", StringComparison.InvariantCultureIgnoreCase) &&
                                                                                 !t.StartsWith("Cryptography.Implementation.") &&
                                                                                 !t.StartsWith("Cryptography.Reference."))
                                                                          .Select(t => t.Replace("Cryptography.", ""))
                                                                          .OrderBy(s => s);
                            if (characteristics.Any())
                            {
                                foreach (string?tag in characteristics)
                                {
                                    sb.AppendLine(Bright.Green($" * {tag}"));
                                }
                            }
                            else
                            {
                                sb.AppendLine(Bright.Black("  No additional characteristics found."));
                            }

                            if ((bool?)detectCryptographyTool.Options["verbose"] == true)
                            {
                                IOrderedEnumerable <IGrouping <string, IssueRecord> >?items = results.GroupBy(k => k.Issue.Rule.Name).OrderByDescending(k => k.Count());
                                foreach (IGrouping <string, IssueRecord>?item in items)
                                {
                                    sb.AppendLine();
                                    sb.AppendLine($"There were {item.Count()} finding(s) of type [{item.Key}].");

                                    foreach (IssueRecord?result in results)
                                    {
                                        if (result.Issue.Rule.Name == item.Key)
                                        {
                                            sb.AppendLine($" {result.Filename}:");
                                            if (result.Issue.Rule.Id == "_CRYPTO_DENSITY")
                                            {
                                                // No excerpt for cryptographic density
                                                // TODO: We stuffed the density in the unused 'Description' field. This is code smell.
                                                sb.AppendLine($"  | The maximum cryptographic density is {result.Issue.Rule.Description}.");
                                            }
                                            else
                                            {
                                                // Show the excerpt
                                                foreach (string?line in result.TextSample.Split(new char[] { '\n', '\r' }))
                                                {
                                                    if (!string.IsNullOrWhiteSpace(line))
                                                    {
                                                        sb.AppendLine($"  | {line.Trim()}");
                                                    }
                                                }
                                            }
                                            sb.AppendLine();
                                        }
                                    }
                                }
                            }

                            if (Logger.IsDebugEnabled)
                            {
                                foreach (IssueRecord?result in results)
                                {
                                    Logger.Debug($"Result: {result.Filename} {result.Issue.Rule.Name} {result.TextSample}");
                                }
                            }
                        }
                        Console.WriteLine(sb.ToString());
                    }
                    catch (Exception ex)
                    {
                        Logger.Warn(ex, "Error processing {0}: {1}", target, ex.Message);
                        Logger.Warn(ex.StackTrace);
                    }
                }
            }
            else
            {
                Logger.Warn("No target provided; nothing to analyze.");
                DetectCryptographyTool.ShowUsage();
                Environment.Exit(1);
            }
        }