예제 #1
0
        private static Options ParseImpl(string[] args)
        {
            BlockingMq Mq = BlockingMq.GetMq();

            Mq.Info("Parsing args...");
            Options parsedConfig = new Options();

            // define args
            ValueArgument <string> configFileArg = new ValueArgument <string>('z', "config", "Path to a .toml config file. Run with \'generate\' to puke a sample config file into the working directory.");
            ValueArgument <string> outFileArg    = new ValueArgument <string>('o', "outfile",
                                                                              "Path for output file. You probably want this if you're not using -s.");
            ValueArgument <string> verboseArg = new ValueArgument <string>('v', "verbosity",
                                                                           "Controls verbosity level, options are Trace (most verbose), Debug (less verbose), Info (less verbose still, default), and Data (results only). e.g '-v debug' ");
            SwitchArgument helpArg   = new SwitchArgument('h', "help", "Displays this help.", false);
            SwitchArgument stdOutArg = new SwitchArgument('s', "stdout",
                                                          "Enables outputting results to stdout as soon as they're found. You probably want this if you're not using -o.",
                                                          false);
            ValueArgument <string> snaffleArg = new ValueArgument <string>('m', "snaffle",
                                                                           "Enables and assigns an output dir for Snaffler to automatically snaffle a copy of any found files.");
            ValueArgument <long> snaffleSizeArg = new ValueArgument <long>('l', "snafflesize", "Maximum size of file to snaffle, in bytes. Defaults to 10MB.");
            //var fileHuntArg = new SwitchArgument('f', "filehuntoff",
            //    "Disables file discovery, will only perform computer and share discovery.", false);
            ValueArgument <string> dirTargetArg = new ValueArgument <string>('i', "dirtarget",
                                                                             "Disables computer and share discovery, requires a path to a directory in which to perform file discovery.");
            ValueArgument <string> domainArg = new ValueArgument <string>('d', "domain",
                                                                          "Domain to search for computers to search for shares on to search for files in. Easy.");
            ValueArgument <string> domainControllerArg = new ValueArgument <string>('c', "domaincontroller",
                                                                                    "Domain controller to query for a list of domain computers.");
            ValueArgument <long> maxGrepSizeArg = new ValueArgument <long>('r', "maxgrepsize",
                                                                           "The maximum size file (in bytes) to search inside for interesting strings. Defaults to 500k.");
            ValueArgument <int> grepContextArg = new ValueArgument <int>('j', "grepcontext",
                                                                         "How many bytes of context either side of found strings in files to show, e.g. -j 200");
            SwitchArgument domainUserArg = new SwitchArgument('u', "domainusers", "Makes Snaffler grab a list of interesting-looking accounts from the domain and uses them in searches.", false);

            // list of letters i haven't used yet: abefgknpqwxy

            CommandLineParser.CommandLineParser parser = new CommandLineParser.CommandLineParser();
            parser.Arguments.Add(configFileArg);
            parser.Arguments.Add(outFileArg);
            parser.Arguments.Add(helpArg);
            parser.Arguments.Add(stdOutArg);
            parser.Arguments.Add(snaffleArg);
            parser.Arguments.Add(snaffleSizeArg);
            parser.Arguments.Add(dirTargetArg);
            parser.Arguments.Add(domainArg);
            parser.Arguments.Add(verboseArg);
            parser.Arguments.Add(domainControllerArg);
            parser.Arguments.Add(maxGrepSizeArg);
            parser.Arguments.Add(grepContextArg);
            parser.Arguments.Add(domainUserArg);

            // extra check to handle builtin behaviour from cmd line arg parser
            if ((args.Contains("--help") || args.Contains("/?") || args.Contains("help") || args.Contains("-h") || args.Length == 0))
            {
                parser.ShowUsage();
                Environment.Exit(0);
            }

            TomlSettings settings = TomlSettings.Create(cfg => cfg
                                                        .ConfigureType <LogLevel>(tc =>
                                                                                  tc.WithConversionFor <TomlString>(conv => conv
                                                                                                                    .FromToml(s => (LogLevel)Enum.Parse(typeof(LogLevel), s.Value, ignoreCase: true))
                                                                                                                    .ToToml(e => e.ToString()))));

            try
            {
                parser.ParseCommandLine(args);

                if (configFileArg.Parsed)
                {
                    if (!configFileArg.Value.Equals("generate"))
                    {
                        string configFile = configFileArg.Value;
                        parsedConfig = Toml.ReadFile <Options>(configFile, settings);
                        parsedConfig.PrepareClassifiers();
                        Mq.Info("Read config file from " + configFile);
                        return(parsedConfig);
                    }
                }

                if (parsedConfig.ClassifierRules.Count <= 0)
                {
                    parsedConfig.BuildDefaultClassifiers();
                }
                // get the args into our config

                // output args
                if (outFileArg.Parsed && (!String.IsNullOrEmpty(outFileArg.Value)))
                {
                    parsedConfig.LogToFile   = true;
                    parsedConfig.LogFilePath = outFileArg.Value;
                    Mq.Degub("Logging to file at " + parsedConfig.LogFilePath);
                }

                // Set loglevel.
                if (verboseArg.Parsed)
                {
                    parsedConfig.LogLevelString = verboseArg.Value;
                    Mq.Degub("Requested verbosity level: " + parsedConfig.LogLevelString);
                }

                // if enabled, display findings to the console
                parsedConfig.LogToConsole = stdOutArg.Parsed;
                Mq.Degub("Enabled logging to stdout.");

                // args that tell us about targeting
                if ((domainArg.Parsed) && (!String.IsNullOrEmpty(domainArg.Value)))
                {
                    parsedConfig.TargetDomain = domainArg.Value;
                    Mq.Degub("Target domain is " + domainArg.Value);
                }

                if ((domainControllerArg.Parsed) && (!String.IsNullOrEmpty(domainControllerArg.Value)))
                {
                    parsedConfig.TargetDc = domainControllerArg.Value;
                    Mq.Degub("Target DC is " + domainControllerArg.Value);
                }

                if (domainUserArg.Parsed)
                {
                    parsedConfig.DomainUserRules = true;
                    Mq.Degub("Enabled use of domain user accounts in rules.");
                }

                if (dirTargetArg.Parsed)
                {
                    parsedConfig.ShareFinderEnabled = false;
                    parsedConfig.PathTargets        = new string[] { dirTargetArg.Value };
                    Mq.Degub("Disabled finding shares.");
                    Mq.Degub("Target path is " + dirTargetArg.Value);
                }

                if (maxGrepSizeArg.Parsed)
                {
                    parsedConfig.MaxSizeToGrep = maxGrepSizeArg.Value;
                    Mq.Degub("We won't bother looking inside files if they're bigger than " + parsedConfig.MaxSizeToGrep +
                             " bytes");
                }

                if (snaffleArg.Parsed)
                {
                    parsedConfig.SnafflePath = snaffleArg.Value;
                }

                if (snaffleSizeArg.Parsed)
                {
                    parsedConfig.MaxSizeToSnaffle = snaffleSizeArg.Value;
                }

                // how many bytes
                if (grepContextArg.Parsed)
                {
                    parsedConfig.MatchContextBytes = grepContextArg.Value;
                    Mq.Degub(
                        "We'll show you " + grepContextArg.Value +
                        " bytes of context around matches inside files.");
                }

                // if enabled, grab a copy of files that we like.
                if (snaffleArg.Parsed)
                {
                    if (snaffleArg.Value.Length <= 0)
                    {
                        Mq.Error("-m or -mirror arg requires a path value.");
                        throw new ArgumentException("Invalid argument combination.");
                    }

                    parsedConfig.Snaffle     = true;
                    parsedConfig.SnafflePath = snaffleArg.Value.TrimEnd('\\');
                    Mq.Degub("Mirroring matched files to path " + parsedConfig.SnafflePath);
                }

                if (!parsedConfig.LogToConsole && !parsedConfig.LogToFile)
                {
                    Mq.Error(
                        "\nYou didn't enable output to file or to the console so you won't see any results or debugs or anything. Your l0ss.");
                    throw new ArgumentException("Pointless argument combination.");
                }

                if (configFileArg.Parsed)
                {
                    if (configFileArg.Value.Equals("generate"))
                    {
                        Toml.WriteFile(parsedConfig, ".\\default.toml", settings);
                        Mq.Info("Wrote default config values to .\\default.toml");
                        Mq.Terminate();
                    }
                }

                parsedConfig.PrepareClassifiers();
            }
            catch (Exception e)
            {
                Mq.Error(e.ToString());
                throw;
            }

            return(parsedConfig);
        }
예제 #2
0
파일: Config.cs 프로젝트: SnaffCon/Snaffler
        private static Options ParseImpl(string[] args)
        {
            BlockingMq Mq = BlockingMq.GetMq();

            Mq.Info("Parsing args...");
            Options parsedConfig = new Options();

            // define args
            ValueArgument <string> configFileArg = new ValueArgument <string>('z', "config", "Path to a .toml config file. Run with \'generate\' to puke a sample config file into the working directory.");
            ValueArgument <string> outFileArg    = new ValueArgument <string>('o', "outfile",
                                                                              "Path for output file. You probably want this if you're not using -s.");
            ValueArgument <string> verboseArg = new ValueArgument <string>('v', "verbosity",
                                                                           "Controls verbosity level, options are Trace (most verbose), Debug (less verbose), Info (less verbose still, default), and Data (results only). e.g '-v debug' ");
            SwitchArgument helpArg   = new SwitchArgument('h', "help", "Displays this help.", false);
            SwitchArgument stdOutArg = new SwitchArgument('s', "stdout",
                                                          "Enables outputting results to stdout as soon as they're found. You probably want this if you're not using -o.",
                                                          false);
            ValueArgument <int>    interestLevel = new ValueArgument <int>('b', "interest", "Interest level to report (0-3)");
            ValueArgument <string> snaffleArg    = new ValueArgument <string>('m', "snaffle",
                                                                              "Enables and assigns an output dir for Snaffler to automatically snaffle a copy of any found files.");
            ValueArgument <long> snaffleSizeArg = new ValueArgument <long>('l', "snafflesize", "Maximum size of file to snaffle, in bytes. Defaults to 10MB.");
            //var fileHuntArg = new SwitchArgument('f', "filehuntoff",
            //    "Disables file discovery, will only perform computer and share discovery.", false);
            ValueArgument <string> dirTargetArg = new ValueArgument <string>('i', "dirtarget",
                                                                             "Disables computer and share discovery, requires a path to a directory in which to perform file discovery.");
            ValueArgument <string> domainArg = new ValueArgument <string>('d', "domain",
                                                                          "Domain to search for computers to search for shares on to search for files in. Easy.");
            ValueArgument <string> domainControllerArg = new ValueArgument <string>('c', "domaincontroller",
                                                                                    "Domain controller to query for a list of domain computers.");
            ValueArgument <long> maxGrepSizeArg = new ValueArgument <long>('r', "maxgrepsize",
                                                                           "The maximum size file (in bytes) to search inside for interesting strings. Defaults to 500k.");
            ValueArgument <int> grepContextArg = new ValueArgument <int>('j', "grepcontext",
                                                                         "How many bytes of context either side of found strings in files to show, e.g. -j 200");
            SwitchArgument      domainUserArg     = new SwitchArgument('u', "domainusers", "Makes Snaffler grab a list of interesting-looking accounts from the domain and uses them in searches.", false);
            ValueArgument <int> maxThreadsArg     = new ValueArgument <int>('x', "maxthreads", "How many threads to be snaffling with. Any less than 4 and you're gonna have a bad time.");
            SwitchArgument      tsvArg            = new SwitchArgument('y', "tsv", "Makes Snaffler output as tsv.", false);
            SwitchArgument      dfsArg            = new SwitchArgument('f', "dfs", "Limits Snaffler to finding file shares via DFS, for \"OPSEC\" reasons.", false);
            SwitchArgument      findSharesOnlyArg = new SwitchArgument('a', "sharesonly",
                                                                       "Stops after finding shares, doesn't walk their filesystems.", false);
            ValueArgument <string> compTargetArg = new ValueArgument <string>('n', "comptarget", "Computer (or comma separated list) to target.");
            ValueArgument <string> ruleDirArg    = new ValueArgument <string>('p', "rulespath", "Path to a directory full of toml-formatted rules. Snaffler will load all of these in place of the default ruleset.");
            ValueArgument <string> logType       = new ValueArgument <string>('t', "logtype", "Type of log you would like to output. Currently supported options are plain and JSON. Defaults to plain.");

            // list of letters i haven't used yet: egknqw

            CommandLineParser.CommandLineParser parser = new CommandLineParser.CommandLineParser();
            parser.Arguments.Add(configFileArg);
            parser.Arguments.Add(outFileArg);
            parser.Arguments.Add(helpArg);
            parser.Arguments.Add(stdOutArg);
            parser.Arguments.Add(snaffleArg);
            parser.Arguments.Add(snaffleSizeArg);
            parser.Arguments.Add(dirTargetArg);
            parser.Arguments.Add(interestLevel);
            parser.Arguments.Add(domainArg);
            parser.Arguments.Add(verboseArg);
            parser.Arguments.Add(domainControllerArg);
            parser.Arguments.Add(maxGrepSizeArg);
            parser.Arguments.Add(grepContextArg);
            parser.Arguments.Add(domainUserArg);
            parser.Arguments.Add(tsvArg);
            parser.Arguments.Add(dfsArg);
            parser.Arguments.Add(findSharesOnlyArg);
            parser.Arguments.Add(maxThreadsArg);
            parser.Arguments.Add(compTargetArg);
            parser.Arguments.Add(ruleDirArg);
            parser.Arguments.Add(logType);

            // extra check to handle builtin behaviour from cmd line arg parser
            if ((args.Contains("--help") || args.Contains("/?") || args.Contains("help") || args.Contains("-h") || args.Length == 0))
            {
                parser.ShowUsage();
                Environment.Exit(0);
            }

            TomlSettings settings = TomlSettings.Create(cfg => cfg
                                                        .ConfigureType <LogLevel>(tc =>
                                                                                  tc.WithConversionFor <TomlString>(conv => conv
                                                                                                                    .FromToml(s => (LogLevel)Enum.Parse(typeof(LogLevel), s.Value, ignoreCase: true))
                                                                                                                    .ToToml(e => e.ToString()))));

            try
            {
                parser.ParseCommandLine(args);

                if (logType.Parsed && !String.IsNullOrWhiteSpace(logType.Value))
                {
                    //Set the default to plain
                    parsedConfig.LogType = LogType.Plain;
                    //if they set a different type then replace it with the new type.
                    if (logType.Value.ToLower() == "json")
                    {
                        parsedConfig.LogType = LogType.JSON;
                    }
                    else
                    {
                        Mq.Info("Invalid type argument passed (" + logType.Value + ") defaulting to plaintext");
                    }
                }

                if (ruleDirArg.Parsed && !String.IsNullOrWhiteSpace(ruleDirArg.Value))
                {
                    parsedConfig.RuleDir = ruleDirArg.Value;
                }

                // get the args into our config

                // output args
                if (outFileArg.Parsed && (!String.IsNullOrEmpty(outFileArg.Value)))
                {
                    parsedConfig.LogToFile   = true;
                    parsedConfig.LogFilePath = outFileArg.Value;
                    Mq.Degub("Logging to file at " + parsedConfig.LogFilePath);
                }

                if (dfsArg.Parsed)
                {
                    parsedConfig.DfsOnly = dfsArg.Value;
                }

                if (compTargetArg.Parsed)
                {
                    string[] compTargets = null;
                    if (compTargetArg.Value.Contains(","))
                    {
                        compTargets = compTargetArg.Value.Split(',');
                    }
                    else
                    {
                        compTargets = new string[] { compTargetArg.Value };
                    }
                    parsedConfig.ComputerTargets = compTargets;
                }

                if (findSharesOnlyArg.Parsed)
                {
                    parsedConfig.ScanFoundShares = false;
                }
                if (maxThreadsArg.Parsed)
                {
                    parsedConfig.MaxThreads = maxThreadsArg.Value;
                }

                parsedConfig.ShareThreads = parsedConfig.MaxThreads / 3;
                parsedConfig.FileThreads  = parsedConfig.MaxThreads / 3;
                parsedConfig.TreeThreads  = parsedConfig.MaxThreads / 3;

                if (tsvArg.Parsed)
                {
                    parsedConfig.LogTSV = true;
                    if (parsedConfig.Separator == ' ')
                    {
                        parsedConfig.Separator = '\t';
                    }
                }

                // Set loglevel.
                if (verboseArg.Parsed)
                {
                    parsedConfig.LogLevelString = verboseArg.Value;
                    Mq.Degub("Requested verbosity level: " + parsedConfig.LogLevelString);
                }

                // if enabled, display findings to the console
                parsedConfig.LogToConsole = stdOutArg.Parsed;
                Mq.Degub("Enabled logging to stdout.");

                // args that tell us about targeting
                if ((domainArg.Parsed) && (!String.IsNullOrEmpty(domainArg.Value)))
                {
                    parsedConfig.TargetDomain = domainArg.Value;
                    Mq.Degub("Target domain is " + domainArg.Value);
                }

                if ((domainControllerArg.Parsed) && (!String.IsNullOrEmpty(domainControllerArg.Value)))
                {
                    parsedConfig.TargetDc = domainControllerArg.Value;
                    Mq.Degub("Target DC is " + domainControllerArg.Value);
                }

                if (domainUserArg.Parsed)
                {
                    parsedConfig.DomainUserRules = true;
                    Mq.Degub("Enabled use of domain user accounts in rules.");
                }

                if (dirTargetArg.Parsed)
                {
                    parsedConfig.ShareFinderEnabled = false;
                    parsedConfig.PathTargets.Add(dirTargetArg.Value);
                    Mq.Degub("Disabled finding shares.");
                    Mq.Degub("Target path is " + dirTargetArg.Value);
                }

                if (maxGrepSizeArg.Parsed)
                {
                    parsedConfig.MaxSizeToGrep = maxGrepSizeArg.Value;
                    Mq.Degub("We won't bother looking inside files if they're bigger than " + parsedConfig.MaxSizeToGrep +
                             " bytes");
                }

                if (snaffleSizeArg.Parsed)
                {
                    parsedConfig.MaxSizeToSnaffle = snaffleSizeArg.Value;
                }

                if (interestLevel.Parsed)
                {
                    parsedConfig.InterestLevel = interestLevel.Value;
                    Mq.Degub("Requested interest level: " + parsedConfig.InterestLevel);
                }

                // how many bytes
                if (grepContextArg.Parsed)
                {
                    parsedConfig.MatchContextBytes = grepContextArg.Value;
                    Mq.Degub(
                        "We'll show you " + grepContextArg.Value +
                        " bytes of context around matches inside files.");
                }

                // if enabled, grab a copy of files that we like.
                if (snaffleArg.Parsed)
                {
                    if (snaffleArg.Value.Length <= 0)
                    {
                        Mq.Error("-m or -mirror arg requires a path value.");
                        throw new ArgumentException("Invalid argument combination.");
                    }

                    parsedConfig.Snaffle     = true;
                    parsedConfig.SnafflePath = snaffleArg.Value.TrimEnd('\\');
                    Mq.Degub("Mirroring matched files to path " + parsedConfig.SnafflePath);
                }

                if (configFileArg.Parsed)
                {
                    if (configFileArg.Value.Equals("generate"))
                    {
                        Toml.WriteFile(parsedConfig, ".\\default.toml", settings);
                        Console.WriteLine("Wrote config values to .\\default.toml");
                        parsedConfig.LogToConsole = true;
                        Mq.Degub("Enabled logging to stdout.");
                        Environment.Exit(0);
                    }
                    else
                    {
                        string configFile = configFileArg.Value;
                        parsedConfig = Toml.ReadFile <Options>(configFile, settings);
                        Mq.Info("Read config file from " + configFile);
                    }
                }

                if (!parsedConfig.LogToConsole && !parsedConfig.LogToFile)
                {
                    Mq.Error(
                        "\nYou didn't enable output to file or to the console so you won't see any results or debugs or anything. Your l0ss.");
                    throw new ArgumentException("Pointless argument combination.");
                }

                if (parsedConfig.ClassifierRules.Count <= 0)
                {
                    if (String.IsNullOrWhiteSpace(parsedConfig.RuleDir))
                    {
                        // get all the embedded toml file resources
                        string[]      resourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
                        StringBuilder sb            = new StringBuilder();

                        foreach (string resourceName in resourceNames)
                        {
                            if (!resourceName.EndsWith(".toml"))
                            {
                                // skip this one as it's just metadata
                                continue;
                            }
                            string ruleFile = ReadResource(resourceName);
                            sb.AppendLine(ruleFile);
                        }

                        string bulktoml = sb.ToString();

                        // deserialise the toml to an actual ruleset
                        RuleSet ruleSet = Toml.ReadString <RuleSet>(bulktoml, settings);

                        // stick the rules in our config!
                        parsedConfig.ClassifierRules = ruleSet.ClassifierRules;
                    }
                    else
                    {
                        string[]      tomlfiles = Directory.GetFiles(parsedConfig.RuleDir, "*.toml", SearchOption.AllDirectories);
                        StringBuilder sb        = new StringBuilder();
                        foreach (string tomlfile in tomlfiles)
                        {
                            string tomlstring = File.ReadAllText(tomlfile);
                            sb.AppendLine(tomlstring);
                        }
                        string bulktoml = sb.ToString();
                        // deserialise the toml to an actual ruleset
                        RuleSet ruleSet = Toml.ReadString <RuleSet>(bulktoml, settings);

                        // stick the rules in our config!
                        parsedConfig.ClassifierRules = ruleSet.ClassifierRules;
                    }
                }

                parsedConfig.PrepareClassifiers();
            }
            catch (Exception e)
            {
                Mq.Error(e.ToString());
                throw;
            }

            return(parsedConfig);
        }