Exemplo n.º 1
0
        /// <summary>
        /// Process the output of the scan
        /// </summary>
        /// <param name="options"></param>
        /// <param name="hostname"></param>
        /// <param name="result">Compound result</param>
        private static void ProcessResult(CommandOptions options, ScanResult result)
        {
            {
                if (result.Status != QueryStatus.Success || result.Content == null)
                {
                    if (options.MinVerbosity(Verbosity.Errors))
                    {
                        Console.WriteLine("[!] Error: {0} whilst processing {1}", result.Status, result.Hostname);
                    }
                    return;
                }


                // Save
                if (!String.IsNullOrEmpty(options.OutputFilename))
                {
                    Save(options, result);
                }


                // Nothing to output if verbosity is below Standard
                if (!options.MinVerbosity(Verbosity.Standard))
                {
                    return;
                }


                string score = GetScore(result.Content);

                if (options.Verbosity != Verbosity.None)
                {
                    Console.WriteLine("{0} ({1})", result.Hostname, score);

                    if (options.DetailLevel != DetailLevel.Score)
                    {
                        Console.WriteLine(result.Content);
                    }
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Normal run condition
        /// </summary>
        /// <param name="options"></param>
        internal static void RunOptions(CommandOptions options)
        {
            List <string> errors = new List <string>();

            // Process the targets from the hostnames and import any files
            errors.AddRange(CommandOptions.PopulateTargets(ref options));

            // Validate entries
            errors.AddRange(options.CheckOptions());

            // Report on any errors
            if (errors.Count > 0)
            {
                Console.WriteLine("Errors found:");
                foreach (string error in errors)
                {
                    Console.WriteLine(" * " + error);
                }
                Console.WriteLine("\nUse --help for details of command options.");
                return;
            }


            // Parallel operation, but will be serial if MaxParallel is set as 1
            Parallel.ForEach(options.Targets,
                             new ParallelOptions {
                MaxDegreeOfParallelism = options.MaxParallel
            },
                             (hostname) =>
            {
                Stopwatch runTimer = new Stopwatch();
                runTimer.Start();


                // check we have something to scan
                ScanResult result = Scanner.ScanHost(ref options, hostname);


                runTimer.Stop();
                result.Runtime = runTimer.ElapsedMilliseconds / 1000;
                if (options.MinVerbosity(Verbosity.Standard))
                {
                    Console.WriteLine("[.] Timer: {0} took {1}s", hostname, result.Runtime);
                }


                if (result != null)
                {
                    ProcessResult(options, result);
                }
            });
        }
Exemplo n.º 3
0
        /// <summary>
        /// Save it
        /// </summary>
        /// <param name="options"></param>
        /// <param name="hostname"></param>
        /// <param name="result"></param>
        private static void Save(CommandOptions options, ScanResult result)
        {
            // Format the filename
            string fileName = options.GenerateFilename(result);

            try
            {
                // If this is a directory, then we will add default naming  [don't use EndsWith as this doesn't support char in targetted .NET Framework]
                if (Directory.Exists(fileName) || fileName[fileName.Length - 1] == Path.DirectorySeparatorChar || fileName[fileName.Length - 1] == Path.AltDirectorySeparatorChar)
                {
                    Directory.CreateDirectory(fileName);
                    fileName = Path.Combine(fileName, result.Hostname + "-" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".json");
                }


                if (options.MinVerbosity(Verbosity.Standard))
                {
                    Console.WriteLine("[.] Writing to: {0}", fileName);
                }


                FileInfo fileInfo = new FileInfo(fileName);
                if (!fileInfo.Directory.Exists)
                {
                    Directory.CreateDirectory(fileInfo.Directory.FullName);
                }


                string serialised = null;
                try
                {
                    serialised = result.Content.ToString();
                }
                catch (Exception)
                {
                    Console.WriteLine("[!] Error: Unable to convert {0} to a saveable format", result.Hostname);
                }


                // Store it to the drive
                using (var filestream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
                    using (var file = new StreamWriter(filestream, System.Text.Encoding.Default, 4096))
                    {
                        file.WriteLine(serialised);
                    }
            }
            catch (Exception)
            {
                Console.WriteLine("[!] Error: Unable to save {0} to {1}", result.Hostname, fileName);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Obtain the results of a host
        /// </summary>
        /// <param name="options"></param>
        /// <param name="hostname"></param>
        /// <returns></returns>
        internal static ScanResult ScanHost(ref CommandOptions options, string hostname)
        {
            ScanResult result = new ScanResult()
            {
                Hostname = hostname, StartTime = DateTime.UtcNow
            };

            string apiResult = null;

            if (options.Verbosity > 0)
            {
                Console.WriteLine("[.] Scanning: {0}", hostname);
            }

            // server can report overload, so have a limited number of tests
            int overLoadRetry = 0;

            while (overLoadRetry < MaxOverloadRetries)
            {
                using (WebClient client = new WebClient())
                {
                    result.Tries = 1;
                    Uri endpoint = BuildQueryUri(options, hostname, true);

                    if (options.MinVerbosity(Verbosity.Standard))
                    {
                        Console.WriteLine("[.] Requesting: " + endpoint.ToString());
                    }

                    // Iterate for up to the permitted number of tries
                    while (result.Tries <= options.MaxTries)
                    {
                        // Get the revised one - it can change after the first request due to the caching mode
                        if (result.Tries == 2)
                        {
                            endpoint = endpoint = BuildQueryUri(options, hostname, false);

                            if (options.MinVerbosity(Verbosity.Detailed))
                            {
                                Console.WriteLine("[.] Request string is now: " + endpoint.ToString());
                            }
                        }


                        // Obtain the response
                        try
                        {
                            apiResult = client.DownloadString(endpoint);
                        }
                        catch (WebException ex)
                        {
                            if (ex.Status == WebExceptionStatus.Timeout)
                            {
                                result.Status = QueryStatus.Timeout;
                            }
                            else if (ex.Response != null)
                            {
                                switch (((HttpWebResponse)ex.Response).StatusCode)
                                {
                                case (HttpStatusCode)429:                                             // TooManyRequests - Not a const in .NET Framework target
                                    result.Status = QueryStatus.RateLimited;

                                    // Adapt to manage this if it's the first time seeing it
                                    if (options.MaxParallel > 1 && overLoadRetry == 0)
                                    {
                                        options.MaxParallel--;
                                    }

                                    // Sleep for a random time as there may well be other threads also hitting this
                                    Random sleepRandomiser = new Random();
#pragma warning disable SCS0005 // Weak random generator - this is not intended to be a strong form of random
                                    int rateLimitedSleepDelay = sleepRandomiser.Next(1000, 10000);
#pragma warning restore SCS0005 // Weak random generator

                                    if (options.MinVerbosity(Verbosity.Detailed))
                                    {
                                        Console.WriteLine("[.] Server overloaded. Pausing {0} for {1}", hostname, rateLimitedSleepDelay);
                                    }

                                    System.Threading.Thread.Sleep(rateLimitedSleepDelay);

                                    continue;

                                case HttpStatusCode.ServiceUnavailable:                                           // 503
                                    result.Status = QueryStatus.Maintenance;
                                    break;

                                case (HttpStatusCode)529:                                                         // 529
                                    result.Status = QueryStatus.Overloaded;
                                    break;

                                case (HttpStatusCode)441:                                                         // Unknown. Received with host of 127.0.0.1
                                    result.Status = QueryStatus.WebError;
                                    break;

                                default:
                                    result.Status = QueryStatus.WebError;

                                    if (options.Verbosity == Verbosity.Responses)
                                    {
                                        Console.WriteLine("[!] Error with the Web Server... Techie details follow:\n" + ex.ToString());
                                    }
                                    else if (options.MinVerbosity(Verbosity.Errors))
                                    {
                                        Console.WriteLine("[!] Error with the Web Server");
                                    }

                                    break;
                                }
                            }

                            if (result.Status != QueryStatus.RateLimited)
                            {
                                return(result);
                            }
                        }


                        if (options.Verbosity == Verbosity.Responses)
                        {
                            Console.WriteLine("[.] Raw server response: " + apiResult);
                        }


                        // Convert to a parsed JSON object
                        try
                        {
                            result.Content = JObject.Parse(apiResult);
                        }
                        catch (Exception)
                        {
                            result.Status = QueryStatus.ResponseError;
                            return(result);
                        }


                        // Check it
                        string responseStatus = (string)result.Content["status"];

                        if (responseStatus == "READY")
                        {
                            // This means it's finished, not that the test was correct. e.g. checks for a host that responds to ping but has no HTTPS endpoint (test case: amazon.ie)
                            bool validScan = false;

                            foreach (var item in result.Content["endpoints"])
                            {
                                if ((string)item["statusMessage"] == "Ready")
                                {
                                    validScan = true;
                                }
                            }

                            if (validScan)
                            {
                                result.Status = QueryStatus.Success;
                            }
                            else
                            {
                                result.Status = QueryStatus.HostError;                                    // e.g. "Unable to connect to the server"
                            }
                            return(result);
                        }

                        if (responseStatus == "ERROR")
                        {
                            if ((string)result.Content["statusMessage"] == "Unable to resolve domain name")
                            {
                                result.Status = QueryStatus.InvalidHostname;
                            }
                            else
                            {
                                result.Status = QueryStatus.ServiceError;
                            }

                            return(result);
                        }


                        result.Tries++;

                        int pauseMs = CalculatePauseTime(options, result);

                        if (options.MinVerbosity(Verbosity.Detailed))
                        {
                            Console.WriteLine("[.] Pausing {1} for {0} ms", pauseMs, hostname);
                        }

                        // Pause for a little mo
                        System.Threading.Thread.Sleep(pauseMs);
                    }
                }

                overLoadRetry++;
            }

            if (result.Status != QueryStatus.RateLimited)
            {
                result.Status = QueryStatus.Timeout;
            }

            return(result);
        }