diff --git a/README.md b/README.md index e83b48a..36bd1f9 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,12 @@ dotnet build --statusinterval (Default: 30000) Interval in which to display status in milliseconds + --localadminsessionenum Specify if you want to use a dedicated LOCAL user for session enumeration + + --localadminusername Specify the username of the localadmin for session enumeration + + --localadminpassword Specify the password of the localadmin for session enumeration + -v (Default: 2) Enable verbose output. Lower is more verbose --help Display this help screen. diff --git a/src/BaseContext.cs b/src/BaseContext.cs index 1bea89f..b0c58dc 100644 --- a/src/BaseContext.cs +++ b/src/BaseContext.cs @@ -115,6 +115,9 @@ public string ResolveFileName(string filename, string extension, bool addTimesta } public string[] Domains { get; set; } + public string LocalAdminUsername { get; set; } + public string LocalAdminPassword { get; set; } + public bool LocalAdminSessionEnum { get; set; } // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources // ~Context() diff --git a/src/Client/Context.cs b/src/Client/Context.cs index e4223b2..8150255 100644 --- a/src/Client/Context.cs +++ b/src/Client/Context.cs @@ -58,6 +58,10 @@ public interface IContext int Jitter { get; set; } int PortScanTimeout { get; set; } + public string LocalAdminUsername { get; set; } + + public string LocalAdminPassword { get; set; } + ResolvedCollectionMethod ResolvedCollectionMethods { get; set; } /// diff --git a/src/Client/Flags.cs b/src/Client/Flags.cs index 630f304..83c20c9 100644 --- a/src/Client/Flags.cs +++ b/src/Client/Flags.cs @@ -1,4 +1,6 @@ -namespace Sharphound.Client +using SharpHoundCommonLib.OutputTypes; + +namespace Sharphound.Client { public class Flags { @@ -23,5 +25,6 @@ public class Flags public bool DCOnly { get; set; } public bool PrettyPrint { get; set; } public bool SearchForest { get; set; } + public bool DoLocalAdminSessionEnum { get; set; } } } \ No newline at end of file diff --git a/src/Options.cs b/src/Options.cs index cb00185..6521e9e 100644 --- a/src/Options.cs +++ b/src/Options.cs @@ -76,8 +76,16 @@ public class Options [Option(HelpText = "Password for LDAP", Default = null)] public string LDAPPassword { get; set; } - [Option(HelpText = "Override domain controller to pull LDAP from. This option can result in data loss", - Default = null)] + [Option(HelpText = "Do the session enumeration with local admin credentials instead of domain credentials", Default = false)] + public bool DoLocalAdminSessionEnum { get; set; } + + [Option(HelpText = "Username for local Administrator to be used if DoLocalAdminSessionEnum is set", Default = null)] + public string LocalAdminUsername { get; set; } + + [Option(HelpText = "Password for local Administrator to be used if DoLocalAdminSessionEnum is set", Default = null)] + public string LocalAdminPassword { get; set; } + + [Option(HelpText = "Override domain controller to pull LDAP from. This option can result in data loss", Default = null)] public string DomainController { get; set; } [Option(HelpText = "Override port for LDAP", Default = 0)] diff --git a/src/Runtime/ObjectProcessors.cs b/src/Runtime/ObjectProcessors.cs index 5b0355b..cd8e249 100644 --- a/src/Runtime/ObjectProcessors.cs +++ b/src/Runtime/ObjectProcessors.cs @@ -38,7 +38,7 @@ public ObjectProcessors(IContext context, ILogger log) _ldapPropertyProcessor = new LDAPPropertyProcessor(context.LDAPUtils); _domainTrustProcessor = new DomainTrustProcessor(context.LDAPUtils); _computerAvailability = new ComputerAvailability(context.PortScanTimeout, skipPortScan: context.Flags.SkipPortScan, skipPasswordCheck: context.Flags.SkipPasswordAgeCheck); - _computerSessionProcessor = new ComputerSessionProcessor(context.LDAPUtils); + _computerSessionProcessor = new ComputerSessionProcessor(context.LDAPUtils, doLocalAdminSessionEnum: context.Flags.DoLocalAdminSessionEnum, localAdminUsername: context.LocalAdminUsername, localAdminPassword: context.LocalAdminPassword); _groupProcessor = new GroupProcessor(context.LDAPUtils); _containerProcessor = new ContainerProcessor(context.LDAPUtils); _gpoLocalGroupProcessor = new GPOLocalGroupProcessor(context.LDAPUtils); diff --git a/src/Sharphound.cs b/src/Sharphound.cs index 8034d89..eb687c1 100644 --- a/src/Sharphound.cs +++ b/src/Sharphound.cs @@ -103,7 +103,7 @@ public IContext Initialize(IContext context, LDAPConfig options) context.Flags.IsFaulted = true; return context; } - + //Check some loop options if (!context.Flags.Loop) return context; //If loop is set, ensure we actually set options properly @@ -371,7 +371,8 @@ await options.WithParsedAsync(async options => CollectAllProperties = options.CollectAllProperties, DCOnly = dconly, PrettyPrint = options.PrettyPrint, - SearchForest = options.SearchForest + SearchForest = options.SearchForest, + DoLocalAdminSessionEnum = options.DoLocalAdminSessionEnum, }; var ldapOptions = new LDAPConfig @@ -396,7 +397,38 @@ await options.WithParsedAsync(async options => ldapOptions.Username = options.LDAPUsername; ldapOptions.Password = options.LDAPPassword; } + + // Check to make sure both Local Admin Session Enum options are set if either is set + + if (options.LocalAdminPassword != null && options.LocalAdminUsername == null || + options.LocalAdminUsername != null && options.LocalAdminPassword == null) + { + logger.LogError("You must specify both LocalAdminUsername and LocalAdminPassword if using these options!"); + return; + } + + // Check to make sure doLocalAdminSessionEnum is set when specifying localadmin and password + + if (options.LocalAdminPassword != null || options.LocalAdminUsername != null) + { + if (options.DoLocalAdminSessionEnum == false) + { + logger.LogError("You must use the --doLocalAdminSessionEnum switch in combination with --LocalAdminUsername and --LocalAdminPassword!"); + return; + } + } + // Check to make sure LocalAdminUsername and LocalAdminPassword are set when using doLocalAdminSessionEnum + + if (options.DoLocalAdminSessionEnum == true) + { + if (options.LocalAdminPassword == null || options.LocalAdminUsername == null) + { + logger.LogError("You must specify both LocalAdminUsername and LocalAdminPassword if using the --doLocalAdminSessionEnum option!"); + return; + } + } + IContext context = new BaseContext(logger, ldapOptions, flags) { DomainName = options.Domain, @@ -417,7 +449,10 @@ await options.WithParsedAsync(async options => LoopDuration = options.LoopDuration, LoopInterval = options.LoopInterval, ZipPassword = options.ZipPassword, - IsFaulted = false + IsFaulted = false, + LocalAdminUsername = options.LocalAdminUsername, + LocalAdminPassword = options.LocalAdminPassword + }; var cancellationTokenSource = new CancellationTokenSource();