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
}
2020-07-13 22:01:46 +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 { }
2020-06-25 16:10:20 +00:00
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" )
flag . BoolVar ( & options . NoColor , "nC" , false , "Don't Use 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)" )
2020-10-22 10:42:16 +00:00
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" )
2020-07-15 11:38:45 +00:00
flag . BoolVar ( & options . JSONRequests , "json-requests" , false , "Write requests/responses for matches in JSON output" )
2020-07-31 16:46:23 +00:00
flag . BoolVar ( & options . EnableProgressBar , "pbar" , false , "Enable the progress bar" )
2020-08-29 13:26:11 +00:00
flag . BoolVar ( & options . TemplateList , "tl" , false , "List available templates" )
2020-11-15 23:40:32 +00:00
flag . IntVar ( & options . RateLimit , "rate-limit" , 150 , "Rate-Limit (maximum requests/second" )
2020-10-06 19:38:44 +00: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 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" )
2020-10-19 20:44:44 +00:00
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 )
}
2020-10-19 20:44:44 +00:00
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 01:18:10 +00:00
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-08-25 21:24:31 +00:00
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-08-25 21:24:31 +00:00
2020-09-28 10:50:00 +00:00
isPipedFromChrDev := ( stat . Mode ( ) & os . ModeCharDevice ) == 0
isPipedFromFIFO := ( stat . Mode ( ) & os . ModeNamedPipe ) != 0
2020-08-25 21:24:31 +00:00
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" )
}
2020-08-29 21:02:45 +00:00
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
}
}