public static void Main(string[] args) { if (args == null) { throw new ArgumentNullException(nameof(args)); } var options = new Options(); if (!Parser.Default.ParseArguments(args, options)) { return; } try { // ReSharper disable once ReturnValueOfPureMethodIsNotUsed Path.Combine(options.CSVFolder, options.CacheFile); } catch (ArgumentException) { Console.WriteLine("Invalid characters in output path. Check for trailing backslashes!"); return; } var collectionMethods = new List <CollectionMethod>(); if (options.CollectionMethod.Length == 1) { options.CollectionMethod = options.CollectionMethod[0].Split(','); } if (options.Jitter > 100 || options.Jitter < 0) { Console.WriteLine("Jitter must be a value between 0 and 100!"); return; } if (options.Throttle < 0) { Console.WriteLine("Throttle must be 0 or greater!"); return; } foreach (var unparsed in options.CollectionMethod) { try { var e = (CollectionMethod)Enum.Parse(typeof(CollectionMethod), unparsed, true); collectionMethods.Add(e); } catch { Console.WriteLine($"Failed to parse value {unparsed}. Check your values for CollectionMethods!"); return; } } if (options.Debug) { Console.WriteLine("Debug Mode activated!"); options.Threads = 1; } if (options.MaxLoopTime != null && collectionMethods.Contains(SessionLoop)) { var regex = new Regex("[0-9]+[smdh]"); var matches = regex.Matches(options.MaxLoopTime); var numregex = new Regex("[0-9]+"); var timeregex = new Regex("[smdh]"); if (matches.Count == 0) { Console.WriteLine("LoopEndTime does not match required format"); return; } var now = DateTime.Now; var drift = 0; foreach (var match in matches) { var num = int.Parse(numregex.Match(match.ToString()).Value); var spec = timeregex.Match(match.ToString()); switch (spec.Value) { case "s": now = now.AddSeconds(num); drift += num; break; case "m": now = now.AddMinutes(num); drift += num * 60; break; case "h": now = now.AddHours(num); drift += num * 60 * 60; break; case "d": now = now.AddDays(num); drift += num * 60 * 60 * 24; break; } } options.LoopEnd = now; if (drift == 0) { Console.WriteLine("LoopEndTime is zero! Specify a real value"); return; } } options.CurrentUser = WindowsIdentity.GetCurrent().Name.Split('\\')[1]; var nowtime = DateTime.Now; Console.WriteLine($"Initializing BloodHound at {nowtime.ToShortTimeString()} on {nowtime.ToShortDateString()}"); if (options.ComputerFile != null) { if (options.PingTimeout < 1000) { Console.WriteLine("Increasing ping timeout to 1 second for ComputerFile mode"); options.PingTimeout = 1000; } } Cache.CreateInstance(options); Utils.CreateInstance(options); if (!Utils.CheckWritePrivs()) { Console.WriteLine("Unable to write in chosen directory. Please check privs"); return; } if (Utils.Instance.GetDomainList().Count == 0) { Console.WriteLine("Unable to contact domain. Try from a domain context!"); return; } SessionHelpers.Init(options); LocalAdminHelpers.Init(); GroupHelpers.Init(); AclHelpers.Init(); DomainTrustEnumeration.Init(); ContainerHelpers.Init(); if (options.Test != null) { Test.DoStuff(options.Test); return; } //Lets test our connection to LDAP before we do anything else try { using (var conn = Utils.Instance.GetLdapConnection(options.Domain)) { if (conn == null) { Console.WriteLine("LDAP connection test failed, probably can't contact domain"); return; } conn.Bind(); } } catch (LdapException) { Console.WriteLine("Ldap Connection Failure."); Console.WriteLine("Try again with the IgnoreLdapCert option if using SecureLDAP or check your DomainController/LdapPort option"); return; } if (options.Uri != null) { if (!options.Uri.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("URI must start with http:// or https://"); return; } using (var client = new WebClient()) { client.Headers.Add("content-type", "application/json"); client.Headers.Add("Accept", "application/json; charset=UTF-8"); if (options.UserPass != null) { client.Headers.Add("Authorization", options.GetEncodedUserPass()); } try { client.DownloadData(options.GetCheckURI()); Console.WriteLine("Successfully connected to the Neo4j REST endpoint."); } catch { Console.WriteLine("Unable to connect to the Neo4j REST endpoint. Check your URI and username/password"); return; } } } if (options.RemoveCSV && !options.CompressData) { Console.WriteLine("Ignoring RemoveCSV as CompressData is not set"); options.RemoveCSV = false; } if (options.Stealth) { Console.WriteLine("Note: All stealth options are single threaded"); } if (options.Throttle > 0) { Console.WriteLine( $"Adding a delay of {options.Throttle} milliseconds to computer requests with a jitter of {options.Jitter}%"); } foreach (var cmethod in collectionMethods) { options.CurrentCollectionMethod = cmethod; if (options.ComputerFile != null) { if (!File.Exists(options.ComputerFile)) { Console.WriteLine("Specified ComputerFile does not exist!"); return; } if (options.CurrentCollectionMethod.Equals(Default)) { options.CurrentCollectionMethod = ComputerOnly; Console.WriteLine("ComputerFile detected with default enumeration. Switching to ComputerOnly collection method"); } if (!(options.CurrentCollectionMethod.Equals(Session) || options.CurrentCollectionMethod.Equals(SessionLoop) || options.CurrentCollectionMethod.Equals(LoggedOn) || options.CurrentCollectionMethod.Equals(LocalGroup) || options.CurrentCollectionMethod.Equals(ComputerOnly))) { Console.WriteLine("ComputerFile can only be used with the following collection methods: ComputerOnly, Session, SessionLoop, LocalGroup, LoggedOn"); continue; } } if (options.CurrentCollectionMethod.Equals(LocalGroup) && options.Stealth) { Console.WriteLine("Note: You specified Stealth and LocalGroup which is equivalent to GPOLocalGroup"); options.CurrentCollectionMethod = GPOLocalGroup; } var runner = new EnumerationRunner(options); if (options.CurrentCollectionMethod.Equals(SessionLoop)) { Console.WriteLine(options.MaxLoopTime == null ? "Session Loop mode specified without MaxLoopTime, will loop indefinitely" : $"Session Loop mode specified. Looping will end on {options.LoopEnd.ToShortDateString()} at {options.LoopEnd.ToShortTimeString()}"); } if (options.Stealth) { runner.StartStealthEnumeration(); } else { runner.StartEnumeration(); } Console.WriteLine(); } Cache.Instance.SaveCache(); Utils.DeduplicateFiles(); if (options.CompressData) { Utils.CompressFiles(); } }