From e798c304858168a30df499a1db5a89eeb49fbad3 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Mon, 2 Aug 2021 11:47:21 -0700 Subject: [PATCH] Re sync main with 2.3 (#608) --- Benchmarks/Benchmarks.csproj | 6 +- Benchmarks/LiteDbManager.cs | 2 +- Benchmarks/SystemSqliteDatabaseManager.cs | 2 +- Cli/AttackSurfaceAnalyzerClient.cs | 162 +++++++++++++----- Cli/Cli.csproj | 11 +- .../FileCollectorOptions.razor | 2 +- .../RegistryCollectorOptions.razor | 2 +- .../MonitorOptions/FileMonitorOptions.razor | 2 +- Cli/Components/States/Monitoring.razor | 2 +- Cli/Components/States/Results.razor | 22 ++- Cli/Helper.cs | 2 +- Cli/Pages/Analyze.razor | 6 +- Cli/Pages/Report.razor | 16 +- Cli/Pages/Sandbox.razor | 63 +++++-- Cli/wwwroot/css/asa.css | 4 + Directory.Build.props | 2 +- Lib/Collectors/FileSystemCollector.cs | 31 ++-- Lib/Lib.csproj | 18 +- Lib/Objects/CommandOptions.cs | 2 +- Lib/Objects/CryptographicKeyObject.cs | 1 + Lib/Objects/FileMonitorObject.cs | 1 + Lib/Objects/FileSystemObject.cs | 6 + Lib/Objects/ProcessModuleObject.cs | 9 +- Lib/Objects/ProcessObject.cs | 5 +- Lib/Objects/Signature.cs | 6 +- Lib/Objects/Types.cs | 3 +- Lib/Objects/WifiObject.cs | 1 + Lib/Properties/Resources.resx | 9 + Lib/Utils/AsaHelpers.cs | 54 +++--- Lib/Utils/CryptoHelpers.cs | 33 +++- Lib/Utils/DatabaseManager.cs | 2 +- Tests/Tests.csproj | 6 +- 32 files changed, 322 insertions(+), 171 deletions(-) diff --git a/Benchmarks/Benchmarks.csproj b/Benchmarks/Benchmarks.csproj index 97a250da..afa3018b 100644 --- a/Benchmarks/Benchmarks.csproj +++ b/Benchmarks/Benchmarks.csproj @@ -10,8 +10,8 @@ - - + + @@ -25,6 +25,6 @@ - + \ No newline at end of file diff --git a/Benchmarks/LiteDbManager.cs b/Benchmarks/LiteDbManager.cs index bfeaf0c4..3dedfd95 100644 --- a/Benchmarks/LiteDbManager.cs +++ b/Benchmarks/LiteDbManager.cs @@ -68,7 +68,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Utils var firstRun = runs?.FindOne(x => x.RunId.Equals(baseId)); var secondRun = runs?.FindOne(x => x.RunId.Equals(compareId)); - return firstRun?.ResultTypes.Intersect(secondRun?.ResultTypes); + return firstRun?.ResultTypes.Intersect(secondRun?.ResultTypes ?? new List()) ?? secondRun?.ResultTypes ?? new List(); } public static bool? GetComparisonCompleted(string firstRunId, string secondRunId) diff --git a/Benchmarks/SystemSqliteDatabaseManager.cs b/Benchmarks/SystemSqliteDatabaseManager.cs index 2cad8325..2f65f107 100644 --- a/Benchmarks/SystemSqliteDatabaseManager.cs +++ b/Benchmarks/SystemSqliteDatabaseManager.cs @@ -76,7 +76,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Utils var runOne = GetRun(baseId); var runTwo = GetRun(compareId); - return runOne?.ResultTypes.Intersect(runTwo?.ResultTypes).ToList() ?? new List(); + return runOne?.ResultTypes.Intersect(runTwo?.ResultTypes ?? new List()).ToList() ?? runTwo?.ResultTypes ?? new List(); } public static bool GetComparisonCompleted(string firstRunId, string secondRunId) diff --git a/Cli/AttackSurfaceAnalyzerClient.cs b/Cli/AttackSurfaceAnalyzerClient.cs index 9e76366f..b7378139 100644 --- a/Cli/AttackSurfaceAnalyzerClient.cs +++ b/Cli/AttackSurfaceAnalyzerClient.cs @@ -33,7 +33,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli private static readonly List monitors = new List(); private static List comparators = new List(); - public static DatabaseManager DatabaseManager { get; private set; } + public static DatabaseManager? DatabaseManager { get; private set; } private static void SetupLogging(CommandOptions opts) { @@ -197,7 +197,12 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli public static ConcurrentDictionary<(RESULT_TYPE, CHANGE_TYPE), List> AnalyzeMonitored(CompareCommandOptions opts) { - if (opts is null) { return new ConcurrentDictionary<(RESULT_TYPE, CHANGE_TYPE), List>(); } + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "InsertCompareResults"); + return new ConcurrentDictionary<(RESULT_TYPE, CHANGE_TYPE), List>(); + } + if (opts is null || opts.SecondRunId is null) { return new ConcurrentDictionary<(RESULT_TYPE, CHANGE_TYPE), List>(); } var analyzer = new AsaAnalyzer(new AnalyzerOptions(opts.RunScripts)); return AnalyzeMonitored(opts, analyzer, DatabaseManager.GetMonitorResults(opts.SecondRunId), opts.AnalysesFile ?? throw new ArgumentNullException(nameof(opts.AnalysesFile))); } @@ -257,6 +262,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli internal static void InsertCompareResults(ConcurrentDictionary<(RESULT_TYPE, CHANGE_TYPE), List> results, string? FirstRunId, string SecondRunId, string AnalysesHash) { + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "InsertCompareResults"); + return; + } DatabaseManager.InsertCompareRun(FirstRunId, SecondRunId, AnalysesHash, RUN_STATUS.RUNNING); foreach (var key in results.Keys) { @@ -331,7 +341,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli else { SetupDatabase(opts); - + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "RunConfigCommand"); + return ASA_ERROR.DATABASE_NULL; + } if (opts.ListRuns) { if (DatabaseManager.FirstRun) @@ -408,6 +422,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli private static ASA_ERROR RunExportCollectCommand(ExportCollectCommandOptions opts) { + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "RunExportCollectCommand"); + return ASA_ERROR.DATABASE_NULL; + } if (opts.OutputPath != null && !Directory.Exists(opts.OutputPath)) { Log.Fatal(Strings.Get("Err_OutputPathNotExist"), opts.OutputPath); @@ -611,6 +630,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli private static ASA_ERROR RunExportMonitorCommand(ExportMonitorCommandOptions opts) { + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "RunExportMonitorCommand"); + return ASA_ERROR.DATABASE_NULL; + } if (opts.RunId is null) { var runIds = DatabaseManager.GetLatestRunIds(1, RUN_TYPE.MONITOR); @@ -644,6 +668,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli public static void WriteMonitorJson(string RunId, int ResultType, string OutputPath) { + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "WriteMonitorJson"); + return; + } var invalidFileNameChars = Path.GetInvalidPathChars().ToList(); OutputPath = new string(OutputPath.Select(ch => invalidFileNameChars.Contains(ch) ? Convert.ToChar(invalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray()); @@ -672,6 +701,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli private static ASA_ERROR RunMonitorCommand(MonitorCommandOptions opts) { + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "RunMonitorCommand"); + return ASA_ERROR.DATABASE_NULL; + } if (opts.RunId is string) { opts.RunId = opts.RunId.Trim(); @@ -742,7 +776,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli } } - void consoleCancelDelegate(object sender, ConsoleCancelEventArgs args) + void consoleCancelDelegate(object? sender, ConsoleCancelEventArgs args) { args.Cancel = true; exitEvent.Set(); @@ -804,7 +838,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli { throw new ArgumentNullException(nameof(opts)); } - + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "CompareRuns"); + return new ConcurrentDictionary<(RESULT_TYPE, CHANGE_TYPE), List>(); + } comparators = new List(); Dictionary EndEvent = new Dictionary(); @@ -827,51 +865,58 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli if (!opts.DisableAnalysis) { - watch = Stopwatch.StartNew(); - var analyzer = new AsaAnalyzer(new AnalyzerOptions(opts.RunScripts)); - var platform = DatabaseManager.RunIdToPlatform(opts.SecondRunId); - var violations = analyzer.EnumerateRuleIssues(opts.AnalysesFile.GetRules()); - OAT.Utils.Strings.Setup(); - OAT.Utils.Helpers.PrintViolations(violations); - if (violations.Any()) + if (opts.AnalysesFile is not null) { - Log.Error("Encountered {0} issues with rules in {1}. Skipping analysis.", violations.Count(), opts.AnalysesFile.Source ?? "Embedded"); - } - else - { - if (c.Results.Count > 0) + watch = Stopwatch.StartNew(); + var analyzer = new AsaAnalyzer(new AnalyzerOptions(opts.RunScripts)); + var platform = DatabaseManager.RunIdToPlatform(opts.SecondRunId); + var violations = analyzer.EnumerateRuleIssues(opts.AnalysesFile.GetRules()); + OAT.Utils.Strings.Setup(); + OAT.Utils.Helpers.PrintViolations(violations); + if (violations.Any()) { - foreach (var key in c.Results.Keys) + Log.Error("Encountered {0} issues with rules in {1}. Skipping analysis.", violations.Count(), opts.AnalysesFile?.Source ?? "Embedded"); + } + else + { + if (c.Results.Count > 0) { - if (c.Results[key] is List queue) + foreach (var key in c.Results.Keys) { - queue.AsParallel().ForAll(res => + if (c.Results[key] is List queue) { - // Select rules with the appropriate change type, platform and target - // - Target is also checked inside Analyze, but this shortcuts repeatedly - // checking rules which don't apply - var selectedRules = opts.AnalysesFile.Rules.Where((rule) => - (rule.ChangeTypes == null || rule.ChangeTypes.Contains(res.ChangeType)) - && (rule.Platforms == null || rule.Platforms.Contains(platform)) - && (rule.ResultType == res.ResultType)); - res.Rules = analyzer.Analyze(selectedRules, res.Base, res.Compare).ToList(); - res.Analysis = res.Rules.Count - > 0 ? res.Rules.Max(x => ((AsaRule)x).Flag) : opts.AnalysesFile.DefaultLevels[res.ResultType]; - res.AnalysesHash = opts.AnalysesFile.GetHash(); - }); + queue.AsParallel().ForAll(res => + { + // Select rules with the appropriate change type, platform and target + // - Target is also checked inside Analyze, but this shortcuts repeatedly + // checking rules which don't apply + var selectedRules = opts.AnalysesFile.Rules.Where((rule) => + (rule.ChangeTypes == null || rule.ChangeTypes.Contains(res.ChangeType)) + && (rule.Platforms == null || rule.Platforms.Contains(platform)) + && (rule.ResultType == res.ResultType)); + res.Rules = analyzer.Analyze(selectedRules, res.Base, res.Compare).ToList(); + res.Analysis = res.Rules.Count + > 0 ? res.Rules.Max(x => ((AsaRule)x).Flag) : opts.AnalysesFile.DefaultLevels[res.ResultType]; + res.AnalysesHash = opts.AnalysesFile.GetHash(); + }); + } } } } - } - watch.Stop(); - t = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds); - answer = string.Format(CultureInfo.InvariantCulture, "{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms", - t.Hours, - t.Minutes, - t.Seconds, - t.Milliseconds); - Log.Information(Strings.Get("Completed"), "Analysis", answer); + watch.Stop(); + t = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds); + answer = string.Format(CultureInfo.InvariantCulture, "{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms", + t.Hours, + t.Minutes, + t.Seconds, + t.Milliseconds); + Log.Information(Strings.Get("Completed"), "Analysis", answer); + } + else + { + Log.Error(Strings.Get("Err_AnalysisNull")); + } } return c.Results; @@ -879,6 +924,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli public static ASA_ERROR RunGuiMonitorCommand(MonitorCommandOptions opts) { + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "RunGuiMonitorCommand"); + return ASA_ERROR.DATABASE_NULL; + } if (opts is null) { return ASA_ERROR.NO_COLLECTORS; @@ -894,7 +944,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli { Log.Warning(Strings.Get("Err_NoMonitors")); } - var run = new AsaRun(RunId: opts.RunId, Timestamp: DateTime.Now, Version: AsaHelpers.GetVersionString(), Platform: AsaHelpers.GetPlatform(), ResultTypes: setResultTypes, Type: RUN_TYPE.MONITOR); + var run = new AsaRun(RunId: opts?.RunId ?? string.Empty, Timestamp: DateTime.Now, Version: AsaHelpers.GetVersionString(), Platform: AsaHelpers.GetPlatform(), ResultTypes: setResultTypes, Type: RUN_TYPE.MONITOR); DatabaseManager.InsertRun(run); foreach (var c in monitors) @@ -907,6 +957,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli public static int StopMonitors() { + foreach (var c in monitors) { Log.Information(Strings.Get("End"), c.GetType().Name); @@ -916,6 +967,12 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli FlushResults(); + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "RunGuiMonitorCommand"); + return (int)ASA_ERROR.DATABASE_NULL; + } + DatabaseManager.Commit(); return 0; @@ -948,6 +1005,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli public static ASA_ERROR RunCollectCommand(CollectCommandOptions opts) { + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "RunCollectCommand"); + return ASA_ERROR.DATABASE_NULL; + } if (opts == null) { return ASA_ERROR.NO_COLLECTORS; } collectors.Clear(); AdminOrWarn(); @@ -1123,11 +1185,19 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli using CancellationTokenSource source = new CancellationTokenSource(); CancellationToken token = source.Token; - void cancelKeyDelegate(object sender, ConsoleCancelEventArgs args) + void cancelKeyDelegate(object? sender, ConsoleCancelEventArgs args) { Log.Information("Cancelling collection. Rolling back transaction. Please wait to avoid corrupting database."); source.Cancel(); - DatabaseManager.CloseDatabase(); + + if (DatabaseManager is null) + { + Log.Error("Err_DatabaseManagerNull", "InsertCompareResults"); + } + else + { + DatabaseManager.CloseDatabase(); + } Environment.Exit((int)ASA_ERROR.CANCELLED); } Console.CancelKeyPress += cancelKeyDelegate; @@ -1163,6 +1233,10 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli private static void FlushResults() { + if (DatabaseManager is null) + { + return; + } var prevFlush = DatabaseManager.QueueSize; var totFlush = prevFlush; diff --git a/Cli/Cli.csproj b/Cli/Cli.csproj index 9b173ffd..f0738cb3 100644 --- a/Cli/Cli.csproj +++ b/Cli/Cli.csproj @@ -33,17 +33,16 @@ - + - - - - + + + - + diff --git a/Cli/Components/CollectorOptions/FileCollectorOptions.razor b/Cli/Components/CollectorOptions/FileCollectorOptions.razor index a53035f8..abb93b4e 100644 --- a/Cli/Components/CollectorOptions/FileCollectorOptions.razor +++ b/Cli/Components/CollectorOptions/FileCollectorOptions.razor @@ -66,7 +66,7 @@ @code{ Helper.GlowClass directorySelectElementGlowClass = new Helper.GlowClass(); - string SelectedDirectoryInput; + string SelectedDirectoryInput = string.Empty; int SelectedDirectoryTop; void RemoveInputFromList() diff --git a/Cli/Components/CollectorOptions/RegistryCollectorOptions.razor b/Cli/Components/CollectorOptions/RegistryCollectorOptions.razor index 1cdefe70..f5479e45 100644 --- a/Cli/Components/CollectorOptions/RegistryCollectorOptions.razor +++ b/Cli/Components/CollectorOptions/RegistryCollectorOptions.razor @@ -39,7 +39,7 @@ @code{ Helper.GlowClass directorySelectElementGlowClass = new Helper.GlowClass(); - string SelectedHiveInput; + string SelectedHiveInput = string.Empty; int SelectedHiveTop; void RemoveInputFromList() diff --git a/Cli/Components/MonitorOptions/FileMonitorOptions.razor b/Cli/Components/MonitorOptions/FileMonitorOptions.razor index 19c14938..1c1691e3 100644 --- a/Cli/Components/MonitorOptions/FileMonitorOptions.razor +++ b/Cli/Components/MonitorOptions/FileMonitorOptions.razor @@ -46,7 +46,7 @@ @code{ Helper.GlowClass directorySelectElementGlowClass = new Helper.GlowClass(); - string SelectedDirectoryInput; + string SelectedDirectoryInput = string.Empty; int SelectedDirectoryTop; void RemoveInputFromList() diff --git a/Cli/Components/States/Monitoring.razor b/Cli/Components/States/Monitoring.razor index 4457d0da..f203cddf 100644 --- a/Cli/Components/States/Monitoring.razor +++ b/Cli/Components/States/Monitoring.razor @@ -3,5 +3,5 @@ @code{ [Parameter] - public Action Continue { get; set; } + public Action Continue { get; set; } = delegate () { }; } \ No newline at end of file diff --git a/Cli/Components/States/Results.razor b/Cli/Components/States/Results.razor index 4ce550b0..ed4af867 100644 --- a/Cli/Components/States/Results.razor +++ b/Cli/Components/States/Results.razor @@ -67,18 +67,15 @@ else } @code { - string _firstRunId = string.Empty; - string _secondRundId = string.Empty; - string _analysesHash = string.Empty; - string _monitorRunId = string.Empty; + [Parameter] - public string FirstRunId { get { return _firstRunId; } set { _firstRunId = value; OnInitialized(); } } + public string FirstRunId { get; set; } = string.Empty; [Parameter] - public string SecondRunId { get { return _secondRundId; } set { _secondRundId = value; OnInitialized(); } } + public string SecondRunId { get; set; } = string.Empty; [Parameter] - public string AnalysesHash { get { return _analysesHash; } set { _analysesHash = value; OnInitialized(); } } + public string AnalysesHash { get; set; } = string.Empty; [Parameter] - public string MonitorRunId { get { return _monitorRunId; } set { _monitorRunId = value; OnInitialized(); } } + public string MonitorRunId { get; set; } = string.Empty; protected override void OnInitialized() { @@ -150,6 +147,11 @@ else public void GetAnalysisResults() { + if (AttackSurfaceAnalyzerClient.DatabaseManager is null) + { + analysisResults = new List(); + return; + } var resultType = (RESULT_TYPE)Enum.Parse(typeof(RESULT_TYPE), SelectedResultType); switch (resultType) { @@ -165,6 +167,10 @@ else public void ParseOptsToResultTypes() { foundResultTypes.Clear(); + if (AttackSurfaceAnalyzerClient.DatabaseManager is null) + { + return; + } foreach (var resultType in Enum.GetValues(typeof(RESULT_TYPE))) { var found = AttackSurfaceAnalyzerClient.DatabaseManager.GetComparisonResultsCount(FirstRunId, SecondRunId, AnalysesHash, (int)resultType); diff --git a/Cli/Helper.cs b/Cli/Helper.cs index 5d11c147..fb38dd4e 100644 --- a/Cli/Helper.cs +++ b/Cli/Helper.cs @@ -13,7 +13,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Cli /// public class GlowClass { - public string ClassName; + public string ClassName { get; set; } = string.Empty; } public static string GetGlowClass(bool value) diff --git a/Cli/Pages/Analyze.razor b/Cli/Pages/Analyze.razor index af72a63b..e06ffd14 100644 --- a/Cli/Pages/Analyze.razor +++ b/Cli/Pages/Analyze.razor @@ -49,7 +49,7 @@ Error } - List Runs = AttackSurfaceAnalyzerClient.DatabaseManager.GetRuns(); + List Runs = AttackSurfaceAnalyzerClient.DatabaseManager?.GetRuns() ?? new List(); int RunIdInput { get @@ -99,7 +99,7 @@ await AnalyzeIt(); pageState = PageState.Finished; } - System.Threading.Timer timer; + System.Threading.Timer? timer; async Task AnalyzeIt() { @@ -117,7 +117,7 @@ CompareOneOptions.FirstRunId = appData.ExportCollectCommandOptions.FirstRunId; CompareOneOptions.SecondRunId = appData.ExportCollectCommandOptions.SecondRunId; var results = AttackSurfaceAnalyzerClient.CompareRuns(CompareOneOptions); - AttackSurfaceAnalyzerClient.InsertCompareResults(results, CompareOneOptions.FirstRunId, CompareOneOptions.SecondRunId, appData.CompareCommandOptions.AnalysesFile.GetHash()); + AttackSurfaceAnalyzerClient.InsertCompareResults(results, CompareOneOptions.FirstRunId, CompareOneOptions.SecondRunId, appData.CompareCommandOptions.AnalysesFile?.GetHash() ?? string.Empty); }); return ASA_ERROR.NONE; diff --git a/Cli/Pages/Report.razor b/Cli/Pages/Report.razor index 14012b44..abdcea14 100644 --- a/Cli/Pages/Report.razor +++ b/Cli/Pages/Report.razor @@ -10,13 +10,7 @@ @@ -50,12 +44,4 @@ else this.StateHasChanged(); } } - - System.Threading.Timer timer; - - protected override void OnInitialized() - { - //timer = new System.Threading.Timer((_) => InvokeAsync(() => StateHasChanged()), null, 0, 100); - base.OnInitialized(); - } } diff --git a/Cli/Pages/Sandbox.razor b/Cli/Pages/Sandbox.razor index 91a5de18..3bf4f3f8 100644 --- a/Cli/Pages/Sandbox.razor +++ b/Cli/Pages/Sandbox.razor @@ -29,8 +29,13 @@ +
+ +
@@ -69,11 +74,9 @@
+
-
State
-

Load in JSON serialized Sandbox State.

- - + @if (SandBoxErrors.Any()) { @@ -98,6 +101,24 @@
}
+ + +
+
State
+

Load in JSON serialized Sandbox State.

+ + + + @if (SandBoxErrors.Any()) + { + + } +
@@ -176,14 +197,17 @@ var inputs = new List(); foreach (var param in ctor.GetParameters()) { - var representation = objState?[param.Name]?.ToObject(); - if (representation != null && GetValueFromJObject(param.ParameterType, representation) is { } obj) + if (param.Name is not null) { - inputs.Add(obj); - } - else - { - inputs.Add(null); + var representation = objState?[param.Name]?.ToObject(); + if (representation != null && GetValueFromJObject(param.ParameterType, representation) is { } obj) + { + inputs.Add(obj); + } + else + { + inputs.Add(null); + } } } var empty = ctor.Invoke(inputs.ToArray()); @@ -262,7 +286,7 @@ ScaffoldedObject = new Scaffold(constructors[value]); if (constructors[value].DeclaringType == typeof(CertificateObject)) { - ScaffoldedObject.Parameters["Certificate"] = new Scaffold(typeof(SerializableCertificate).GetConstructors().Where(x => x.GetParameters().Count() > 1).FirstOrDefault()); + ScaffoldedObject.Parameters["Certificate"] = (new Scaffold(typeof(SerializableCertificate).GetConstructors().Where(x => x.GetParameters().Count() > 1).First()), typeof(SerializableCertificate)); } } RefreshState(); @@ -285,7 +309,7 @@ ScaffoldedObject = new Scaffold(constructorToUse, Assemblies); if (constructors[constructorToInvoke].DeclaringType == typeof(CertificateObject)) { - ScaffoldedObject.Parameters["Certificate"] = new Scaffold(typeof(SerializableCertificate).GetConstructors().Where(x => x.GetParameters().Count() > 1).FirstOrDefault()); + ScaffoldedObject.Parameters["Certificate"] = (new Scaffold(typeof(SerializableCertificate).GetConstructors().Where(x => x.GetParameters().Count() > 1).First()), typeof(SerializableCertificate)); } } RefreshState(); @@ -470,7 +494,7 @@ } else if (type.IsEnum) { - if (Enum.TryParse(type, objectState, out object result)) + if (Enum.TryParse(type, objectState, out object? result)) { return Convert.ChangeType(result, type); } @@ -484,13 +508,16 @@ foreach (var obj in AppState.TestObjects) { var t = obj.GetType(); - if (!objects.ContainsKey(t.FullName)) + if (t.FullName is not null) { - objects.Add(t.FullName, new List()); + if (!objects.ContainsKey(t.FullName)) + { + objects.Add(t.FullName, new List()); + } + objects[t.FullName].Add(obj); } - objects[t.FullName].Add(obj); } - var state = new SandboxState(objects); + var state = new Cli.SandboxState(objects); await JSRuntime.InvokeAsync( "FileSaveAs", "SandboxState.json", diff --git a/Cli/wwwroot/css/asa.css b/Cli/wwwroot/css/asa.css index bef08fa1..2e450943 100644 --- a/Cli/wwwroot/css/asa.css +++ b/Cli/wwwroot/css/asa.css @@ -59,6 +59,10 @@ main { border-color: #db7500; } +.form-group { + margin-bottom: 0.5rem; +} + .hover-shadow-circle:hover { box-shadow: 0px 0px 6px 3px rgba(255, 255, 255, 0.7); border-radius: 50%; diff --git a/Directory.Build.props b/Directory.Build.props index 95a6843e..aa3ea4f8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ - 3.3.37 + 3.4.231 all diff --git a/Lib/Collectors/FileSystemCollector.cs b/Lib/Collectors/FileSystemCollector.cs index 50a5cec1..fbe56247 100644 --- a/Lib/Collectors/FileSystemCollector.cs +++ b/Lib/Collectors/FileSystemCollector.cs @@ -91,7 +91,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Collectors try { var fileSecurity = new FileSecurity(path, AccessControlSections.Owner); - IdentityReference oid = fileSecurity.GetOwner(typeof(SecurityIdentifier)); + IdentityReference? oid = fileSecurity.GetOwner(typeof(SecurityIdentifier)); obj.Owner = AsaHelpers.SidToName(oid); } catch (Exception e) @@ -101,7 +101,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Collectors try { var fileSecurity = new FileSecurity(path, AccessControlSections.Group); - IdentityReference gid = fileSecurity.GetGroup(typeof(SecurityIdentifier)); + IdentityReference? gid = fileSecurity.GetGroup(typeof(SecurityIdentifier)); obj.Group = AsaHelpers.SidToName(gid); } catch (Exception e) @@ -193,8 +193,6 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Collectors try { - FileIOPermission fiop = new FileIOPermission(FileIOPermissionAccess.Read, path); - fiop.Demand(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { if (Directory.Exists(path)) @@ -326,14 +324,17 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Collectors Log.Debug("Should be caught in DirectoryWalker {0} {1}", e.GetType().ToString(), path); } - try + if (path is not null) { - obj.LastModified = File.GetLastWriteTimeUtc(path); - obj.Created = File.GetCreationTimeUtc(path); - } - catch (Exception e) - { - Log.Verbose("Failed to get last modified for {0} ({1}:{2})", path, e.GetType(), e.Message); + try + { + obj.LastModified = File.GetLastWriteTimeUtc(path); + obj.Created = File.GetCreationTimeUtc(path); + } + catch (Exception e) + { + Log.Verbose("Failed to get last modified for {0} ({1}:{2})", path, e.GetType(), e.Message); + } } return obj; @@ -383,7 +384,11 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Collectors try { uint clusterSize = 0; - var root = path.Directory.Root.FullName; + var root = path.Directory?.Root.FullName; + if (root is null) + { + throw new ArgumentNullException(nameof(path.Directory)); + } if (!ClusterSizes.ContainsKey(root)) { NativeMethods.GetDiskFreeSpace(root, out uint lpSectorsPerCluster, out uint lpBytesPerSector, out _, out _); @@ -447,7 +452,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Collectors { var opts = new ExtractorOptions() { ExtractSelfOnFail = false }; Extractor extractor = new Extractor(); - foreach (var fso in extractor.ExtractFile(path, opts).Select(fileEntry => FileEntryToFileSystemObject(fileEntry))) + foreach (var fso in extractor.Extract(path, opts).Select(fileEntry => FileEntryToFileSystemObject(fileEntry))) { HandleChange(fso); } diff --git a/Lib/Lib.csproj b/Lib/Lib.csproj index 71ea0493..7c9f1015 100644 --- a/Lib/Lib.csproj +++ b/Lib/Lib.csproj @@ -32,23 +32,23 @@ - + - - + + - + - - + + @@ -60,7 +60,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -77,7 +77,7 @@ - - + + \ No newline at end of file diff --git a/Lib/Objects/CommandOptions.cs b/Lib/Objects/CommandOptions.cs index 0974eee6..f792ef22 100644 --- a/Lib/Objects/CommandOptions.cs +++ b/Lib/Objects/CommandOptions.cs @@ -208,7 +208,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer public string? FirstRunId { get; set; } [Option(HelpText = "Second run (post-install) identifier")] - public string? SecondRunId { get; set; } + public string SecondRunId { get; set; } = string.Empty; } [Verb("export-monitor", HelpText = "Output a .json report for a monitor run")] diff --git a/Lib/Objects/CryptographicKeyObject.cs b/Lib/Objects/CryptographicKeyObject.cs index aa75253b..a2991806 100644 --- a/Lib/Objects/CryptographicKeyObject.cs +++ b/Lib/Objects/CryptographicKeyObject.cs @@ -11,6 +11,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Objects { public CryptographicKeyObject(string Source, TpmAlgId tpmAlgId) { + this.ResultType = Types.RESULT_TYPE.KEY; this.Source = Source; this.tpmAlgId = tpmAlgId; } diff --git a/Lib/Objects/FileMonitorObject.cs b/Lib/Objects/FileMonitorObject.cs index 212b5f1e..7f422198 100644 --- a/Lib/Objects/FileMonitorObject.cs +++ b/Lib/Objects/FileMonitorObject.cs @@ -9,6 +9,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Objects public FileMonitorObject(string PathIn) { Path = PathIn; + ResultType = RESULT_TYPE.FILEMONITOR; } public string? ExtendedResults { get; set; } diff --git a/Lib/Objects/FileSystemObject.cs b/Lib/Objects/FileSystemObject.cs index 4d4cc19f..21b53157 100644 --- a/Lib/Objects/FileSystemObject.cs +++ b/Lib/Objects/FileSystemObject.cs @@ -13,6 +13,12 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Objects ResultType = RESULT_TYPE.FILE; } + public FileSystemObject() + { + Path = string.Empty; + ResultType = RESULT_TYPE.FILE; + } + /// /// If this is windows executable what DLL Characteristics are set /// diff --git a/Lib/Objects/ProcessModuleObject.cs b/Lib/Objects/ProcessModuleObject.cs index cc190d60..5e1c180c 100644 --- a/Lib/Objects/ProcessModuleObject.cs +++ b/Lib/Objects/ProcessModuleObject.cs @@ -6,17 +6,18 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Objects { public class ProcessModuleObject { - public ProcessModuleObject(string FileName, string ModuleName, SerializableFileVersionInfo? FileVersionInfo) + public ProcessModuleObject(string? FileName, string? ModuleName, SerializableFileVersionInfo? FileVersionInfo) { this.FileName = FileName; this.ModuleName = ModuleName; this.FileVersionInfo = FileVersionInfo; } - public string FileName { get; } + public ProcessModuleObject() { } - public SerializableFileVersionInfo? FileVersionInfo { get; } - public string ModuleName { get; } + public string? FileName { get; set; } + public SerializableFileVersionInfo? FileVersionInfo { get; set; } + public string? ModuleName { get; set; } internal static ProcessModuleObject FromProcessModule(ProcessModule mainModule) { diff --git a/Lib/Objects/ProcessObject.cs b/Lib/Objects/ProcessObject.cs index 6f97da03..8f7f8cfc 100644 --- a/Lib/Objects/ProcessObject.cs +++ b/Lib/Objects/ProcessObject.cs @@ -94,7 +94,10 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Objects try { - obj.MainModule = ProcessModuleObject.FromProcessModule(process.MainModule); + if (process.MainModule is { }) + { + obj.MainModule = ProcessModuleObject.FromProcessModule(process.MainModule); + } } catch (Exception e) { diff --git a/Lib/Objects/Signature.cs b/Lib/Objects/Signature.cs index 5589da7b..0360db00 100644 --- a/Lib/Objects/Signature.cs +++ b/Lib/Objects/Signature.cs @@ -34,13 +34,10 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Objects /// /// [JsonConstructor] - public Signature(bool IsAuthenticodeValid) + public Signature() { - this.IsAuthenticodeValid = IsAuthenticodeValid; } - public bool IsAuthenticodeValid { get; set; } - public bool IsTimeValid { get @@ -53,6 +50,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Objects } } + public bool IsAuthenticodeValid { get; set; } public string? SignedHash { get; set; } public string? SignerSerialNumber { get; set; } public SerializableCertificate? SigningCertificate { get; set; } diff --git a/Lib/Objects/Types.cs b/Lib/Objects/Types.cs index 97cd4227..fa4813ea 100644 --- a/Lib/Objects/Types.cs +++ b/Lib/Objects/Types.cs @@ -100,7 +100,8 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Types FAILED_TO_ESTABLISH_MAIN_DB_CONNECTION, UNKNOWN, CANCELLED, - FAILED_TO_COMMIT + FAILED_TO_COMMIT, + DATABASE_NULL } /// diff --git a/Lib/Objects/WifiObject.cs b/Lib/Objects/WifiObject.cs index b725b8bc..0cf8dc60 100644 --- a/Lib/Objects/WifiObject.cs +++ b/Lib/Objects/WifiObject.cs @@ -5,6 +5,7 @@ public WifiObject(string SSID) { this.SSID = SSID; + this.ResultType = Types.RESULT_TYPE.WIFI; } public string? Authentication { get; set; } diff --git a/Lib/Properties/Resources.resx b/Lib/Properties/Resources.resx index 0ee620f8..9d43adbb 100644 --- a/Lib/Properties/Resources.resx +++ b/Lib/Properties/Resources.resx @@ -591,4 +591,13 @@ Rule {0} Clause {1} has specified custom operation but the CustomOperation field is missing. + + The AnalysisFile passed in options was null and analysis cannot be performed. + + + Cryptographic Exception: Failed to get hash of {0}. + + + DatabaseManager is null at execution of {0}. + \ No newline at end of file diff --git a/Lib/Utils/AsaHelpers.cs b/Lib/Utils/AsaHelpers.cs index 70bfd24f..6b13f34b 100644 --- a/Lib/Utils/AsaHelpers.cs +++ b/Lib/Utils/AsaHelpers.cs @@ -194,38 +194,42 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Utils return $"{firstRunId} & {secondRunId}"; } - public static string SidToName(IdentityReference SID) + public static string SidToName(IdentityReference? SID) { - string sid = SID?.Value ?? string.Empty; - string identity = sid; - - if (SidMap.TryGetValue(sid, out string? mappedIdentity)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (mappedIdentity != null) + string sid = SID?.Value ?? string.Empty; + string identity = sid; + + if (SidMap.TryGetValue(sid, out string? mappedIdentity)) { - return mappedIdentity; + if (mappedIdentity != null) + { + return mappedIdentity; + } + else + { + SidMap.TryRemove(sid, out _); + } } - else + + // Only map NTAccounts, https://en.wikipedia.org/wiki/Security_Identifier + if (sid.StartsWith("S-1-5")) { - SidMap.TryRemove(sid, out _); + try + { + identity = SID?.Translate(typeof(NTAccount))?.Value ?? sid; + } + catch (IdentityNotMappedException) //lgtm [cs/empty-catch-block] + { + } } + + SidMap.TryAdd(sid, identity); + + return sid; } - - // Only map NTAccounts, https://en.wikipedia.org/wiki/Security_Identifier - if (sid.StartsWith("S-1-5")) - { - try - { - identity = SID?.Translate(typeof(NTAccount))?.Value ?? sid; - } - catch (IdentityNotMappedException) //lgtm [cs/empty-catch-block] - { - } - } - - SidMap.TryAdd(sid, identity); - - return sid; + return string.Empty; } private static readonly Random random = new Random(); diff --git a/Lib/Utils/CryptoHelpers.cs b/Lib/Utils/CryptoHelpers.cs index 833841e1..bd1a3ade 100644 --- a/Lib/Utils/CryptoHelpers.cs +++ b/Lib/Utils/CryptoHelpers.cs @@ -1,4 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. +using Serilog; using System; using System.IO; using System.Linq; @@ -11,18 +12,42 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Utils { public static string CreateHash(string input) { - byte[] hashOutput = sha512.ComputeHash(Encoding.UTF8.GetBytes(input)); - return Convert.ToBase64String(hashOutput); + try + { + byte[] hashOutput = sha512.ComputeHash(Encoding.UTF8.GetBytes(input)); + return Convert.ToBase64String(hashOutput); + } + catch (CryptographicException e) + { + Log.Warning(e, Strings.Get("Err_CreateHash"), "string"); + return string.Empty; + } } public static byte[] CreateHash(byte[] input) { - return sha512.ComputeHash(input); + try + { + return sha512.ComputeHash(input); + } + catch (CryptographicException e) + { + Log.Warning(e, Strings.Get("Err_CreateHash"), "bytes"); + return Array.Empty(); + } } public static string CreateHash(Stream stream) { - return Convert.ToBase64String(sha512.ComputeHash(stream) ?? Array.Empty()); + try + { + return Convert.ToBase64String(sha512.ComputeHash(stream) ?? Array.Empty()); + } + catch (CryptographicException e) + { + Log.Warning(e, Strings.Get("Err_CreateHash"), "stream"); + return string.Empty; + } } public static double GetRandomPositiveDouble(double max) diff --git a/Lib/Utils/DatabaseManager.cs b/Lib/Utils/DatabaseManager.cs index cc78cd1f..b69148ff 100644 --- a/Lib/Utils/DatabaseManager.cs +++ b/Lib/Utils/DatabaseManager.cs @@ -50,7 +50,7 @@ namespace Microsoft.CST.AttackSurfaceAnalyzer.Utils var runOne = GetRun(baseId); var runTwo = GetRun(compareId); - return runOne?.ResultTypes.Intersect(runTwo?.ResultTypes).ToList() ?? new List(); + return runOne?.ResultTypes.Intersect(runTwo?.ResultTypes ?? new List()).ToList() ?? (runTwo?.ResultTypes ?? new List()); } public abstract bool GetComparisonCompleted(string? firstRunId, string secondRunId, string analysesHash); diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 3d0e5d22..c325b5e1 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -14,8 +14,8 @@ - - + + @@ -49,7 +49,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive