diff --git a/v2/internal/runner/options.go b/v2/internal/runner/options.go index cd5b4bb9..53bac22b 100644 --- a/v2/internal/runner/options.go +++ b/v2/internal/runner/options.go @@ -13,6 +13,7 @@ import ( type Options struct { Debug bool // Debug mode allows debugging request/responses for the engine Templates multiStringFlag // Signature specifies the template/templates to use + ExcludedTemplates multiStringFlag // Signature specifies the template/templates to exclude 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. @@ -52,7 +53,8 @@ func ParseOptions() *Options { options := &Options{} flag.StringVar(&options.Target, "target", "", "Target is a single target to scan using template") - flag.Var(&options.Templates, "t", "Template input file/files to run on host. Can be used multiple times.") + 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.") 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.") flag.StringVar(&options.Targets, "l", "", "List of URLs to run templates on") flag.StringVar(&options.Output, "o", "", "File to write output to (optional)") diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go index 133a87fd..51545ea4 100644 --- a/v2/internal/runner/runner.go +++ b/v2/internal/runner/runner.go @@ -231,15 +231,14 @@ func (r *Runner) getParsedTemplatesFor(templatePaths []string, severities string return parsedTemplates, workflowCount } -// RunEnumeration sets up the input layer for giving input nuclei. -// binary and runs the actual enumeration -func (r *Runner) RunEnumeration() { +// getTemplatesFor parses the specified input template definitions and returns a list of unique, absolute template paths. +func (r *Runner) getTemplatesFor(definitions []string) []string { // keeps track of processed dirs and files processed := make(map[string]bool) allTemplates := []string{} // parses user input, handle file/directory cases and produce a list of unique templates - for _, t := range r.options.Templates { + for _, t := range definitions { var absPath string var err error @@ -335,6 +334,33 @@ func (r *Runner) RunEnumeration() { } } + return allTemplates +} + +// RunEnumeration sets up the input layer for giving input nuclei. +// binary and runs the actual enumeration +func (r *Runner) RunEnumeration() { + // resolves input templates definitions and any optional exclusion + includedTemplates := r.getTemplatesFor(r.options.Templates) + excludedTemplates := r.getTemplatesFor(r.options.ExcludedTemplates) + // defaults to all templates + allTemplates := includedTemplates + if len(excludedTemplates) > 0 { + excludedMap := make(map[string]struct{}, len(excludedTemplates)) + for _, excl := range excludedTemplates { + excludedMap[excl] = struct{}{} + } + // rebuild list with only non-excluded templates + allTemplates = []string{} + for _, incl := range includedTemplates { + if _, found := excludedMap[incl]; !found { + allTemplates = append(allTemplates, incl) + } else { + gologger.Warningf("Excluding '%s'", incl) + } + } + } + // pre-parse all the templates, apply filters availableTemplates, workflowCount := r.getParsedTemplatesFor(allTemplates, r.options.Severity) templateCount := len(availableTemplates)