private static int RunMonitorCommand(MonitorCommandOptions opts) { #if DEBUG Logger.Setup(true, opts.Verbose); #else Logger.Setup(opts.Debug, opts.Verbose); #endif AdminOrQuit(); SetupOrDie(opts.DatabaseFilename); AsaTelemetry.Setup(); Dictionary <string, string> StartEvent = new Dictionary <string, string>(); StartEvent.Add("Files", opts.EnableFileSystemMonitor.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Admin", AsaHelpers.IsAdmin().ToString(CultureInfo.InvariantCulture)); AsaTelemetry.TrackEvent("Begin monitoring", StartEvent); CheckFirstRun(); if (opts.RunId is string) { opts.RunId = opts.RunId.Trim(); } else { opts.RunId = DateTime.Now.ToString("o", CultureInfo.InvariantCulture); } if (opts.Overwrite) { DatabaseManager.DeleteRun(opts.RunId); } else { if (DatabaseManager.GetRun(opts.RunId) != null) { Log.Error(Strings.Get("Err_RunIdAlreadyUsed")); return((int)ASA_ERROR.UNIQUE_ID); } } var run = new AsaRun(RunId: opts.RunId, Timestamp: DateTime.Now, Version: AsaHelpers.GetVersionString(), Platform: AsaHelpers.GetPlatform(), new List <RESULT_TYPE>() { RESULT_TYPE.FILEMONITOR }, RUN_TYPE.MONITOR); DatabaseManager.InsertRun(run); int returnValue = 0; if (opts.EnableFileSystemMonitor) { List <String> directories = new List <string>(); if (opts.MonitoredDirectories != null) { var parts = opts.MonitoredDirectories.Split(','); foreach (String part in parts) { directories.Add(part); } } else { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { directories.Add("/"); } if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { directories.Add("C:\\"); } if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { directories.Add("/"); } } List <NotifyFilters> filterOptions = new List <NotifyFilters> { NotifyFilters.Attributes, NotifyFilters.CreationTime, NotifyFilters.DirectoryName, NotifyFilters.FileName, NotifyFilters.LastAccess, NotifyFilters.LastWrite, NotifyFilters.Security, NotifyFilters.Size }; foreach (String dir in directories) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { var newMon = new FileSystemMonitor(opts.RunId, dir, false); monitors.Add(newMon); } else { foreach (NotifyFilters filter in filterOptions) { Log.Information("Adding Path {0} Filter Type {1}", dir, filter.ToString()); var newMon = new FileSystemMonitor(opts.RunId, dir, false, filter); monitors.Add(newMon); } } } } //if (opts.EnableRegistryMonitor) //{ //var monitor = new RegistryMonitor(); //monitors.Add(monitor); //} if (monitors.Count == 0) { Log.Warning(Strings.Get("Err_NoMonitors")); returnValue = (int)ASA_ERROR.NO_COLLECTORS; } using var exitEvent = new ManualResetEvent(false); // If duration is set, we use the secondary timer. if (opts.Duration > 0) { Log.Information("{0} {1} {2}.", Strings.Get("MonitorStartedFor"), opts.Duration, Strings.Get("Minutes")); using var aTimer = new System.Timers.Timer { Interval = opts.Duration * 60 * 1000, AutoReset = false, }; aTimer.Elapsed += (source, e) => { exitEvent.Set(); }; // Start the timer aTimer.Enabled = true; } foreach (FileSystemMonitor c in monitors) { Log.Information(Strings.Get("Begin"), c.GetType().Name); try { c.StartRun(); } catch (Exception ex) { Log.Error(Strings.Get("Err_CollectingFrom"), c.GetType().Name, ex.Message, ex.StackTrace); returnValue = 1; } } // Set up the event to capture CTRL+C Console.CancelKeyPress += (sender, eventArgs) => { eventArgs.Cancel = true; exitEvent.Set(); }; Console.Write(Strings.Get("MonitoringPressC")); // Write a spinner and wait until CTRL+C WriteSpinner(exitEvent); Log.Information(""); foreach (var c in monitors) { Log.Information(Strings.Get("End"), c.GetType().Name); try { c.StopRun(); if (c is FileSystemMonitor) { ((FileSystemMonitor)c).Dispose(); } } catch (Exception ex) { Log.Error(ex, " {0}: {1}", c.GetType().Name, ex.Message, Strings.Get("Err_Stopping")); } } DatabaseManager.Commit(); return(returnValue); }
private static int RunConfigCommand(ConfigCommandOptions opts) { SetupOrDie(opts.DatabaseFilename); CheckFirstRun(); AsaTelemetry.Setup(); if (opts.ResetDatabase) { var filename = DatabaseManager.SqliteFilename; DatabaseManager.Destroy(); Log.Information(Strings.Get("DeletedDatabaseAt"), filename); } else { if (opts.ListRuns) { if (DatabaseManager.FirstRun) { Log.Warning(Strings.Get("FirstRunListRunsError"), opts.DatabaseFilename); } else { Log.Information(Strings.Get("DumpingDataFromDatabase"), opts.DatabaseFilename); List <string> CollectRuns = DatabaseManager.GetRuns(RUN_TYPE.COLLECT); if (CollectRuns.Count > 0) { Log.Information(Strings.Get("Begin"), Strings.Get("EnumeratingCollectRunIds")); foreach (string runId in CollectRuns) { var run = DatabaseManager.GetRun(runId); if (run is AsaRun) { Log.Information("RunId:{2} Timestamp:{0} AsaVersion:{1} ", run.Timestamp, run.Version, run.RunId); var resultTypesAndCounts = DatabaseManager.GetResultTypesAndCounts(run.RunId); foreach (var kvPair in resultTypesAndCounts) { Log.Information("{0} : {1}", kvPair.Key, kvPair.Value); } } } } else { Log.Information(Strings.Get("NoCollectRuns")); } List <string> MonitorRuns = DatabaseManager.GetRuns(RUN_TYPE.MONITOR); if (MonitorRuns.Count > 0) { Log.Information(Strings.Get("Begin"), Strings.Get("EnumeratingMonitorRunIds")); foreach (string monitorRun in MonitorRuns) { var run = DatabaseManager.GetRun(monitorRun); if (run != null) { string output = $"{run.RunId} {run.Timestamp} {run.Version} {run.Type}"; Log.Information(output); Log.Information(string.Join(',', run.ResultTypes.Where(x => run.ResultTypes.Contains(x)))); } } } else { Log.Information(Strings.Get("NoMonitorRuns")); } } } if (opts.TelemetryOptOut != null) { AsaTelemetry.SetEnabled(!bool.Parse(opts.TelemetryOptOut)); Log.Information(Strings.Get("TelemetryOptOut"), (bool.Parse(opts.TelemetryOptOut)) ? "Opted out" : "Opted in"); } if (opts.DeleteRunId != null) { DatabaseManager.DeleteRun(opts.DeleteRunId); } if (opts.TrimToLatest) { DatabaseManager.TrimToLatest(); } } return(0); }
private static int RunExportCollectCommand(ExportCollectCommandOptions opts) { #if DEBUG Logger.Setup(true, opts.Verbose, opts.Quiet); #else Logger.Setup(opts.Debug, opts.Verbose, opts.Quiet); #endif if (opts.OutputPath != null && !Directory.Exists(opts.OutputPath)) { Log.Fatal(Strings.Get("Err_OutputPathNotExist"), opts.OutputPath); return(0); } SetupOrDie(opts.DatabaseFilename); CheckFirstRun(); AsaTelemetry.Setup(); if (opts.FirstRunId is null || opts.SecondRunId is null) { Log.Information("Provided null run Ids using latest two runs."); List <string> runIds = DatabaseManager.GetLatestRunIds(2, RUN_TYPE.COLLECT); if (runIds.Count < 2) { Log.Fatal(Strings.Get("Err_CouldntDetermineTwoRun")); System.Environment.Exit(-1); } else { opts.SecondRunId = runIds.First(); opts.FirstRunId = runIds.ElementAt(1); } } if (opts.FirstRunId is null || opts.SecondRunId is null) { return((int)ASA_ERROR.INVALID_ID); } Log.Information(Strings.Get("Comparing"), opts.FirstRunId, opts.SecondRunId); Dictionary <string, string> StartEvent = new Dictionary <string, string>(); StartEvent.Add("OutputPathSet", (opts.OutputPath != null).ToString(CultureInfo.InvariantCulture)); AsaTelemetry.TrackEvent("{0} Export Compare", StartEvent); CompareCommandOptions options = new CompareCommandOptions(opts.FirstRunId, opts.SecondRunId) { DatabaseFilename = opts.DatabaseFilename, AnalysesFile = opts.AnalysesFile, Analyze = opts.Analyze, SaveToDatabase = opts.SaveToDatabase }; Dictionary <string, object> results = CompareRuns(options); JsonSerializer serializer = JsonSerializer.Create(new JsonSerializerSettings() { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore, Converters = new List <JsonConverter>() { new StringEnumConverter() }, ContractResolver = new AsaExportContractResolver() }); var outputPath = opts.OutputPath; if (outputPath is null) { outputPath = Directory.GetCurrentDirectory(); } if (opts.ExplodedOutput) { results.Add("metadata", AsaHelpers.GenerateMetadata()); string path = Path.Combine(outputPath, AsaHelpers.MakeValidFileName(opts.FirstRunId + "_vs_" + opts.SecondRunId)); Directory.CreateDirectory(path); foreach (var key in results.Keys) { string filePath = Path.Combine(path, AsaHelpers.MakeValidFileName(key)); using (StreamWriter sw = new StreamWriter(filePath)) //lgtm[cs/path-injection] { using (JsonWriter writer = new JsonTextWriter(sw)) { serializer.Serialize(writer, results[key]); } } } Log.Information(Strings.Get("OutputWrittenTo"), (new DirectoryInfo(path)).FullName); } else { string path = Path.Combine(outputPath, AsaHelpers.MakeValidFileName(opts.FirstRunId + "_vs_" + opts.SecondRunId + "_summary.json.txt")); var output = new Dictionary <string, Object>(); output["results"] = results; output["metadata"] = AsaHelpers.GenerateMetadata(); using (StreamWriter sw = new StreamWriter(path)) //lgtm[cs/path-injection] { using (JsonWriter writer = new JsonTextWriter(sw)) { serializer.Serialize(writer, output); } } Log.Information(Strings.Get("OutputWrittenTo"), (new FileInfo(path)).FullName); } return(0); }
public void Compare(string firstRunId, string secondRunId) { if (firstRunId == null) { throw new ArgumentNullException(nameof(firstRunId)); } if (secondRunId == null) { throw new ArgumentNullException(nameof(secondRunId)); } List <RawCollectResult> addObjects = DatabaseManager.GetMissingFromFirst(firstRunId, secondRunId); List <RawCollectResult> removeObjects = DatabaseManager.GetMissingFromFirst(secondRunId, firstRunId); List <RawModifiedResult> modifyObjects = DatabaseManager.GetModified(firstRunId, secondRunId); Parallel.ForEach(addObjects, (added => { var obj = new CompareResult() { Compare = added.DeserializedObject, BaseRunId = firstRunId, CompareRunId = secondRunId, CompareRowKey = added.RowKey, ChangeType = CHANGE_TYPE.CREATED, ResultType = added.ResultType, Identity = added.Identity }; Log.Debug($"Adding {obj.Identity}"); Results[$"{added.ResultType.ToString()}_{CHANGE_TYPE.CREATED.ToString()}"].Enqueue(obj); })); Parallel.ForEach(removeObjects, (removed => { var obj = new CompareResult() { Base = removed.DeserializedObject, BaseRunId = firstRunId, CompareRunId = secondRunId, BaseRowKey = removed.RowKey, ChangeType = CHANGE_TYPE.DELETED, ResultType = removed.ResultType, Identity = removed.Identity }; Results[$"{removed.ResultType.ToString()}_{CHANGE_TYPE.DELETED.ToString()}"].Enqueue(obj); })); Parallel.ForEach(modifyObjects, (modified => { var compareLogic = new CompareLogic(); compareLogic.Config.IgnoreCollectionOrder = true; var first = modified.First.DeserializedObject; var second = modified.Second.DeserializedObject; var obj = new CompareResult() { Base = first, Compare = second, BaseRunId = firstRunId, CompareRunId = secondRunId, BaseRowKey = modified.First.RowKey, CompareRowKey = modified.Second.RowKey, ChangeType = CHANGE_TYPE.MODIFIED, ResultType = modified.First.ResultType, Identity = modified.First.Identity }; var properties = first.GetType().GetProperties(); foreach (var prop in properties) { try { var propName = prop.Name; List <Diff> diffs; object added = null; object removed = null; object changed = new object(); object firstProp = prop.GetValue(first); object secondProp = prop.GetValue(second); if (firstProp == null && secondProp == null) { continue; } else if (firstProp == null && secondProp != null) { added = prop.GetValue(second); diffs = GetDiffs(prop, added, null); } else if (secondProp == null && firstProp != null) { removed = prop.GetValue(first); diffs = GetDiffs(prop, null, removed); } else if (firstProp != null && secondProp != null && compareLogic.Compare(firstProp, secondProp).AreEqual) { continue; } else { var firstVal = prop.GetValue(first); var secondVal = prop.GetValue(second); if (firstVal is List <string> ) { added = ((List <string>)prop.GetValue(second)).Except((List <string>)prop.GetValue(first)); removed = ((List <string>)prop.GetValue(first)).Except((List <string>)prop.GetValue(second)); if (!((IEnumerable <string>)added).Any()) { added = null; } if (!((IEnumerable <string>)removed).Any()) { removed = null; } } else if (firstVal is List <KeyValuePair <string, string> > ) { added = ((List <KeyValuePair <string, string> >)prop.GetValue(second)).Except((List <KeyValuePair <string, string> >)prop.GetValue(first)); removed = ((List <KeyValuePair <string, string> >)prop.GetValue(first)).Except((List <KeyValuePair <string, string> >)prop.GetValue(second)); if (!((IEnumerable <KeyValuePair <string, string> >)added).Any()) { added = null; } if (!((IEnumerable <KeyValuePair <string, string> >)removed).Any()) { removed = null; } } else if (firstVal is Dictionary <string, string> ) { added = ((Dictionary <string, string>)secondVal) .Except((Dictionary <string, string>)firstVal) .ToDictionary(x => x.Key, x => x.Value); removed = ((Dictionary <string, string>)firstVal) .Except((Dictionary <string, string>)secondVal) .ToDictionary(x => x.Key, x => x.Value); if (!((IEnumerable <KeyValuePair <string, string> >)added).Any()) { added = null; } if (!((IEnumerable <KeyValuePair <string, string> >)removed).Any()) { removed = null; } } else if (firstVal is string || firstVal is int || firstVal is bool) { obj.Diffs.Add(new Diff() { Field = prop.Name, Before = firstVal, After = secondVal }); } else { obj.Diffs.Add(new Diff() { Field = prop.Name, Before = firstVal, After = secondVal }); } diffs = GetDiffs(prop, added, removed); } foreach (var diff in diffs) { obj.Diffs.Add(diff); } } catch (InvalidCastException e) { Log.Debug(e, $"Failed to cast {JsonSerializer.Serialize(prop)}"); } catch (Exception e) { Log.Debug(e, "Generic exception. Tell a programmer."); Dictionary <string, string> ExceptionEvent = new Dictionary <string, string>(); ExceptionEvent.Add("Exception Type", e.GetType().ToString()); AsaTelemetry.TrackEvent("CompareException", ExceptionEvent); } } Results[$"{modified.First.ResultType.ToString()}_{CHANGE_TYPE.MODIFIED.ToString()}"].Enqueue(obj); })); foreach (var empty in Results.Where(x => x.Value.Count == 0)) { Results.Remove(empty.Key, out _); } }
public static void ClassSetup(TestContext _) { Logger.Setup(false, true); Strings.Setup(); AsaTelemetry.Setup(test: true); }
public void Setup() { Logger.Setup(false, true); Strings.Setup(); AsaTelemetry.Setup(test: true); }
public ActionResult ChangeTelemetryState(bool DisableTelemetry) { AsaTelemetry.SetOptOut(DisableTelemetry); return(Json(true)); }
public static int RunCollectCommand(CollectCommandOptions opts) { if (opts == null) { return(-1); } #if DEBUG Logger.Setup(true, opts.Verbose, opts.Quiet); #else Logger.Setup(opts.Debug, opts.Verbose, opts.Quiet); #endif DatabaseManager.Setup(opts.DatabaseFilename); AsaTelemetry.Setup(); Dictionary <string, string> StartEvent = new Dictionary <string, string>(); StartEvent.Add("Files", opts.EnableAllCollectors ? "True" : opts.EnableFileSystemCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Ports", opts.EnableNetworkPortCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Users", opts.EnableUserCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Certificates", opts.EnableCertificateCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Registry", opts.EnableRegistryCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Service", opts.EnableServiceCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Firewall", opts.EnableFirewallCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("ComObject", opts.EnableComObjectCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("EventLog", opts.EnableEventLogCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Admin", AsaHelpers.IsAdmin().ToString(CultureInfo.InvariantCulture)); AsaTelemetry.TrackEvent("Run Command", StartEvent); AdminOrQuit(); CheckFirstRun(); DatabaseManager.VerifySchemaVersion(); int returnValue = (int)GUI_ERROR.NONE; opts.RunId = opts.RunId.Trim(); if (opts.RunId.Equals("Timestamp", StringComparison.InvariantCulture)) { opts.RunId = DateTime.Now.ToString("o", CultureInfo.InvariantCulture); } if (opts.MatchedCollectorId != null) { var resultTypes = DatabaseManager.GetResultTypes(opts.MatchedCollectorId); foreach (var resultType in resultTypes) { switch (resultType.Key) { case RESULT_TYPE.FILE: opts.EnableFileSystemCollector = resultType.Value; break; case RESULT_TYPE.PORT: opts.EnableNetworkPortCollector = resultType.Value; break; case RESULT_TYPE.CERTIFICATE: opts.EnableCertificateCollector = resultType.Value; break; case RESULT_TYPE.COM: opts.EnableComObjectCollector = resultType.Value; break; case RESULT_TYPE.FIREWALL: opts.EnableFirewallCollector = resultType.Value; break; case RESULT_TYPE.LOG: opts.EnableEventLogCollector = resultType.Value; break; case RESULT_TYPE.SERVICE: opts.EnableServiceCollector = resultType.Value; break; case RESULT_TYPE.USER: opts.EnableUserCollector = resultType.Value; break; } } } var dict = new Dictionary <RESULT_TYPE, bool>(); if (opts.EnableFileSystemCollector || opts.EnableAllCollectors) { collectors.Add(new FileSystemCollector(opts.RunId, enableHashing: opts.GatherHashes, directories: opts.SelectedDirectories, downloadCloud: opts.DownloadCloud, examineCertificates: opts.CertificatesFromFiles, parallel: opts.Parallelization)); dict.Add(RESULT_TYPE.FILE, true); } if (opts.EnableNetworkPortCollector || opts.EnableAllCollectors) { collectors.Add(new OpenPortCollector(opts.RunId)); dict.Add(RESULT_TYPE.PORT, true); } if (opts.EnableServiceCollector || opts.EnableAllCollectors) { collectors.Add(new ServiceCollector(opts.RunId)); dict.Add(RESULT_TYPE.SERVICE, true); } if (opts.EnableUserCollector || opts.EnableAllCollectors) { collectors.Add(new UserAccountCollector(opts.RunId)); dict.Add(RESULT_TYPE.USER, true); } if (opts.EnableRegistryCollector || (opts.EnableAllCollectors && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))) { collectors.Add(new RegistryCollector(opts.RunId, opts.Parallelization)); dict.Add(RESULT_TYPE.REGISTRY, true); } if (opts.EnableCertificateCollector || opts.EnableAllCollectors) { collectors.Add(new CertificateCollector(opts.RunId)); dict.Add(RESULT_TYPE.CERTIFICATE, true); } if (opts.EnableFirewallCollector || opts.EnableAllCollectors) { collectors.Add(new FirewallCollector(opts.RunId)); dict.Add(RESULT_TYPE.FIREWALL, true); } if (opts.EnableComObjectCollector || (opts.EnableAllCollectors && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))) { collectors.Add(new ComObjectCollector(opts.RunId)); dict.Add(RESULT_TYPE.COM, true); } if (opts.EnableEventLogCollector || opts.EnableAllCollectors) { collectors.Add(new EventLogCollector(opts.RunId, opts.GatherVerboseLogs)); dict.Add(RESULT_TYPE.LOG, true); } if (collectors.Count == 0) { Log.Warning(Strings.Get("Err_NoCollectors")); return((int)GUI_ERROR.NO_COLLECTORS); } if (!opts.NoFilters) { if (opts.FilterLocation.Equals("Use embedded filters.", StringComparison.InvariantCulture)) { Filter.LoadEmbeddedFilters(); } else { Filter.LoadFilters(opts.FilterLocation); } } if (opts.Overwrite) { DatabaseManager.DeleteRun(opts.RunId); } else { if (DatabaseManager.GetRun(opts.RunId) != null) { Log.Error(Strings.Get("Err_RunIdAlreadyUsed")); return((int)GUI_ERROR.UNIQUE_ID); } } Log.Information(Strings.Get("Begin"), opts.RunId); DatabaseManager.InsertRun(opts.RunId, dict); Log.Information(Strings.Get("StartingN"), collectors.Count.ToString(CultureInfo.InvariantCulture), Strings.Get("Collectors")); Console.CancelKeyPress += delegate { Log.Information("Cancelling collection. Rolling back transaction. Please wait to avoid corrupting database."); DatabaseManager.Transaction.Rollback(); Environment.Exit(0); }; Dictionary <string, string> EndEvent = new Dictionary <string, string>(); foreach (BaseCollector c in collectors) { try { c.Execute(); EndEvent.Add(c.GetType().ToString(), c.NumCollected().ToString(CultureInfo.InvariantCulture)); } catch (Exception e) { Log.Error(Strings.Get("Err_CollectingFrom"), c.GetType().Name, e.Message, e.StackTrace); Dictionary <string, string> ExceptionEvent = new Dictionary <string, string>(); ExceptionEvent.Add("Exception Type", e.GetType().ToString()); ExceptionEvent.Add("Stack Trace", e.StackTrace); ExceptionEvent.Add("Message", e.Message); AsaTelemetry.TrackEvent("CollectorCrashRogueException", ExceptionEvent); returnValue = 1; } } AsaTelemetry.TrackEvent("End Command", EndEvent); DatabaseManager.Commit(); return(returnValue); }
private static int RunConfigCommand(ConfigCommandOptions opts) { DatabaseManager.Setup(opts.DatabaseFilename); CheckFirstRun(); AsaTelemetry.Setup(); if (opts.ResetDatabase) { DatabaseManager.CloseDatabase(); try { File.Delete(opts.DatabaseFilename); } catch (IOException e) { Log.Fatal(e, Strings.Get("FailedToDeleteDatabase"), opts.DatabaseFilename, e.GetType().ToString(), e.Message); Environment.Exit(-1); } Log.Information(Strings.Get("DeletedDatabaseAt"), opts.DatabaseFilename); } else { DatabaseManager.VerifySchemaVersion(); if (opts.ListRuns) { if (DatabaseManager.FirstRun) { Log.Warning(Strings.Get("FirstRunListRunsError"), opts.DatabaseFilename); } else { Log.Information(Strings.Get("DumpingDataFromDatabase"), opts.DatabaseFilename); List <string> CollectRuns = DatabaseManager.GetRuns("collect"); if (CollectRuns.Count > 0) { Log.Information(Strings.Get("Begin"), Strings.Get("EnumeratingCollectRunIds")); foreach (string runId in CollectRuns) { var run = DatabaseManager.GetRun(runId); Log.Information("RunId:{2} Timestamp:{0} AsaVersion:{1} ", run.Timestamp, run.Version, run.RunId); var resultTypesAndCounts = DatabaseManager.GetResultTypesAndCounts(run.RunId); foreach (var kvPair in resultTypesAndCounts) { Log.Information("{0} : {1}", kvPair.Key, kvPair.Value); } } } else { Log.Information(Strings.Get("NoCollectRuns")); } List <string> MonitorRuns = DatabaseManager.GetRuns("monitor"); if (MonitorRuns.Count > 0) { Log.Information(Strings.Get("Begin"), Strings.Get("EnumeratingMonitorRunIds")); foreach (string monitorRun in MonitorRuns) { var run = DatabaseManager.GetRun(monitorRun); if (run != null) { string output = $"{run.RunId} {run.Timestamp} {run.Version} {run.Type}"; Log.Information(output); Log.Information(string.Join(',', run.ResultTypes.Keys.Where(x => run.ResultTypes[x]))); } } } else { Log.Information(Strings.Get("NoMonitorRuns")); } } } if (opts.TelemetryOptOut != null) { AsaTelemetry.SetOptOut(bool.Parse(opts.TelemetryOptOut)); Log.Information(Strings.Get("TelemetryOptOut"), (bool.Parse(opts.TelemetryOptOut)) ? "Opted out" : "Opted in"); } if (opts.DeleteRunId != null) { DatabaseManager.DeleteRun(opts.DeleteRunId); } if (opts.TrimToLatest) { DatabaseManager.TrimToLatest(); } } return(0); }
public ActionResult ChangeTelemetryState(bool EnableTelemetry) { AsaTelemetry.SetEnabled(EnableTelemetry); return(Json(true)); }
public static Dictionary <string, object> CompareRuns(CompareCommandOptions opts) { if (opts is null) { throw new ArgumentNullException(nameof(opts)); } if (opts.SaveToDatabase) { DatabaseManager.InsertCompareRun(opts.FirstRunId, opts.SecondRunId, RUN_STATUS.RUNNING); } var results = new Dictionary <string, object>(); comparators = new List <BaseCompare>(); Dictionary <string, string> EndEvent = new Dictionary <string, string>(); BaseCompare c = new BaseCompare(); var watch = System.Diagnostics.Stopwatch.StartNew(); if (!c.TryCompare(opts.FirstRunId, opts.SecondRunId)) { Log.Warning(Strings.Get("Err_Comparing") + " : {0}", c.GetType().Name); } c.Results.ToList().ForEach(x => results.Add(x.Key, x.Value)); watch.Stop(); TimeSpan t = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds); string 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"), "Comparing", answer); if (opts.Analyze) { watch = System.Diagnostics.Stopwatch.StartNew(); Analyzer analyzer; analyzer = new Analyzer(DatabaseManager.RunIdToPlatform(opts.FirstRunId), opts.AnalysesFile); if (results.Count > 0) { foreach (var key in results.Keys) { try { Parallel.ForEach(results[key] as ConcurrentQueue <CompareResult>, (result) => { result.Analysis = analyzer.Analyze(result); }); } catch (ArgumentNullException) { } } } 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 = System.Diagnostics.Stopwatch.StartNew(); if (opts.SaveToDatabase) { foreach (var key in results.Keys) { try { foreach (var result in (results[key] as ConcurrentQueue <CompareResult>)) { DatabaseManager.InsertAnalyzed(result); } } catch (NullReferenceException) { Log.Debug(key); } } } 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"), "Flushing", answer); if (opts.SaveToDatabase) { DatabaseManager.UpdateCompareRun(opts.FirstRunId, opts.SecondRunId, RUN_STATUS.COMPLETED); } DatabaseManager.Commit(); AsaTelemetry.TrackEvent("End Command", EndEvent); return(results); }
public static int RunCollectCommand(CollectCommandOptions opts) { if (opts == null) { return(-1); } #if DEBUG Logger.Setup(true, opts.Verbose, opts.Quiet); #else Logger.Setup(opts.Debug, opts.Verbose, opts.Quiet); #endif var dbSettings = new DBSettings() { ShardingFactor = opts.Shards }; SetupOrDie(opts.DatabaseFilename, dbSettings); AsaTelemetry.Setup(); Dictionary <string, string> StartEvent = new Dictionary <string, string>(); StartEvent.Add("Files", opts.EnableAllCollectors ? "True" : opts.EnableFileSystemCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Ports", opts.EnableNetworkPortCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Users", opts.EnableUserCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Certificates", opts.EnableCertificateCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Registry", opts.EnableRegistryCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Service", opts.EnableServiceCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Firewall", opts.EnableFirewallCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("ComObject", opts.EnableComObjectCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("EventLog", opts.EnableEventLogCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Admin", AsaHelpers.IsAdmin().ToString(CultureInfo.InvariantCulture)); AsaTelemetry.TrackEvent("Run Command", StartEvent); AdminOrQuit(); CheckFirstRun(); int returnValue = (int)ASA_ERROR.NONE; opts.RunId = opts.RunId?.Trim() ?? DateTime.Now.ToString("o", CultureInfo.InvariantCulture); if (opts.MatchedCollectorId != null) { var matchedRun = DatabaseManager.GetRun(opts.MatchedCollectorId); if (matchedRun is AsaRun) { foreach (var resultType in matchedRun.ResultTypes) { switch (resultType) { case RESULT_TYPE.FILE: opts.EnableFileSystemCollector = true; break; case RESULT_TYPE.PORT: opts.EnableNetworkPortCollector = true; break; case RESULT_TYPE.CERTIFICATE: opts.EnableCertificateCollector = true; break; case RESULT_TYPE.COM: opts.EnableComObjectCollector = true; break; case RESULT_TYPE.FIREWALL: opts.EnableFirewallCollector = true; break; case RESULT_TYPE.LOG: opts.EnableEventLogCollector = true; break; case RESULT_TYPE.SERVICE: opts.EnableServiceCollector = true; break; case RESULT_TYPE.USER: opts.EnableUserCollector = true; break; } } } } var dict = new List <RESULT_TYPE>(); if (opts.EnableFileSystemCollector || opts.EnableAllCollectors) { collectors.Add(new FileSystemCollector(opts)); dict.Add(RESULT_TYPE.FILE); } if (opts.EnableNetworkPortCollector || opts.EnableAllCollectors) { collectors.Add(new OpenPortCollector(opts.RunId)); dict.Add(RESULT_TYPE.PORT); } if (opts.EnableServiceCollector || opts.EnableAllCollectors) { collectors.Add(new ServiceCollector(opts.RunId)); dict.Add(RESULT_TYPE.SERVICE); } if (opts.EnableUserCollector || opts.EnableAllCollectors) { collectors.Add(new UserAccountCollector(opts.RunId)); dict.Add(RESULT_TYPE.USER); } if (opts.EnableRegistryCollector || (opts.EnableAllCollectors && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))) { collectors.Add(new RegistryCollector(opts.RunId, opts.Parallelization)); dict.Add(RESULT_TYPE.REGISTRY); } if (opts.EnableCertificateCollector || opts.EnableAllCollectors) { collectors.Add(new CertificateCollector(opts.RunId)); dict.Add(RESULT_TYPE.CERTIFICATE); } if (opts.EnableFirewallCollector || opts.EnableAllCollectors) { collectors.Add(new FirewallCollector(opts.RunId)); dict.Add(RESULT_TYPE.FIREWALL); } if (opts.EnableComObjectCollector || (opts.EnableAllCollectors && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))) { collectors.Add(new ComObjectCollector(opts.RunId)); dict.Add(RESULT_TYPE.COM); } if (opts.EnableEventLogCollector || opts.EnableAllCollectors) { collectors.Add(new EventLogCollector(opts.RunId, opts.GatherVerboseLogs)); dict.Add(RESULT_TYPE.LOG); } if (collectors.Count == 0) { Log.Warning(Strings.Get("Err_NoCollectors")); return((int)ASA_ERROR.NO_COLLECTORS); } if (opts.Overwrite) { DatabaseManager.DeleteRun(opts.RunId); } else { if (DatabaseManager.GetRun(opts.RunId) != null) { Log.Error(Strings.Get("Err_RunIdAlreadyUsed")); return((int)ASA_ERROR.UNIQUE_ID); } } Log.Information(Strings.Get("Begin"), opts.RunId); var run = new AsaRun(RunId: opts.RunId, Timestamp: DateTime.Now, Version: AsaHelpers.GetVersionString(), Platform: AsaHelpers.GetPlatform(), ResultTypes: dict, Type: RUN_TYPE.COLLECT); DatabaseManager.InsertRun(run); Log.Information(Strings.Get("StartingN"), collectors.Count.ToString(CultureInfo.InvariantCulture), Strings.Get("Collectors")); Console.CancelKeyPress += delegate { Log.Information("Cancelling collection. Rolling back transaction. Please wait to avoid corrupting database."); DatabaseManager.RollBack(); Environment.Exit(-1); }; Dictionary <string, string> EndEvent = new Dictionary <string, string>(); foreach (BaseCollector c in collectors) { try { c.Execute(); EndEvent.Add(c.GetType().ToString(), c.NumCollected().ToString(CultureInfo.InvariantCulture)); } catch (Exception e) { Log.Error(Strings.Get("Err_CollectingFrom"), c.GetType().Name, e.Message, e.StackTrace); Dictionary <string, string> ExceptionEvent = new Dictionary <string, string>(); ExceptionEvent.Add("Exception Type", e.GetType().ToString()); ExceptionEvent.Add("Stack Trace", e.StackTrace ?? string.Empty); ExceptionEvent.Add("Message", e.Message); AsaTelemetry.TrackEvent("CollectorCrashRogueException", ExceptionEvent); returnValue = 1; } } AsaTelemetry.TrackEvent("End Command", EndEvent); DatabaseManager.Commit(); DatabaseManager.CloseDatabase(); return(returnValue); }
public void Compare(string firstRunId, string secondRunId) { if (firstRunId == null) { throw new ArgumentNullException(nameof(firstRunId)); } if (secondRunId == null) { throw new ArgumentNullException(nameof(secondRunId)); } ConcurrentBag <WriteObject> differentObjects = DatabaseManager.GetAllMissing(firstRunId, secondRunId); ConcurrentBag <(WriteObject, WriteObject)> modifyObjects = DatabaseManager.GetModified(firstRunId, secondRunId); differentObjects.AsParallel().ForAll(different => { if (different.RunId.Equals(firstRunId)) { var obj = new CompareResult() { Base = different.ColObj, BaseRunId = firstRunId, CompareRunId = secondRunId, BaseRowKey = different.RowKey, }; Results[$"{different.ColObj?.ResultType}_{CHANGE_TYPE.DELETED}"].Enqueue(obj); } else if (different.RunId.Equals(secondRunId)) { var obj = new CompareResult() { Compare = different.ColObj, BaseRunId = firstRunId, CompareRunId = secondRunId, CompareRowKey = different.RowKey, }; Results[$"{different.ColObj?.ResultType}_{CHANGE_TYPE.CREATED}"].Enqueue(obj); } }); modifyObjects.AsParallel().ForAll(modified => { var compareLogic = new CompareLogic(); compareLogic.Config.IgnoreCollectionOrder = true; var first = modified.Item1.ColObj; var second = modified.Item2.ColObj; var obj = new CompareResult() { Base = first, Compare = second, BaseRunId = firstRunId, CompareRunId = secondRunId, BaseRowKey = modified.Item1.RowKey, CompareRowKey = modified.Item2.RowKey, }; var properties = first?.GetType().GetProperties(); if (properties is PropertyInfo[]) { foreach (var prop in properties) { try { List <Diff> diffs; object?added = null; object?removed = null; object?firstProp = prop.GetValue(first); object?secondProp = prop.GetValue(second); if (firstProp == null && secondProp == null) { continue; } else if (firstProp == null && secondProp != null) { added = prop.GetValue(second); diffs = GetDiffs(prop, added, null); } else if (secondProp == null && firstProp != null) { removed = prop.GetValue(first); diffs = GetDiffs(prop, null, removed); } else if (firstProp != null && secondProp != null && compareLogic.Compare(firstProp, secondProp).AreEqual) { continue; } else { var firstVal = prop.GetValue(first); var secondVal = prop.GetValue(second); if (firstVal is List <string> && secondVal is List <string> ) { added = ((List <string>)secondVal).Except((List <string>)firstVal); removed = ((List <string>)firstVal).Except((List <string>?)prop.GetValue(second)); if (!((IEnumerable <string>)added).Any()) { added = null; } if (!((IEnumerable <string>)removed).Any()) { removed = null; } } else if (firstVal is List <KeyValuePair <string, string> > && secondVal is List <KeyValuePair <string, string> > ) { added = ((List <KeyValuePair <string, string> >)secondVal).Except((List <KeyValuePair <string, string> >)firstVal); removed = ((List <KeyValuePair <string, string> >)firstVal).Except((List <KeyValuePair <string, string> >)secondVal); if (!((IEnumerable <KeyValuePair <string, string> >)added).Any()) { added = null; } if (!((IEnumerable <KeyValuePair <string, string> >)removed).Any()) { removed = null; } } else if (firstVal is Dictionary <string, string> && secondVal is Dictionary <string, string> ) { added = ((Dictionary <string, string>)secondVal) .Except((Dictionary <string, string>)firstVal) .ToDictionary(x => x.Key, x => x.Value); removed = ((Dictionary <string, string>)firstVal) .Except((Dictionary <string, string>)secondVal) .ToDictionary(x => x.Key, x => x.Value); if (!((IEnumerable <KeyValuePair <string, string> >)added).Any()) { added = null; } if (!((IEnumerable <KeyValuePair <string, string> >)removed).Any()) { removed = null; } } else if ((firstVal is string || firstVal is int || firstVal is bool) && (secondVal is string || secondVal is int || secondVal is bool)) { obj.Diffs.Add(new Diff(prop.Name, firstVal, secondVal)); } else { obj.Diffs.Add(new Diff(prop.Name, firstVal, secondVal)); } diffs = GetDiffs(prop, added, removed); } foreach (var diff in diffs) { obj.Diffs.Add(diff); } } catch (InvalidCastException e) { Log.Debug(e, $"Failed to cast {JsonConvert.SerializeObject(prop)}"); } catch (Exception e) { Log.Debug(e, "Generic exception. Tell a programmer."); Dictionary <string, string> ExceptionEvent = new Dictionary <string, string>(); ExceptionEvent.Add("Exception Type", e.GetType().ToString()); AsaTelemetry.TrackEvent("CompareException", ExceptionEvent); } } } Results[$"{modified.Item1.ColObj?.ResultType.ToString()}_{CHANGE_TYPE.MODIFIED}"].Enqueue(obj); }); foreach (var empty in Results.Where(x => x.Value.Count == 0)) { Results.Remove(empty.Key, out _); } }
public static ConcurrentDictionary <(RESULT_TYPE, CHANGE_TYPE), List <CompareResult> > CompareRuns(CompareCommandOptions opts) { if (opts is null) { throw new ArgumentNullException(nameof(opts)); } if (opts.SaveToDatabase) { DatabaseManager.InsertCompareRun(opts.FirstRunId, opts.SecondRunId, RUN_STATUS.RUNNING); } comparators = new List <BaseCompare>(); Dictionary <string, string> EndEvent = new Dictionary <string, string>(); BaseCompare c = new BaseCompare(); var watch = System.Diagnostics.Stopwatch.StartNew(); if (!c.TryCompare(opts.FirstRunId, opts.SecondRunId)) { Log.Warning(Strings.Get("Err_Comparing") + " : {0}", c.GetType().Name); } watch.Stop(); TimeSpan t = TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds); string 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"), "Comparing", answer); if (opts.Analyze) { watch = Stopwatch.StartNew(); Analyzer analyzer = new Analyzer(DatabaseManager.RunIdToPlatform(opts.SecondRunId), opts.AnalysesFile); var violations = analyzer.VerifyRules(); Analyzer.PrintViolations(violations); if (violations.Any()) { Log.Error("Encountered {0} issues with rules in {1}. Skipping analysis.", violations.Count, opts.AnalysesFile ?? "Embedded"); } else { if (c.Results.Count > 0) { foreach (var key in c.Results.Keys) { if (c.Results[key] is List <CompareResult> queue) { queue.AsParallel().ForAll(res => { res.Rules = analyzer.Analyze(res); res.Analysis = res.Rules.Count > 0 ? res.Rules.Max(x => x.Flag) : analyzer.DefaultLevels[res.ResultType]; }); } } } } 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 = Stopwatch.StartNew(); if (opts.SaveToDatabase) { foreach (var key in c.Results.Keys) { if (c.Results.TryGetValue(key, out List <CompareResult>?obj)) { if (obj is List <CompareResult> Queue) { foreach (var result in Queue) { DatabaseManager.InsertAnalyzed(result); } } } } } 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"), "Flushing", answer); if (opts.SaveToDatabase) { DatabaseManager.UpdateCompareRun(opts.FirstRunId, opts.SecondRunId, RUN_STATUS.COMPLETED); } DatabaseManager.Commit(); AsaTelemetry.TrackEvent("End Command", EndEvent); return(c.Results); }
private static int RunMonitorCommand(MonitorCommandOptions opts) { #if DEBUG Logger.Setup(true, opts.Verbose); #else Logger.Setup(opts.Debug, opts.Verbose); #endif AdminOrQuit(); AsaTelemetry.Setup(); Dictionary <string, string> StartEvent = new Dictionary <string, string>(); StartEvent.Add("Files", opts.EnableFileSystemMonitor.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Admin", AsaHelpers.IsAdmin().ToString(CultureInfo.InvariantCulture)); AsaTelemetry.TrackEvent("Begin monitoring", StartEvent); CheckFirstRun(); if (opts.RunId is string) { opts.RunId = opts.RunId.Trim(); } else { opts.RunId = DateTime.Now.ToString("o", CultureInfo.InvariantCulture); } if (opts.Overwrite) { DatabaseManager.DeleteRun(opts.RunId); } else { if (DatabaseManager.GetRun(opts.RunId) != null) { Log.Error(Strings.Get("Err_RunIdAlreadyUsed")); return((int)ASA_ERROR.UNIQUE_ID); } } var run = new AsaRun(RunId: opts.RunId, Timestamp: DateTime.Now, Version: AsaHelpers.GetVersionString(), Platform: AsaHelpers.GetPlatform(), new List <RESULT_TYPE>() { RESULT_TYPE.FILEMONITOR }, RUN_TYPE.MONITOR); DatabaseManager.InsertRun(run); int returnValue = 0; if (opts.EnableFileSystemMonitor) { monitors.Add(new FileSystemMonitor(opts, x => DatabaseManager.WriteFileMonitor(x, opts.RunId))); } //if (opts.EnableRegistryMonitor) //{ //var monitor = new RegistryMonitor(); //monitors.Add(monitor); //} if (monitors.Count == 0) { Log.Warning(Strings.Get("Err_NoMonitors")); returnValue = (int)ASA_ERROR.NO_COLLECTORS; } using var exitEvent = new ManualResetEvent(false); // If duration is set, we use the secondary timer. if (opts.Duration > 0) { Log.Information("{0} {1} {2}.", Strings.Get("MonitorStartedFor"), opts.Duration, Strings.Get("Minutes")); using var aTimer = new System.Timers.Timer { Interval = opts.Duration * 60 * 1000, //lgtm [cs/loss-of-precision] AutoReset = false, }; aTimer.Elapsed += (source, e) => { exitEvent.Set(); }; // Start the timer aTimer.Enabled = true; } foreach (FileSystemMonitor c in monitors) { Log.Information(Strings.Get("Begin"), c.GetType().Name); try { c.StartRun(); } catch (Exception ex) { Log.Error(Strings.Get("Err_CollectingFrom"), c.GetType().Name, ex.Message, ex.StackTrace); returnValue = 1; } } // Set up the event to capture CTRL+C Console.CancelKeyPress += (sender, eventArgs) => { eventArgs.Cancel = true; exitEvent.Set(); }; Console.Write(Strings.Get("MonitoringPressC")); // Write a spinner and wait until CTRL+C WriteSpinner(exitEvent); Log.Information(""); foreach (var c in monitors) { Log.Information(Strings.Get("End"), c.GetType().Name); try { c.StopRun(); if (c is FileSystemMonitor) { ((FileSystemMonitor)c).Dispose(); } } catch (Exception ex) { Log.Error(ex, " {0}: {1}", c.GetType().Name, ex.Message, Strings.Get("Err_Stopping")); } } FlushResults(); DatabaseManager.Commit(); return(returnValue); }
public static int RunCollectCommand(CollectCommandOptions opts) { if (opts == null) { return(-1); } #if DEBUG Logger.Setup(true, opts.Verbose, opts.Quiet); #else Logger.Setup(opts.Debug, opts.Verbose, opts.Quiet); #endif var dbSettings = new DBSettings() { ShardingFactor = opts.Shards }; SetupOrDie(opts.DatabaseFilename, dbSettings); AsaTelemetry.Setup(); Dictionary <string, string> StartEvent = new Dictionary <string, string>(); StartEvent.Add("Files", opts.EnableAllCollectors ? "True" : opts.EnableFileSystemCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Ports", opts.EnableNetworkPortCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Users", opts.EnableUserCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Certificates", opts.EnableCertificateCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Registry", opts.EnableRegistryCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Service", opts.EnableServiceCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Firewall", opts.EnableFirewallCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("ComObject", opts.EnableComObjectCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("EventLog", opts.EnableEventLogCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Tpm", opts.EnableEventLogCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Keys", opts.EnableKeyCollector.ToString(CultureInfo.InvariantCulture)); StartEvent.Add("Admin", AsaHelpers.IsAdmin().ToString(CultureInfo.InvariantCulture)); AsaTelemetry.TrackEvent("Run Command", StartEvent); AdminOrQuit(); CheckFirstRun(); int returnValue = (int)ASA_ERROR.NONE; opts.RunId = opts.RunId?.Trim() ?? DateTime.Now.ToString("o", CultureInfo.InvariantCulture); if (opts.MatchedCollectorId != null) { var matchedRun = DatabaseManager.GetRun(opts.MatchedCollectorId); if (matchedRun is AsaRun) { foreach (var resultType in matchedRun.ResultTypes) { switch (resultType) { case RESULT_TYPE.FILE: opts.EnableFileSystemCollector = true; break; case RESULT_TYPE.PORT: opts.EnableNetworkPortCollector = true; break; case RESULT_TYPE.CERTIFICATE: opts.EnableCertificateCollector = true; break; case RESULT_TYPE.COM: opts.EnableComObjectCollector = true; break; case RESULT_TYPE.FIREWALL: opts.EnableFirewallCollector = true; break; case RESULT_TYPE.LOG: opts.EnableEventLogCollector = true; break; case RESULT_TYPE.SERVICE: opts.EnableServiceCollector = true; break; case RESULT_TYPE.USER: opts.EnableUserCollector = true; break; case RESULT_TYPE.KEY: opts.EnableKeyCollector = true; break; case RESULT_TYPE.TPM: opts.EnableTpmCollector = true; break; } } } } var dict = new List <RESULT_TYPE>(); if (opts.EnableFileSystemCollector || opts.EnableAllCollectors) { collectors.Add(new FileSystemCollector(opts)); dict.Add(RESULT_TYPE.FILE); } if (opts.EnableNetworkPortCollector || opts.EnableAllCollectors) { collectors.Add(new OpenPortCollector()); dict.Add(RESULT_TYPE.PORT); } if (opts.EnableServiceCollector || opts.EnableAllCollectors) { collectors.Add(new ServiceCollector()); dict.Add(RESULT_TYPE.SERVICE); } if (opts.EnableUserCollector || opts.EnableAllCollectors) { collectors.Add(new UserAccountCollector()); dict.Add(RESULT_TYPE.USER); } if (opts.EnableRegistryCollector || (opts.EnableAllCollectors && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))) { collectors.Add(new RegistryCollector(opts.Parallelization)); dict.Add(RESULT_TYPE.REGISTRY); } if (opts.EnableCertificateCollector || opts.EnableAllCollectors) { collectors.Add(new CertificateCollector()); dict.Add(RESULT_TYPE.CERTIFICATE); } if (opts.EnableFirewallCollector || opts.EnableAllCollectors) { collectors.Add(new FirewallCollector()); dict.Add(RESULT_TYPE.FIREWALL); } if (opts.EnableComObjectCollector || (opts.EnableAllCollectors && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))) { collectors.Add(new ComObjectCollector()); dict.Add(RESULT_TYPE.COM); } if (opts.EnableEventLogCollector || opts.EnableAllCollectors) { collectors.Add(new EventLogCollector(opts.GatherVerboseLogs)); dict.Add(RESULT_TYPE.LOG); } if (opts.EnableTpmCollector || opts.EnableAllCollectors) { collectors.Add(new TpmCollector()); dict.Add(RESULT_TYPE.TPM); } if (opts.EnableKeyCollector || opts.EnableAllCollectors) { collectors.Add(new CryptographicKeyCollector()); dict.Add(RESULT_TYPE.KEY); } if (collectors.Count == 0) { Log.Warning(Strings.Get("Err_NoCollectors")); return((int)ASA_ERROR.NO_COLLECTORS); } if (opts.Overwrite) { DatabaseManager.DeleteRun(opts.RunId); } else { if (DatabaseManager.GetRun(opts.RunId) != null) { Log.Error(Strings.Get("Err_RunIdAlreadyUsed")); return((int)ASA_ERROR.UNIQUE_ID); } } Log.Information(Strings.Get("Begin"), opts.RunId); var run = new AsaRun(RunId: opts.RunId, Timestamp: DateTime.Now, Version: AsaHelpers.GetVersionString(), Platform: AsaHelpers.GetPlatform(), ResultTypes: dict, Type: RUN_TYPE.COLLECT); DatabaseManager.InsertRun(run); Log.Information(Strings.Get("StartingN"), collectors.Count.ToString(CultureInfo.InvariantCulture), Strings.Get("Collectors")); Console.CancelKeyPress += delegate { Log.Information("Cancelling collection. Rolling back transaction. Please wait to avoid corrupting database."); DatabaseManager.RollBack(); Environment.Exit(-1); }; Dictionary <string, string> EndEvent = new Dictionary <string, string>(); foreach (BaseCollector c in collectors) { try { DatabaseManager.BeginTransaction(); var StopWatch = Stopwatch.StartNew(); Task.Run(() => c.Execute()); Thread.Sleep(1); while (c.RunStatus == RUN_STATUS.RUNNING) { if (c.Results.TryDequeue(out CollectObject? res)) { DatabaseManager.Write(res, opts.RunId); } else { Thread.Sleep(1); } } StopWatch.Stop(); TimeSpan t = TimeSpan.FromMilliseconds(StopWatch.ElapsedMilliseconds); string 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.Debug(Strings.Get("Completed"), c.GetType().Name, answer); c.Results.AsParallel().ForAll(x => DatabaseManager.Write(x, opts.RunId)); var prevFlush = DatabaseManager.Connections.Select(x => x.WriteQueue.Count).Sum(); var totFlush = prevFlush; var printInterval = 10; var currentInterval = 0; StopWatch = Stopwatch.StartNew(); while (DatabaseManager.HasElements) { Thread.Sleep(1000); if (currentInterval++ % printInterval == 0) { var actualDuration = (currentInterval < printInterval) ? currentInterval : printInterval; var sample = DatabaseManager.Connections.Select(x => x.WriteQueue.Count).Sum(); var curRate = prevFlush - sample; var totRate = (double)(totFlush - sample) / StopWatch.ElapsedMilliseconds; try { t = (curRate > 0) ? TimeSpan.FromMilliseconds(sample / ((double)curRate / (actualDuration * 1000))) : TimeSpan.FromMilliseconds(99999999); //lgtm[cs/loss-of-precision] 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.Debug("Flushing {0} results. ({1}/{4}s {2:0.00}/s overall {3} ETA)", sample, curRate, totRate * 1000, answer, actualDuration); } catch (Exception e) when( e is OverflowException) { Log.Debug($"Overflowed: {curRate} {totRate} {sample} {t} {answer}"); Log.Debug("Flushing {0} results. ({1}/s {2:0.00}/s)", sample, curRate, totRate * 1000); } prevFlush = sample; } } StopWatch.Stop(); t = TimeSpan.FromMilliseconds(StopWatch.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.Debug("Completed flushing in {0}", answer); DatabaseManager.Commit(); } catch (Exception e) { Log.Error(Strings.Get("Err_CollectingFrom"), c.GetType().Name, e.Message, e.StackTrace); Dictionary <string, string> ExceptionEvent = new Dictionary <string, string>(); ExceptionEvent.Add("Exception Type", e.GetType().ToString()); ExceptionEvent.Add("Stack Trace", e.StackTrace ?? string.Empty); ExceptionEvent.Add("Message", e.Message); AsaTelemetry.TrackEvent("CollectorCrashRogueException", ExceptionEvent); returnValue = 1; } } AsaTelemetry.TrackEvent("End Command", EndEvent); DatabaseManager.Commit(); DatabaseManager.CloseDatabase(); return(returnValue); }