2020-04-04 03:45:39 +05:30
package runner
import (
2020-08-29 15:26:11 +02:00
"errors"
2020-04-04 03:45:39 +05:30
"flag"
2020-08-29 15:26:11 +02:00
"net/url"
2020-04-04 03:45:39 +05:30
"os"
"github.com/projectdiscovery/gologger"
)
// ParseOptions parses the command line flags provided by a user
func ParseOptions ( ) * Options {
options := & Options { }
2020-12-19 00:10:58 +05:30
flag . BoolVar ( & options . Vhost , "vhost" , false , "Input supplied is a comma-separated vhost list" )
2020-12-13 14:04:58 +05:30
flag . BoolVar ( & options . Sandbox , "sandbox" , false , "Run workflows in isolated sandbox mode" )
2020-12-17 20:33:42 +05:30
flag . BoolVar ( & options . Metrics , "metrics" , false , "Expose nuclei metrics on a port" )
flag . IntVar ( & options . MetricsPort , "metrics-port" , 9092 , "Port to expose nuclei metrics on" )
2020-12-13 14:17:58 +05:30
flag . IntVar ( & options . MaxWorkflowDuration , "workflow-duration" , 10 , "Max time for workflow run on single URL in minutes" )
2020-06-25 21:40:20 +05:30
flag . StringVar ( & options . Target , "target" , "" , "Target is a single target to scan using template" )
2020-08-02 15:48:10 +02: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 18:33:55 +02: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 17:24:31 +05:30
flag . StringVar ( & options . Targets , "l" , "" , "List of URLs to run templates on" )
2020-04-04 03:45:39 +05:30
flag . StringVar ( & options . Output , "o" , "" , "File to write output to (optional)" )
2020-04-27 23:49:53 +05:30
flag . StringVar ( & options . ProxyURL , "proxy-url" , "" , "URL of the proxy server" )
2020-04-28 04:01:25 +02:00
flag . StringVar ( & options . ProxySocksURL , "proxy-socks-url" , "" , "URL of the proxy socks server" )
2020-04-04 17:24:31 +05:30
flag . BoolVar ( & options . Silent , "silent" , false , "Show only results in output" )
flag . BoolVar ( & options . Version , "version" , false , "Show version of nuclei" )
2020-04-04 03:45:39 +05:30
flag . BoolVar ( & options . Verbose , "v" , false , "Show Verbose output" )
2020-11-19 15:15:48 +05:30
flag . BoolVar ( & options . NoColor , "no-color" , false , "Disable colors in output" )
2020-04-04 18:10:26 +05:30
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-11-22 17:07:40 +07:00
flag . BoolVar ( & options . RandomAgent , "random-agent" , false , "Use randomly selected HTTP User-Agent header value" )
2020-05-22 00:23:38 +02:00
flag . Var ( & options . CustomHeaders , "H" , "Custom Header." )
2020-06-22 19:30:01 +05:30
flag . BoolVar ( & options . Debug , "debug" , false , "Allow debugging of request/responses" )
2020-06-25 03:53:37 +05:30
flag . BoolVar ( & options . UpdateTemplates , "update-templates" , false , "Update Templates updates the installed templates (optional)" )
2020-10-22 16:12:16 +05:30
flag . StringVar ( & options . TraceLogFile , "trace-log" , "" , "File to write sent requests trace log" )
2020-06-27 20:52:54 +05:30
flag . StringVar ( & options . TemplatesDirectory , "update-directory" , "" , "Directory to use for storing nuclei-templates" )
2020-06-27 20:19:43 +05:30
flag . BoolVar ( & options . JSON , "json" , false , "Write json output to files" )
2020-11-19 13:06:43 +05:30
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 15:26:11 +02:00
flag . BoolVar ( & options . TemplateList , "tl" , false , "List available templates" )
2020-11-16 00:40:32 +01:00
flag . IntVar ( & options . RateLimit , "rate-limit" , 150 , "Rate-Limit (maximum requests/second" )
2020-10-06 21:38:44 +02:00
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 19:21:11 +02: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 02:10:47 +02: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-20 01:57:38 +05:30
flag . BoolVar ( & options . NoMeta , "no-meta" , false , "Don't display metadata for the matches" )
2020-10-20 02:14:44 +05:30
flag . BoolVar ( & options . TemplatesVersion , "templates-version" , false , "Shows the installed nuclei-templates version" )
2020-10-23 10:13:34 +02:00
flag . StringVar ( & options . BurpCollaboratorBiid , "burp-collaborator-biid" , "" , "Burp Collaborator BIID" )
2020-04-04 03:45:39 +05:30
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 )
}
2020-10-20 02:14:44 +05:30
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-26 06:48:10 +05:30
2020-04-04 03:45:39 +05:30
// 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-08-25 23:24:31 +02:00
2020-04-04 03:45:39 +05:30
return options
}
func hasStdin ( ) bool {
2020-09-28 12:50:00 +02:00
stat , err := os . Stdin . Stat ( )
2020-04-04 03:45:39 +05:30
if err != nil {
return false
}
2020-08-25 23:24:31 +02:00
2020-09-28 12:50:00 +02:00
isPipedFromChrDev := ( stat . Mode ( ) & os . ModeCharDevice ) == 0
isPipedFromFIFO := ( stat . Mode ( ) & os . ModeNamedPipe ) != 0
2020-08-25 23:24:31 +02:00
2020-09-28 12:50:00 +02:00
return isPipedFromChrDev || isPipedFromFIFO
2020-04-04 03:45:39 +05:30
}
2020-08-29 15:26:11 +02: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" )
}
2020-08-29 23:02:45 +02:00
if ! options . TemplateList {
2020-08-29 15:26:11 +02: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 16:25:30 +02: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 15:26:11 +02:00
}
2020-08-29 16:25:30 +02:00
return nil
}
func validateProxyURL ( proxyURL , message string ) error {
if proxyURL != "" && ! isValidURL ( proxyURL ) {
return errors . New ( message )
2020-08-29 15:26:11 +02:00
}
return nil
}
2020-08-29 16:25:30 +02:00
func isValidURL ( urlString string ) bool {
_ , err := url . Parse ( urlString )
2020-08-29 15:26:11 +02: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
}
}