diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go index b6ecd1e4..a90c4ed5 100644 --- a/cmd/nuclei/main.go +++ b/cmd/nuclei/main.go @@ -338,6 +338,7 @@ on extensive configurability, massive extensibility and ease of use.`) flagSet.IntVarP(&options.HeadlessTemplateThreads, "headless-concurrency", "headc", 10, "maximum number of headless templates to be executed in parallel"), flagSet.IntVarP(&options.JsConcurrency, "js-concurrency", "jsc", 120, "maximum number of javascript runtimes to be executed in parallel"), flagSet.IntVarP(&options.PayloadConcurrency, "payload-concurrency", "pc", 25, "max payload concurrency for each template"), + flagSet.IntVarP(&options.ProbeConcurrency, "probe-concurrency", "prc", 50, "http probe concurrency with httpx"), ) flagSet.CreateGroup("optimization", "Optimizations", flagSet.IntVar(&options.Timeout, "timeout", 10, "time to wait in seconds before timeout"), diff --git a/internal/runner/inputs.go b/internal/runner/inputs.go index 60aa0319..e7a7c29f 100644 --- a/internal/runner/inputs.go +++ b/internal/runner/inputs.go @@ -30,6 +30,11 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) { } gologger.Info().Msgf("Running httpx on input host") + var bulkSize = GlobalProbeBulkSize + if r.options.BulkSize > GlobalProbeBulkSize { + bulkSize = r.options.BulkSize + } + httpxOptions := httpx.DefaultOptions httpxOptions.RetryMax = r.options.Retries httpxOptions.Timeout = time.Duration(r.options.Timeout) * time.Second @@ -38,8 +43,10 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) { return nil, errors.Wrap(err, "could not create httpx client") } + shouldFollowGlobalProbeBulkSize := bulkSize == GlobalProbeBulkSize + // Probe the non-standard URLs and store them in cache - swg, err := syncutil.New(syncutil.WithSize(GlobalProbeBulkSize)) + swg, err := syncutil.New(syncutil.WithSize(bulkSize)) if err != nil { return nil, errors.Wrap(err, "could not create adaptive group") } @@ -49,7 +56,7 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) { return true } - if swg.Size != GlobalProbeBulkSize { + if shouldFollowGlobalProbeBulkSize && swg.Size != GlobalProbeBulkSize { swg.Resize(GlobalProbeBulkSize) } diff --git a/lib/config.go b/lib/config.go index fd4e9c9a..5b112f8d 100644 --- a/lib/config.go +++ b/lib/config.go @@ -116,6 +116,7 @@ type Concurrency struct { HeadlessTemplateConcurrency int // number of templates to run concurrently for headless templates (per host in host-spray mode) JavascriptTemplateConcurrency int // number of templates to run concurrently for javascript templates (per host in host-spray mode) TemplatePayloadConcurrency int // max concurrent payloads to run for a template (a good default is 25) + ProbeConcurrency int // max concurrent http probes to run (a good default is 50) } // WithConcurrency sets concurrency options @@ -152,6 +153,11 @@ func WithConcurrency(opts Concurrency) NucleiSDKOptions { } else { e.opts.PayloadConcurrency = opts.TemplatePayloadConcurrency } + if opts.ProbeConcurrency <= 0 { + return errors.New("probe concurrency must be at least 1") + } else { + e.opts.ProbeConcurrency = opts.ProbeConcurrency + } return nil } } diff --git a/pkg/types/types.go b/pkg/types/types.go index 34f3c3be..81a27316 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -385,6 +385,8 @@ type Options struct { SkipFormatValidation bool // PayloadConcurrency is the number of concurrent payloads to run per template PayloadConcurrency int + // ProbeConcurrency is the number of concurrent http probes to run with httpx + ProbeConcurrency int // Dast only runs DAST templates DAST bool }