From 0f97498320300b15d180fb69a0a1c6ab0cb80f04 Mon Sep 17 00:00:00 2001 From: Gabe Stocco <98900+gfs@users.noreply.github.com> Date: Thu, 21 May 2020 15:34:37 -0700 Subject: [PATCH] TryExecute (#457) * Better Exception Handling in Collectors (#455) Fix #454 Fix #453 * Catch all collector Exceptions * Replace Execute with TryExecute (#456) --- Cli/Program.cs | 5 +- Lib/Collectors/BaseCollector.cs | 11 ++- Lib/Collectors/ServiceCollector.cs | 142 ++++++++++++++++------------- README.md | 2 +- Tests/CollectorTests.cs | 22 ++--- 5 files changed, 102 insertions(+), 80 deletions(-) diff --git a/Cli/Program.cs b/Cli/Program.cs index 8d6611ff4..9111debe7 100644 --- a/Cli/Program.cs +++ b/Cli/Program.cs @@ -1056,7 +1056,10 @@ public static int RunCollectCommand(CollectCommandOptions opts) { DatabaseManager.BeginTransaction(); - Task.Run(() => c.Execute()); + Task.Run(() => + { + c.TryExecute(); + }); Thread.Sleep(1); diff --git a/Lib/Collectors/BaseCollector.cs b/Lib/Collectors/BaseCollector.cs index 8e18ace39..93cb5b9c3 100644 --- a/Lib/Collectors/BaseCollector.cs +++ b/Lib/Collectors/BaseCollector.cs @@ -20,7 +20,7 @@ public abstract class BaseCollector : IPlatformRunnable { public ConcurrentStack Results { get; } = new ConcurrentStack(); internal CollectCommandOptions opts = new CollectCommandOptions(); - public void Execute() + public void TryExecute() { if (!CanRunOnPlatform()) { @@ -29,7 +29,14 @@ public void Execute() else { Start(); - ExecuteInternal(); + try + { + ExecuteInternal(); + } + catch(Exception e) + { + Log.Debug("Failed to run {0} ({1}:{2})", GetType(), e.GetType(), e.Message); + } Stop(); } } diff --git a/Lib/Collectors/ServiceCollector.cs b/Lib/Collectors/ServiceCollector.cs index 25755659c..dcacc62cd 100644 --- a/Lib/Collectors/ServiceCollector.cs +++ b/Lib/Collectors/ServiceCollector.cs @@ -36,96 +36,108 @@ public override bool CanRunOnPlatform() /// public void ExecuteWindows() { - var fsc = new FileSystemCollector(new CollectCommandOptions() { SingleThread = opts.SingleThread }); - System.Management.SelectQuery sQuery = new System.Management.SelectQuery("select * from Win32_Service"); // where name = '{0}'", "MCShield.exe")); - using System.Management.ManagementObjectSearcher mgmtSearcher = new System.Management.ManagementObjectSearcher(sQuery); - foreach (System.Management.ManagementObject service in mgmtSearcher.Get()) + try { - try + System.Management.SelectQuery sQuery = new System.Management.SelectQuery("select * from Win32_Service"); // where name = '{0}'", "MCShield.exe")); + using System.Management.ManagementObjectSearcher mgmtSearcher = new System.Management.ManagementObjectSearcher(sQuery); + foreach (System.Management.ManagementObject service in mgmtSearcher.Get()) { - var val = service.GetPropertyValue("Name").ToString(); - if (val != null) + try { - var obj = new ServiceObject(val); + var val = service.GetPropertyValue("Name").ToString(); + if (val != null) + { + var obj = new ServiceObject(val); - val = service.GetPropertyValue("AcceptPause")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.AcceptPause = bool.Parse(val); + val = service.GetPropertyValue("AcceptPause")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.AcceptPause = bool.Parse(val); - val = service.GetPropertyValue("AcceptStop")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.AcceptStop = bool.Parse(val); + val = service.GetPropertyValue("AcceptStop")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.AcceptStop = bool.Parse(val); - obj.Caption = service.GetPropertyValue("Caption")?.ToString(); + obj.Caption = service.GetPropertyValue("Caption")?.ToString(); - val = service.GetPropertyValue("CheckPoint")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.CheckPoint = uint.Parse(val, CultureInfo.InvariantCulture); + val = service.GetPropertyValue("CheckPoint")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.CheckPoint = uint.Parse(val, CultureInfo.InvariantCulture); - obj.CreationClassName = service.GetPropertyValue("CreationClassName")?.ToString(); + obj.CreationClassName = service.GetPropertyValue("CreationClassName")?.ToString(); - val = service.GetPropertyValue("DelayedAutoStart")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.DelayedAutoStart = bool.Parse(val); + val = service.GetPropertyValue("DelayedAutoStart")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.DelayedAutoStart = bool.Parse(val); - obj.Description = service.GetPropertyValue("Description")?.ToString(); + obj.Description = service.GetPropertyValue("Description")?.ToString(); - val = service.GetPropertyValue("DesktopInteract")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.DesktopInteract = bool.Parse(val); + val = service.GetPropertyValue("DesktopInteract")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.DesktopInteract = bool.Parse(val); - obj.DisplayName = service.GetPropertyValue("DisplayName")?.ToString(); - obj.ErrorControl = service.GetPropertyValue("ErrorControl")?.ToString(); + obj.DisplayName = service.GetPropertyValue("DisplayName")?.ToString(); + obj.ErrorControl = service.GetPropertyValue("ErrorControl")?.ToString(); - val = service.GetPropertyValue("ExitCode")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.ExitCode = uint.Parse(val, CultureInfo.InvariantCulture); + val = service.GetPropertyValue("ExitCode")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.ExitCode = uint.Parse(val, CultureInfo.InvariantCulture); - if (DateTime.TryParse(service.GetPropertyValue("InstallDate")?.ToString(), out DateTime dateTime)) - { - obj.InstallDate = dateTime; - } - obj.PathName = service.GetPropertyValue("PathName")?.ToString(); + if (DateTime.TryParse(service.GetPropertyValue("InstallDate")?.ToString(), out DateTime dateTime)) + { + obj.InstallDate = dateTime; + } + obj.PathName = service.GetPropertyValue("PathName")?.ToString(); - val = service.GetPropertyValue("ProcessId")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.ProcessId = uint.Parse(val, CultureInfo.InvariantCulture); + val = service.GetPropertyValue("ProcessId")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.ProcessId = uint.Parse(val, CultureInfo.InvariantCulture); - val = service.GetPropertyValue("ServiceSpecificExitCode")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.ServiceSpecificExitCode = uint.Parse(val, CultureInfo.InvariantCulture); + val = service.GetPropertyValue("ServiceSpecificExitCode")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.ServiceSpecificExitCode = uint.Parse(val, CultureInfo.InvariantCulture); - obj.ServiceType = service.GetPropertyValue("ServiceType")?.ToString(); + obj.ServiceType = service.GetPropertyValue("ServiceType")?.ToString(); - val = service.GetPropertyValue("Started").ToString(); - if (!string.IsNullOrEmpty(val)) - obj.Started = bool.Parse(val); + val = service.GetPropertyValue("Started").ToString(); + if (!string.IsNullOrEmpty(val)) + obj.Started = bool.Parse(val); - obj.StartMode = service.GetPropertyValue("StartMode")?.ToString(); - obj.StartName = service.GetPropertyValue("StartName")?.ToString(); - obj.State = service.GetPropertyValue("State")?.ToString(); - obj.Status = service.GetPropertyValue("Status")?.ToString(); - obj.SystemCreationClassName = service.GetPropertyValue("SystemCreationClassName")?.ToString(); - obj.SystemName = service.GetPropertyValue("SystemName")?.ToString(); + obj.StartMode = service.GetPropertyValue("StartMode")?.ToString(); + obj.StartName = service.GetPropertyValue("StartName")?.ToString(); + obj.State = service.GetPropertyValue("State")?.ToString(); + obj.Status = service.GetPropertyValue("Status")?.ToString(); + obj.SystemCreationClassName = service.GetPropertyValue("SystemCreationClassName")?.ToString(); + obj.SystemName = service.GetPropertyValue("SystemName")?.ToString(); - val = service.GetPropertyValue("TagId")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.TagId = uint.Parse(val, CultureInfo.InvariantCulture); + val = service.GetPropertyValue("TagId")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.TagId = uint.Parse(val, CultureInfo.InvariantCulture); - val = service.GetPropertyValue("WaitHint")?.ToString(); - if (!string.IsNullOrEmpty(val)) - obj.WaitHint = uint.Parse(val, CultureInfo.InvariantCulture); + val = service.GetPropertyValue("WaitHint")?.ToString(); + if (!string.IsNullOrEmpty(val)) + obj.WaitHint = uint.Parse(val, CultureInfo.InvariantCulture); - Results.Push(obj); + Results.Push(obj); + } + } + catch (Exception e) when ( + e is TypeInitializationException || + e is PlatformNotSupportedException) + { + Log.Warning(Strings.Get("CollectorNotSupportedOnPlatform"), GetType().ToString()); + } + catch (Exception e) + { + Log.Warning(e, "Failed to grok Service Collector object at {0}.",service.Path); } - } - catch (Exception e) when ( - e is TypeInitializationException || - e is PlatformNotSupportedException) - { - Log.Warning(Strings.Get("CollectorNotSupportedOnPlatform"), GetType().ToString()); } } + catch (Exception e) + { + Log.Warning(e, "Failed to run Service Collector."); + } + + var fsc = new FileSystemCollector(new CollectCommandOptions() { SingleThread = opts.SingleThread }); foreach (var file in Directory.EnumerateFiles("C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup")) { diff --git a/README.md b/README.md index 58ecab780..0849012cc 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ All data collected is stored in a set of local SQLite databases. Run the following commands in an Administrator Shell (or as root). Replace ```asa``` with ```asa.exe``` as appropriate for your platform. ### CLI Mode -To start a default all collectors run: ```asa collect``` +To start a default all collectors run: ```asa collect -a``` To compare the last two collection runs: ```asa export-collect``` diff --git a/Tests/CollectorTests.cs b/Tests/CollectorTests.cs index 700442df4..2ac128249 100644 --- a/Tests/CollectorTests.cs +++ b/Tests/CollectorTests.cs @@ -63,7 +63,7 @@ public void TestFileCollector() } var fsc = new FileSystemCollector(opts); - fsc.Execute(); + fsc.TryExecute(); Assert.IsTrue(fsc.Results.Any(x => x is FileSystemObject FSO && FSO.Path.EndsWith("AsaLibTesterJavaClass") && FSO.IsExecutable == true)); Assert.IsTrue(fsc.Results.Any(x => x is FileSystemObject FSO && FSO.Path.EndsWith("AsaLibTesterMZ") && FSO.IsExecutable == true)); @@ -93,7 +93,7 @@ public void TestEventCollectorWindows() eventLog.WriteEntry("This Log Entry was created for testing the Attack Surface Analyzer library.", EventLogEntryType.Warning, 101, 1); var fsc = new EventLogCollector(new CollectCommandOptions()); - fsc.Execute(); + fsc.TryExecute(); EventLog.DeleteEventSource(source); EventLog.Delete(logname); @@ -108,7 +108,7 @@ public void TestEventCollectorWindows() public void TestCertificateCollectorWindows() { var fsc = new CertificateCollector(); - fsc.Execute(); + fsc.TryExecute(); Assert.IsTrue(fsc.Results.Where(x => x.ResultType == RESULT_TYPE.CERTIFICATE).Count() > 0); } @@ -137,7 +137,7 @@ public void TestPortCollectorWindows() Console.WriteLine("Failed to open port."); } var fsc = new OpenPortCollector(); - fsc.Execute(); + fsc.TryExecute(); server.Stop(); Assert.IsTrue(fsc.Results.Any(x => x is OpenPortObject OPO && OPO.Port == 13000)); @@ -154,7 +154,7 @@ public void TestFirewallCollectorOSX() _ = ExternalCommandRunner.RunExternalCommand("/usr/libexec/ApplicationFirewall/socketfilterfw", "--add /bin/bash"); var fwc = new FirewallCollector(); - fwc.Execute(); + fwc.TryExecute(); _ = ExternalCommandRunner.RunExternalCommand("/usr/libexec/ApplicationFirewall/socketfilterfw", "--remove /bin/bash"); Assert.IsTrue(fwc.Results.Any(x => x is FirewallObject FWO && FWO.ApplicationName == "/bin/bash")); } @@ -171,7 +171,7 @@ public void TestFirewallCollectorLinux() var result = ExternalCommandRunner.RunExternalCommand("iptables", "-A INPUT -p tcp --dport 19999 -j DROP"); var fwc = new FirewallCollector(); - fwc.Execute(); + fwc.TryExecute(); Assert.IsTrue(fwc.Results.Any(x => x is FirewallObject FWO && FWO.LocalPorts.Contains("19999"))); @@ -204,7 +204,7 @@ public void TestFirewallCollectorWindows() FirewallManager.Instance.Rules.Add(rule); var fwc = new FirewallCollector(); - fwc.Execute(); + fwc.TryExecute(); Assert.IsTrue(fwc.Results.Any(x => x is FirewallObject FWO && FWO.LocalPorts.Contains("9999"))); Assert.IsTrue(fwc.Results.Any(x => x is FirewallObject FWO && FWO.ApplicationName is string && FWO.ApplicationName.Equals(@"C:\MyApp.exe"))); @@ -243,7 +243,7 @@ public void TestRegistryCollectorWindows() key.Close(); var rc = new RegistryCollector(new List<(RegistryHive, string)>() { (RegistryHive.CurrentUser, name) }, new CollectCommandOptions() { SingleThread = true }); - rc.Execute(); + rc.TryExecute(); Registry.CurrentUser.DeleteSubKey(name); @@ -267,7 +267,7 @@ public void TestServiceCollectorWindows() ExternalCommandRunner.RunExternalCommand("sc.exe", cmd); var sc = new ServiceCollector(); - sc.Execute(); + sc.TryExecute(); Assert.IsTrue(sc.Results.Any(x => x is ServiceObject RO && RO.Name.Equals(serviceName))); @@ -286,7 +286,7 @@ public void TestComObjectCollector() if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var coc = new ComObjectCollector(new CollectCommandOptions()); - coc.Execute(); + coc.TryExecute(); Assert.IsTrue(coc.Results.Any(x => x is ComObject y && y.x86_Binary != null)); } @@ -308,7 +308,7 @@ public void TestUserCollectorWindows() ExternalCommandRunner.RunExternalCommand("net", cmd); var uac = new UserAccountCollector(); - uac.Execute(); + uac.TryExecute(); Assert.IsTrue(uac.Results.Any(x => x is UserAccountObject y && y.Name.Equals(user)));