Exemplo n.º 1
0
        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;
            }

            if (options.Debug)
            {
                Console.WriteLine("Debug Mode activated!");
                options.Threads = 1;
            }

            if (options.MaxLoopTime != null && options.CollectMethod.Equals(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()}");
            Cache.CreateInstance(options);
            Utils.CreateInstance(options);

            if (!Utils.CheckWritePrivs())
            {
                Console.WriteLine("Unable to write in chosen directory. Please check privs");
                return;
            }

            SessionHelpers.Init(options);
            LocalAdminHelpers.Init();
            GroupHelpers.Init();
            AclHelpers.Init();
            DomainTrustEnumeration.Init();
            ContainerHelpers.Init();

            if (options.Test != null)
            {
                Test.DoStuff(options.Test);
                return;
            }

            if (options.ComputerFile != null)
            {
                if (!File.Exists(options.ComputerFile))
                {
                    Console.WriteLine("Specified ComputerFile does not exist!");
                    return;
                }

                if (options.CollectMethod.Equals(Default))
                {
                    options.CollectMethod = ComputerOnly;
                    Console.WriteLine("ComputerFile detected with default enumeration. Switching to ComputerOnly collection method");
                }

                if (!(options.CollectMethod.Equals(Session) || options.CollectMethod.Equals(SessionLoop) ||
                      options.CollectMethod.Equals(LoggedOn) || options.CollectMethod.Equals(LocalGroup) ||
                      options.CollectMethod.Equals(ComputerOnly)))
                {
                    Console.WriteLine("ComputerFile can only be used with the following collection methods: ComputerOnly, Session, SessionLoop, LocalGroup, LoggedOn");
                    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 option");
                return;
            }

            if (options.Uri != null)
            {
                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.Stealth)
            {
                Console.WriteLine("Note: All stealth options are single threaded");
            }

            if (options.CollectMethod.Equals(LocalGroup) && options.Stealth)
            {
                Console.WriteLine("Note: You specified Stealth and LocalGroup which is equivalent to GPOLocalGroup");
                options.CollectMethod = GPOLocalGroup;
            }

            var runner = new EnumerationRunner(options);

            if (options.CollectMethod.Equals(SessionLoop))
            {
                if (options.MaxLoopTime == null)
                {
                    Console.WriteLine("Session Loop mode specified without MaxLoopTime, will loop indefinitely");
                }
                else
                {
                    Console.WriteLine($"Session Loop mode specified. Looping will end on {options.LoopEnd.ToShortDateString()} at {options.LoopEnd.ToShortTimeString()}");
                }
            }

            if (options.Stealth)
            {
                runner.StartStealthEnumeration();
            }
            else
            {
                runner.StartEnumeration();
            }
            Cache.Instance.SaveCache();

            Utils.DeduplicateFiles();

            if (options.CompressData)
            {
                Utils.CompressFiles();
            }
        }
Exemplo n.º 2
0
        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;
            }

            if (options.CacheFile == null)
            {
                var sid            = Utils.GetLocalMachineSid();
                var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(sid);
                options.CacheFile = $"{Convert.ToBase64String(plainTextBytes)}.bin";
            }

            try
            {
                // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
                Path.Combine(options.JsonFolder, options.CacheFile);
            }
            catch (ArgumentException)
            {
                Console.WriteLine("Invalid characters in output path. Check for trailing backslashes!");
                return;
            }

            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;
            }

            var resolved = ResolvedCollectionMethod.None;

            foreach (var unparsed in options.CollectionMethod)
            {
                try
                {
                    var e = (CollectionMethod)Enum.Parse(typeof(CollectionMethod), unparsed, true);
                    switch (e)
                    {
                    case All:
                        resolved = resolved | ResolvedCollectionMethod.ACL | ResolvedCollectionMethod.Container |
                                   ResolvedCollectionMethod.Group | ResolvedCollectionMethod.LocalAdmin |
                                   ResolvedCollectionMethod.ObjectProps | ResolvedCollectionMethod.RDP |
                                   ResolvedCollectionMethod.Session | ResolvedCollectionMethod.Trusts |
                                   ResolvedCollectionMethod.DCOM;
                        break;

                    case DcOnly:
                        resolved = resolved | ResolvedCollectionMethod.ACL | ResolvedCollectionMethod.Container |
                                   ResolvedCollectionMethod.Trusts | ResolvedCollectionMethod.ObjectProps |
                                   ResolvedCollectionMethod.GPOLocalGroup | ResolvedCollectionMethod.Group;
                        break;

                    case CollectionMethod.Group:
                        resolved = resolved | ResolvedCollectionMethod.Group;
                        break;

                    case ComputerOnly:
                        resolved = resolved | ResolvedCollectionMethod.LocalAdmin |
                                   ResolvedCollectionMethod.Session | ResolvedCollectionMethod.RDP |
                                   ResolvedCollectionMethod.DCOM;
                        break;

                    case LocalGroup:
                        resolved = resolved | ResolvedCollectionMethod.LocalAdmin | ResolvedCollectionMethod.RDP | ResolvedCollectionMethod.DCOM;
                        break;

                    case GPOLocalGroup:
                        resolved = resolved | ResolvedCollectionMethod.GPOLocalGroup;
                        break;

                    case Session:
                        resolved = resolved | ResolvedCollectionMethod.Session;
                        break;

                    case LoggedOn:
                        resolved = resolved | ResolvedCollectionMethod.LoggedOn;
                        break;

                    case Trusts:
                        resolved = resolved | ResolvedCollectionMethod.Trusts;
                        break;

                    case ACL:
                        resolved = resolved | ResolvedCollectionMethod.ACL;
                        break;

                    case SessionLoop:
                        resolved = resolved | ResolvedCollectionMethod.SessionLoop;
                        break;

                    case Default:
                        resolved = resolved | ResolvedCollectionMethod.RDP | ResolvedCollectionMethod.DCOM | ResolvedCollectionMethod.LocalAdmin | ResolvedCollectionMethod.Group | ResolvedCollectionMethod.Session | ResolvedCollectionMethod.Trusts;
                        break;

                    case ObjectProps:
                        resolved = resolved | ResolvedCollectionMethod.ObjectProps;
                        break;

                    case Container:
                        resolved = resolved | ResolvedCollectionMethod.Container;
                        break;

                    case LocalAdmin:
                        resolved = resolved | ResolvedCollectionMethod.LocalAdmin;
                        break;

                    case RDP:
                        resolved = resolved | ResolvedCollectionMethod.RDP;
                        break;

                    case DCOM:
                        resolved = resolved | ResolvedCollectionMethod.DCOM;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
                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 ((resolved & ResolvedCollectionMethod.SessionLoop) != 0)
            {
                if (options.MaxLoopTime != null)
                {
                    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;
                    }
                }
                else
                {
                    options.LoopEnd = DateTime.Now + TimeSpan.FromHours(2);
                }
            }

            options.CurrentUser = WindowsIdentity.GetCurrent().Name.Split('\\')[1];

            Cache.CreateInstance(options);
            Utils.CreateInstance(options);


            if (!Utils.CheckWritePrivs())
            {
                Console.WriteLine("Unable to write in chosen directory. Please check privs");
                return;
            }

            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;
                }
            }

            if (Utils.Instance.GetDomainList().Count == 0)
            {
                Console.WriteLine("Unable to contact domain. Try from a domain context!");
                return;
            }

            if (options.DomainController != null)
            {
                Console.WriteLine("Manually specifying a domain controller will likely result in data loss. Only use this for performance/opsec reasons");
                if (options.SearchForest)
                {
                    Console.WriteLine("SearchForest is not usable with the --DomainController flag");
                    options.SearchForest = false;
                }
            }
            else
            {
                //Build our DC cache
                Utils.Instance.GetUsableDomainControllers();
            }

            SessionHelpers.Init(options);
            LocalGroupHelpers.Init(options);
            GroupHelpers.Init();
            AclHelpers.Init();
            TrustHelpers.Init();
            ContainerHelpers.Init();

            if (options.Test != null)
            {
                Test.DoStuff(options.Test);
                return;
            }

            //Lets test our connection to LDAP before we do anything else
            try
            {
                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.");
                if (options.LdapPass != null)
                {
                    Console.WriteLine("Check credentials supplied to SharpHound");
                }
                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.");
            //            Console.WriteLine("WARNING: As of BloodHound 1.5, using the REST API is unsupported and will be removed in a future release.");
            //            Console.WriteLine("WARNING: Container collection will not work with the REST API, and bugs may exist.");
            //        }
            //        catch
            //        {
            //            Console.WriteLine("Unable to connect to the Neo4j REST endpoint. Check your URI and username/password");
            //            Console.WriteLine("WARNING: As of BloodHound 1.5, using the REST API is unsupported and will be removed in a future release.");
            //            Console.WriteLine("WARNING: Container collection will not work with the REST API, and bugs may exist.");
            //            return;
            //        }
            //    }
            //}

            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}%");
            }

            //Do some sanity checks
            if (options.ComputerFile != null)
            {
                if (!File.Exists(options.ComputerFile))
                {
                    Console.WriteLine("Specified ComputerFile does not exist!");
                    return;
                }

                if (options.Stealth)
                {
                    Console.WriteLine("Switching to one thread for ComputerFile, removing stealth");
                    options.Stealth = false;
                    options.Threads = 1;
                }

                Console.WriteLine("ComputerFile detected! Removing non-computer collection methods");
                resolved = resolved & ~ResolvedCollectionMethod.ACL & ~ResolvedCollectionMethod.Group
                           & ~ResolvedCollectionMethod.GPOLocalGroup & ~ResolvedCollectionMethod.Trusts
                           & ~ResolvedCollectionMethod.Container & ~ResolvedCollectionMethod.ObjectProps;
            }

            if (options.Stealth)
            {
                if ((resolved & ResolvedCollectionMethod.LocalAdmin) != 0)
                {
                    Console.WriteLine("Note: You specified Stealth and LocalGroup which is equivalent to GPOLocalGroup");
                    resolved = resolved & ~ResolvedCollectionMethod.LocalAdmin;
                    resolved = resolved | ResolvedCollectionMethod.GPOLocalGroup;
                }

                if ((resolved & ResolvedCollectionMethod.LoggedOn) != 0)
                {
                    Console.WriteLine("LoggedOn enumeration is not supported with Stealth");
                    resolved = resolved & ~ResolvedCollectionMethod.LoggedOn;
                }
            }

            if ((resolved & ResolvedCollectionMethod.Session) != 0 &&
                (resolved & ResolvedCollectionMethod.SessionLoop) != 0)
            {
                resolved = resolved ^ ResolvedCollectionMethod.Session;
            }

            if ((resolved & ResolvedCollectionMethod.LoggedOn) != 0 &&
                (resolved & ResolvedCollectionMethod.SessionLoop) != 0)
            {
                resolved = resolved ^ ResolvedCollectionMethod.LoggedOn;
                resolved = resolved | ResolvedCollectionMethod.LoggedOnLoop;
            }


            if ((resolved & ResolvedCollectionMethod.SessionLoop) != 0)
            {
                Console.WriteLine(options.MaxLoopTime == null
                    ? $"Session Loop mode specified without MaxLoopTime, will loop for 2 hours ({options.LoopEnd.ToShortDateString()} at {options.LoopEnd.ToShortTimeString()})"
                    : $"Session Loop mode specified. Looping will end on {options.LoopEnd.ToShortDateString()} at {options.LoopEnd.ToShortTimeString()}");
                Console.WriteLine("Looping will start after any other collection methods");
            }

            if (resolved.Equals(ResolvedCollectionMethod.None))
            {
                Console.WriteLine("No collection methods specified. Exiting");
                return;
            }

            Console.WriteLine($"Resolved Collection Methods to {resolved}");

            if ((resolved & ResolvedCollectionMethod.ACL) != 0)
            {
                Utils.Verbose("Building GUID Cache");
                AclHelpers.BuildGuidCache();
            }

            options.ResolvedCollMethods = resolved;

            var runner = new EnumerationRunner(options);

            if (options.Stealth)
            {
                runner.StartStealthEnumeration();
            }
            else
            {
                if (options.ComputerFile == null)
                {
                    runner.StartEnumeration();
                }
                else
                {
                    runner.StartCompFileEnumeration();
                }
            }
            Console.WriteLine();

            Cache.Instance.SaveCache();
            Utils.Instance.KillConnections();

            if (!options.NoZip)
            {
                Utils.CompressFiles();
            }
        }
Exemplo n.º 3
0
        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();
            }
        }