diff --git a/src/Client/Flags.cs b/src/Client/Flags.cs index 48e935a..0f04ccc 100644 --- a/src/Client/Flags.cs +++ b/src/Client/Flags.cs @@ -28,5 +28,6 @@ public class Flags public bool RecurseDomains { get; set; } public bool DoLocalAdminSessionEnum { get; set; } public bool ParititonLdapQueries { get; set; } + public bool Metrics { get; set; } } } \ No newline at end of file diff --git a/src/Options.cs b/src/Options.cs index e560b02..bdc84e2 100644 --- a/src/Options.cs +++ b/src/Options.cs @@ -142,6 +142,9 @@ public class Options [Option(HelpText = "Split the main ldap query into smaller chunks to attempt to reduce server load")] public bool PartitionLdapQueries { get; set; } + + [Option(HelpText = "Output metrics that were captured from SharpHound")] + public bool Metrics { get; set; } //Loop Options [Option('l', "Loop", HelpText = "Loop computer collection")] diff --git a/src/Sharphound.cs b/src/Sharphound.cs index 87e009b..1229650 100644 --- a/src/Sharphound.cs +++ b/src/Sharphound.cs @@ -25,6 +25,9 @@ using Sharphound.Client; using SharpHoundCommonLib; using SharpHoundCommonLib.Enums; +using SharpHoundCommonLib.Models; +using SharpHoundCommonLib.Services; +using SharpHoundCommonLib.Static; namespace Sharphound { @@ -36,6 +39,8 @@ namespace Sharphound #region Console Entrypoint public class Program { + private static MetricsFlushTimer _flushTimer; + public static async Task Main(string[] args) { var logger = new BasicLogger((int)LogLevel.Information); logger.LogInformation("This version of SharpHound is compatible with the 5.0.0 Release of BloodHound"); @@ -88,7 +93,8 @@ await options.WithParsedAsync(async options => SearchForest = options.SearchForest, RecurseDomains = options.RecurseDomains, DoLocalAdminSessionEnum = options.DoLocalAdminSessionEnum, - ParititonLdapQueries = options.PartitionLdapQueries + ParititonLdapQueries = options.PartitionLdapQueries, + Metrics = options.Metrics, }; var ldapOptions = new LdapConfig @@ -149,10 +155,44 @@ await options.WithParsedAsync(async options => } } + if (flags.Metrics) { + var metricsRegistry = new MetricRegistry(); + metricsRegistry.RegisterDefaultMetrics(); + metricsRegistry.Seal(); + + var fileSinkOptions = new FileMetricSinkOptions { + FlushInterval = TimeSpan.FromSeconds(5), + }; + + var metricsWriter = new MetricWriter(); + + var metricsFileName = string.IsNullOrEmpty(options.OutputPrefix) ? "metrics.log" : $"{options.OutputPrefix}_metrics.log"; + var metricsFilePath = System.IO.Path.Combine(options.OutputDirectory, metricsFileName); + + var fileSink = new FileMetricSink( + metricsRegistry.Definitions, + filePath: metricsFilePath, + metricsWriter, + fileSinkOptions); + + var metricsRouter = new MetricRouter( + metricsRegistry.Definitions, + [fileSink], + new DefaultLabelValuesCache()); + + Metrics.Factory = new MetricFactory(metricsRouter); + + _flushTimer = new MetricsFlushTimer( + flush: metricsRouter.Flush, + interval: fileSinkOptions.FlushInterval); + + } + await StartCollection(options, logger, resolved, flags, ldapOptions); }); } catch (Exception ex) { logger.LogError($"Error running SharpHound: {ex.Message}\n{ex.StackTrace}"); + _flushTimer?.Dispose(); } } @@ -214,6 +254,7 @@ private static async Task StartCollection(Options options, BasicLogger logger, C context = await links.AwaitLoopCompletion(context); context = links.SaveCacheFile(context); links.Finish(context); + _flushTimer?.Dispose(); } // Accessor function for the PS1 to work, do not change or remove