nuclei/v2/internal/runner/options.go

213 lines
9.7 KiB
Go
Raw Normal View History

2020-04-03 22:15:39 +00:00
package runner
import (
2020-08-29 13:26:11 +00:00
"errors"
2020-04-03 22:15:39 +00:00
"flag"
2020-08-29 13:26:11 +00:00
"net/url"
2020-04-03 22:15:39 +00:00
"os"
"github.com/projectdiscovery/gologger"
2020-07-01 10:47:24 +00:00
"github.com/projectdiscovery/nuclei/v2/pkg/requests"
2020-04-03 22:15:39 +00:00
)
// Options contains the configuration options for tuning
// the template requesting process.
2020-10-23 10:29:49 +00:00
// nolint // false positive, options are allocated once and are necessary as is
2020-04-03 22:15:39 +00:00
type Options struct {
2020-10-23 08:13:34 +00:00
Debug bool // Debug mode allows debugging request/responses for the engine
Silent bool // Silent suppresses any extra text and only writes found URLs on screen.
Version bool // Version specifies if we should just show version and exit
Verbose bool // Verbose flag indicates whether to show verbose output or not
NoColor bool // No-Color disables the colored output.
UpdateTemplates bool // UpdateTemplates updates the templates installed at startup
JSON bool // JSON writes json output to files
JSONRequests bool // write requests/responses for matches in JSON output
EnableProgressBar bool // Enable progrss bar
TemplatesVersion bool // Show the templates installed version
TemplateList bool // List available templates
Stdin bool // Stdin specifies whether stdin input was given to the process
StopAtFirstMatch bool // Stop processing template at first full match (this may break chained requests)
NoMeta bool // Don't display metadata for the matches
BulkSize int // Number of targets analyzed in parallel for each template
2020-10-23 10:55:48 +00:00
TemplateThreads int // Number of templates executed in parallel
Project bool // Nuclei uses project folder to avoid sending same HTTP request multiple times
ProjectPath string // Nuclei uses a user defined project folder
2020-10-23 08:13:34 +00:00
Timeout int // Timeout is the seconds to wait for a response from the server.
Retries int // Retries is the number of times to retry the request
RateLimit int // Rate-Limit of requests per specified target
Severity string // Filter templates based on their severity and only run the matching ones.
Target string // Target is a single URL/Domain to scan usng a template
Targets string // Targets specifies the targets to scan using templates.
Output string // Output is the file to write found subdomains to.
ProxyURL string // ProxyURL is the URL for the proxy server
ProxySocksURL string // ProxySocksURL is the URL for the proxy socks server
TemplatesDirectory string // TemplatesDirectory is the directory to use for storing templates
2020-10-23 08:16:17 +00:00
TraceLogFile string // TraceLogFile specifies a file to write with the trace of all requests
2020-10-23 08:13:34 +00:00
Templates multiStringFlag // Signature specifies the template/templates to use
ExcludedTemplates multiStringFlag // Signature specifies the template/templates to exclude
CustomHeaders requests.CustomHeaders // Custom global headers
2020-10-23 10:55:48 +00:00
Threads int // Thread controls the number of concurrent requests to make.
2020-10-23 08:13:34 +00:00
BurpCollaboratorBiid string // Burp Collaborator BIID for polling
2020-04-03 22:15:39 +00:00
}
type multiStringFlag []string
func (m *multiStringFlag) String() string {
return ""
}
func (m *multiStringFlag) Set(value string) error {
*m = append(*m, value)
return nil
}
2020-04-03 22:15:39 +00:00
// ParseOptions parses the command line flags provided by a user
func ParseOptions() *Options {
options := &Options{}
flag.StringVar(&options.Target, "target", "", "Target is a single target to scan using template")
2020-08-02 13:48:10 +00:00
flag.Var(&options.Templates, "t", "Template input dir/file/files to run on host. Can be used multiple times. Supports globbing.")
flag.Var(&options.ExcludedTemplates, "exclude", "Template input dir/file/files to exclude. Can be used multiple times. Supports globbing.")
2020-08-02 16:33:55 +00:00
flag.StringVar(&options.Severity, "severity", "", "Filter templates based on their severity and only run the matching ones. Comma-separated values can be used to specify multiple severities.")
2020-04-04 11:54:31 +00:00
flag.StringVar(&options.Targets, "l", "", "List of URLs to run templates on")
2020-04-03 22:15:39 +00:00
flag.StringVar(&options.Output, "o", "", "File to write output to (optional)")
2020-04-27 18:19:53 +00:00
flag.StringVar(&options.ProxyURL, "proxy-url", "", "URL of the proxy server")
2020-04-28 02:01:25 +00:00
flag.StringVar(&options.ProxySocksURL, "proxy-socks-url", "", "URL of the proxy socks server")
2020-04-04 11:54:31 +00:00
flag.BoolVar(&options.Silent, "silent", false, "Show only results in output")
flag.BoolVar(&options.Version, "version", false, "Show version of nuclei")
2020-04-03 22:15:39 +00:00
flag.BoolVar(&options.Verbose, "v", false, "Show Verbose output")
2020-11-19 09:45:48 +00:00
flag.BoolVar(&options.NoColor, "no-color", false, "Disable colors in output")
2020-04-04 12:40:26 +00:00
flag.IntVar(&options.Timeout, "timeout", 5, "Time to wait in seconds before timeout")
flag.IntVar(&options.Retries, "retries", 1, "Number of times to retry a failed request")
2020-05-21 22:23:38 +00:00
flag.Var(&options.CustomHeaders, "H", "Custom Header.")
2020-06-22 14:00:01 +00:00
flag.BoolVar(&options.Debug, "debug", false, "Allow debugging of request/responses")
2020-06-24 22:23:37 +00:00
flag.BoolVar(&options.UpdateTemplates, "update-templates", false, "Update Templates updates the installed templates (optional)")
flag.StringVar(&options.TraceLogFile, "trace-log", "", "File to write sent requests trace log")
2020-06-27 15:22:54 +00:00
flag.StringVar(&options.TemplatesDirectory, "update-directory", "", "Directory to use for storing nuclei-templates")
2020-06-27 14:49:43 +00:00
flag.BoolVar(&options.JSON, "json", false, "Write json output to files")
flag.BoolVar(&options.JSONRequests, "include-rr", false, "Write requests/responses for matches in JSON output")
flag.BoolVar(&options.EnableProgressBar, "stats", false, "Display stats of the running scan")
2020-08-29 13:26:11 +00:00
flag.BoolVar(&options.TemplateList, "tl", false, "List available templates")
flag.IntVar(&options.RateLimit, "rate-limit", 150, "Rate-Limit (maximum requests/second")
flag.BoolVar(&options.StopAtFirstMatch, "stop-at-first-match", false, "Stop processing http requests at first match (this may break template/workflow logic)")
2020-10-20 17:21:11 +00:00
flag.IntVar(&options.BulkSize, "bulk-size", 25, "Maximum Number of hosts analyzed in parallel per template")
flag.IntVar(&options.TemplateThreads, "c", 10, "Maximum Number of templates executed in parallel")
2020-10-17 00:10:47 +00:00
flag.BoolVar(&options.Project, "project", false, "Use a project folder to avoid sending same request multiple times")
flag.StringVar(&options.ProjectPath, "project-path", "", "Use a user defined project folder, temporary folder is used if not specified but enabled")
2020-10-19 20:27:38 +00:00
flag.BoolVar(&options.NoMeta, "no-meta", false, "Don't display metadata for the matches")
flag.BoolVar(&options.TemplatesVersion, "templates-version", false, "Shows the installed nuclei-templates version")
2020-10-23 08:13:34 +00:00
flag.StringVar(&options.BurpCollaboratorBiid, "burp-collaborator-biid", "", "Burp Collaborator BIID")
2020-04-03 22:15:39 +00:00
flag.Parse()
// Check if stdin pipe was given
options.Stdin = hasStdin()
// Read the inputs and configure the logging
options.configureOutput()
// Show the user the banner
showBanner()
if options.Version {
gologger.Infof("Current Version: %s\n", Version)
os.Exit(0)
}
if options.TemplatesVersion {
config, err := readConfiguration()
if err != nil {
gologger.Fatalf("Could not read template configuration: %s\n", err)
}
gologger.Infof("Current nuclei-templates version: %s (%s)\n", config.CurrentVersion, config.TemplatesDirectory)
os.Exit(0)
}
2020-04-03 22:15:39 +00:00
// Validate the options passed by the user and if any
// invalid options have been used, exit.
err := options.validateOptions()
if err != nil {
gologger.Fatalf("Program exiting: %s\n", err)
}
2020-04-03 22:15:39 +00:00
return options
}
func hasStdin() bool {
2020-09-28 10:50:00 +00:00
stat, err := os.Stdin.Stat()
2020-04-03 22:15:39 +00:00
if err != nil {
return false
}
2020-09-28 10:50:00 +00:00
isPipedFromChrDev := (stat.Mode() & os.ModeCharDevice) == 0
isPipedFromFIFO := (stat.Mode() & os.ModeNamedPipe) != 0
2020-09-28 10:50:00 +00:00
return isPipedFromChrDev || isPipedFromFIFO
2020-04-03 22:15:39 +00:00
}
2020-08-29 13:26:11 +00:00
// validateOptions validates the configuration options passed
func (options *Options) validateOptions() error {
// Both verbose and silent flags were used
if options.Verbose && options.Silent {
return errors.New("both verbose and silent mode specified")
}
if !options.TemplateList {
2020-08-29 13:26:11 +00:00
// Check if a list of templates was provided and it exists
if len(options.Templates) == 0 && !options.UpdateTemplates {
return errors.New("no template/templates provided")
}
if options.Targets == "" && !options.Stdin && options.Target == "" && !options.UpdateTemplates {
return errors.New("no target input provided")
}
}
// Validate proxy options if provided
2020-08-29 14:25:30 +00:00
err := validateProxyURL(
options.ProxyURL,
"invalid http proxy format (It should be http://username:password@host:port)",
)
if err != nil {
return err
}
err = validateProxyURL(
options.ProxySocksURL,
"invalid socks proxy format (It should be socks5://username:password@host:port)",
)
if err != nil {
return err
2020-08-29 13:26:11 +00:00
}
2020-08-29 14:25:30 +00:00
return nil
}
func validateProxyURL(proxyURL, message string) error {
if proxyURL != "" && !isValidURL(proxyURL) {
return errors.New(message)
2020-08-29 13:26:11 +00:00
}
return nil
}
2020-08-29 14:25:30 +00:00
func isValidURL(urlString string) bool {
_, err := url.Parse(urlString)
2020-08-29 13:26:11 +00:00
return err == nil
}
// configureOutput configures the output on the screen
func (options *Options) configureOutput() {
// If the user desires verbose output, show verbose output
if options.Verbose {
gologger.MaxLevel = gologger.Verbose
}
if options.NoColor {
gologger.UseColors = false
}
if options.Silent {
gologger.MaxLevel = gologger.Silent
}
}