diff --git a/.gitignore b/.gitignore index 3eed20eae..10f5c008e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ cmd/nuclei/nuclei* v2/cmd/nuclei/nuclei .idea +integration_tests/integration-test +integration_tests/nuclei +v2/cmd/integration-test/integration-test \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index 694cea254..6c88a19f1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,9 +6,9 @@ linters-settings: # funlen: # lines: 100 # statements: 50 - goconst: - min-len: 2 - min-occurrences: 2 + #goconst: + # min-len: 2 + # min-occurrences: 2 gocritic: enabled-tags: - diagnostic @@ -56,18 +56,18 @@ linters: # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint disable-all: true enable: - - bodyclose + #- bodyclose - deadcode - dogsled - errcheck - exhaustive - gochecknoinits - - goconst + #- goconst - gocritic - gofmt - goimports - golint - - gomnd + #- gomnd - goprintffuncname - gosimple - govet diff --git a/v2/cmd/integration-test/http.go b/v2/cmd/integration-test/http.go index 5cc3e813b..5e20b2c76 100644 --- a/v2/cmd/integration-test/http.go +++ b/v2/cmd/integration-test/http.go @@ -41,7 +41,7 @@ func httpDebugRequestDump(r *http.Request) { type httpGetHeaders struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpGetHeaders) Execute(filePath string) error { router := httprouter.New() router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { @@ -65,7 +65,7 @@ func (h *httpGetHeaders) Execute(filePath string) error { type httpGetQueryString struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpGetQueryString) Execute(filePath string) error { router := httprouter.New() router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { @@ -89,12 +89,12 @@ func (h *httpGetQueryString) Execute(filePath string) error { type httpGetRedirects struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpGetRedirects) Execute(filePath string) error { router := httprouter.New() router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { httpDebugRequestDump(r) - http.Redirect(w, r, "/redirected", 302) + http.Redirect(w, r, "/redirected", http.StatusFound) })) router.GET("/redirected", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { httpDebugRequestDump(r) @@ -115,7 +115,7 @@ func (h *httpGetRedirects) Execute(filePath string) error { type httpGet struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpGet) Execute(filePath string) error { router := httprouter.New() router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { @@ -137,7 +137,7 @@ func (h *httpGet) Execute(filePath string) error { type httpPostBody struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpPostBody) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -170,7 +170,7 @@ func (h *httpPostBody) Execute(filePath string) error { type httpPostJSONBody struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpPostJSONBody) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -209,7 +209,7 @@ func (h *httpPostJSONBody) Execute(filePath string) error { type httpPostMultipartBody struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpPostMultipartBody) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -252,7 +252,7 @@ func (h *httpPostMultipartBody) Execute(filePath string) error { type httpRawDynamicExtractor struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpRawDynamicExtractor) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -291,7 +291,7 @@ func (h *httpRawDynamicExtractor) Execute(filePath string) error { type httpRawGetQuery struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpRawGetQuery) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -320,7 +320,7 @@ func (h *httpRawGetQuery) Execute(filePath string) error { type httpRawGet struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpRawGet) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -348,7 +348,7 @@ func (h *httpRawGet) Execute(filePath string) error { type httpRawPayload struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpRawPayload) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -384,7 +384,7 @@ func (h *httpRawPayload) Execute(filePath string) error { type httpRawPostBody struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpRawPostBody) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -417,7 +417,7 @@ func (h *httpRawPostBody) Execute(filePath string) error { type httpRawCookieReuse struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpRawCookieReuse) Execute(filePath string) error { router := httprouter.New() var routerErr error @@ -466,14 +466,14 @@ func (h *httpRawCookieReuse) Execute(filePath string) error { type httpRawUnsafeRequest struct{} -// Executes executes a test case and returns an error if occured +// Executes executes a test case and returns an error if occurred func (h *httpRawUnsafeRequest) Execute(filePath string) error { var routerErr error ts := testutils.NewTCPServer(func(conn net.Conn) { defer conn.Close() - conn.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 40\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Thu, 25 Feb 2021 17:17:28 GMT\r\n\r\nThis is test-raw-unsafe request matcher.\r\n")) + _, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 40\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Thu, 25 Feb 2021 17:17:28 GMT\r\n\r\nThis is test-raw-unsafe request matcher.\r\n")) }) defer ts.Close() diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go index 6fb10683b..e16af2ca4 100644 --- a/v2/cmd/nuclei/main.go +++ b/v2/cmd/nuclei/main.go @@ -4,9 +4,6 @@ import ( "os" "path" - "net/http" - _ "net/http/pprof" - "github.com/projectdiscovery/goflags" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/nuclei/v2/internal/runner" @@ -20,7 +17,6 @@ var ( func main() { readConfig() - go http.ListenAndServe(":6060", http.DefaultServeMux) runner.ParseOptions(options) diff --git a/v2/go.sum b/v2/go.sum index 39d502a94..b6d852825 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -208,6 +208,7 @@ github.com/projectdiscovery/gologger v1.1.3 h1:rKWZW2QUigRV1jnlWwWJbJRvz8b+T/+bB github.com/projectdiscovery/gologger v1.1.3/go.mod h1:jdXflz3TLB8bcVNzb0v26TztI9KPz8Lr4BVdUhNUs6E= github.com/projectdiscovery/hmap v0.0.1 h1:VAONbJw5jP+syI5smhsfkrq9XPGn4aiYy5pR6KR1wog= github.com/projectdiscovery/hmap v0.0.1/go.mod h1:VDEfgzkKQdq7iGTKz8Ooul0NuYHQ8qiDs6r8bPD1Sb0= +github.com/projectdiscovery/nuclei v1.1.7 h1:5Z1fBHcjyAuuI89xcCzv8tYK7b6ucqLxs+mCC/nJjno= github.com/projectdiscovery/rawhttp v0.0.6 h1:HbgPB1eKXQVV5F9sq0Uxflm95spWFyZYD8dgFpeOC9M= github.com/projectdiscovery/rawhttp v0.0.6/go.mod h1:PQERZAhAv7yxI/hR6hdDPgK1WTU56l204BweXrBec+0= github.com/projectdiscovery/retryabledns v1.0.7 h1:fwbwrl+0XmWRvwiNzm/YSBjmUh7KwIsryScUK9juOuA= diff --git a/v2/internal/colorizer/colorizer.go b/v2/internal/colorizer/colorizer.go index 0b001b79b..43f4c8977 100644 --- a/v2/internal/colorizer/colorizer.go +++ b/v2/internal/colorizer/colorizer.go @@ -8,8 +8,7 @@ type Colorizer struct { } const ( - fgOrange uint8 = 208 - undefined string = "undefined" + fgOrange uint8 = 208 ) // New returns a new severity based colorizer diff --git a/v2/internal/runner/processor.go b/v2/internal/runner/processor.go index 50db69784..a00993b88 100644 --- a/v2/internal/runner/processor.go +++ b/v2/internal/runner/processor.go @@ -1,10 +1,6 @@ package runner import ( - "fmt" - "os" - "path" - "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/nuclei/v2/pkg/templates" "github.com/remeh/sizedwaitgroup" @@ -52,13 +48,3 @@ func (r *Runner) processWorkflowWithList(template *templates.Template) bool { wg.Wait() return results.Load() } - -// resolvePathWithBaseFolder resolves a path with the base folder -func resolvePathWithBaseFolder(baseFolder, templateName string) (string, error) { - templatePath := path.Join(baseFolder, templateName) - if _, err := os.Stat(templatePath); !os.IsNotExist(err) { - gologger.Debug().Msgf("Found template in current directory: %s\n", templatePath) - return templatePath, nil - } - return "", fmt.Errorf("no such path found: %s", templateName) -} diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go index becd659e5..762e0fa72 100644 --- a/v2/internal/runner/runner.go +++ b/v2/internal/runner/runner.go @@ -12,7 +12,7 @@ import ( "github.com/projectdiscovery/nuclei/v2/internal/collaborator" "github.com/projectdiscovery/nuclei/v2/internal/colorizer" "github.com/projectdiscovery/nuclei/v2/internal/progress" - "github.com/projectdiscovery/nuclei/v2/pkg/catalogue" + "github.com/projectdiscovery/nuclei/v2/pkg/catalog" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/projectfile" "github.com/projectdiscovery/nuclei/v2/pkg/protocols" @@ -35,7 +35,7 @@ type Runner struct { templatesConfig *nucleiConfig options *types.Options projectFile *projectfile.ProjectFile - catalogue *catalogue.Catalogue + catalog *catalog.Catalog progress *progress.Progress colorizer aurora.Aurora issuesClient *issues.Client @@ -63,7 +63,7 @@ func New(options *types.Options) (*Runner, error) { if runner.templatesConfig != nil { runner.readNucleiIgnoreFile() } - runner.catalogue = catalogue.New(runner.options.TemplatesDirectory) + runner.catalog = catalog.New(runner.options.TemplatesDirectory) if options.ReportingConfig != "" { if client, err := issues.New(options.ReportingConfig, options.ReportingDB); err != nil { @@ -147,11 +147,11 @@ func New(options *types.Options) (*Runner, error) { } // Create the output file if asked - output, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.JSON, options.Output, options.TraceLogFile) + outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.JSON, options.Output, options.TraceLogFile) if err != nil { gologger.Fatal().Msgf("Could not create output file '%s': %s\n", options.Output, err) } - runner.output = output + runner.output = outputWriter // Creates the progress tracking object var progressErr error @@ -200,8 +200,8 @@ func (r *Runner) RunEnumeration() { if len(r.options.Templates) == 0 && len(r.options.Tags) > 0 { r.options.Templates = append(r.options.Templates, r.options.TemplatesDirectory) } - includedTemplates := r.catalogue.GetTemplatesPath(r.options.Templates) - excludedTemplates := r.catalogue.GetTemplatesPath(r.options.ExcludedTemplates) + includedTemplates := r.catalog.GetTemplatesPath(r.options.Templates) + excludedTemplates := r.catalog.GetTemplatesPath(r.options.ExcludedTemplates) // defaults to all templates allTemplates := includedTemplates @@ -245,7 +245,7 @@ func (r *Runner) RunEnumeration() { Output: r.output, Options: r.options, Progress: r.progress, - Catalogue: r.catalogue, + Catalog: r.catalog, RateLimiter: r.ratelimiter, IssuesClient: r.issuesClient, Browser: r.browser, @@ -261,9 +261,7 @@ func (r *Runner) RunEnumeration() { }) clusterCount += len(cluster) } else { - for _, item := range cluster { - finalTemplates = append(finalTemplates, item) - } + finalTemplates = append(finalTemplates, cluster...) } } diff --git a/v2/internal/runner/templates.go b/v2/internal/runner/templates.go index ac1c5b142..19e75a822 100644 --- a/v2/internal/runner/templates.go +++ b/v2/internal/runner/templates.go @@ -14,13 +14,12 @@ import ( // getParsedTemplatesFor parse the specified templates and returns a slice of the parsable ones, optionally filtered // by severity, along with a flag indicating if workflows are present. -func (r *Runner) getParsedTemplatesFor(templatePaths []string, severities []string) (map[string]*templates.Template, int) { - workflowCount := 0 +func (r *Runner) getParsedTemplatesFor(templatePaths, severities []string) (parsedTemplates map[string]*templates.Template, workflowCount int) { filterBySeverity := len(severities) > 0 gologger.Info().Msgf("Loading templates...") - parsedTemplates := make(map[string]*templates.Template) + parsedTemplates = make(map[string]*templates.Template) for _, match := range templatePaths { t, err := r.parseTemplateFile(match) if err != nil { @@ -50,7 +49,7 @@ func (r *Runner) parseTemplateFile(file string) (*templates.Template, error) { Output: r.output, Options: r.options, Progress: r.progress, - Catalogue: r.catalogue, + Catalog: r.catalog, IssuesClient: r.issuesClient, RateLimiter: r.ratelimiter, ProjectFile: r.projectFile, @@ -143,20 +142,3 @@ func directoryWalker(fsPath string, callback func(fsPath string, d *godirwalk.Di return nil } - -func isFilePath(filePath string) (bool, error) { - info, err := os.Stat(filePath) - if err != nil { - return false, err - } - - return info.Mode().IsRegular(), nil -} - -func isNewPath(filePath string, pathMap map[string]bool) bool { - if _, already := pathMap[filePath]; already { - gologger.Warning().Msgf("Skipping already specified path '%s'", filePath) - return false - } - return true -} diff --git a/v2/internal/runner/update.go b/v2/internal/runner/update.go index 7b286d4d8..7e2d9195e 100644 --- a/v2/internal/runner/update.go +++ b/v2/internal/runner/update.go @@ -278,15 +278,14 @@ func (r *Runner) downloadReleaseAndUnzip(ctx context.Context, version, downloadU // If we don't find a previous file in new download and it hasn't been // changed on the disk, delete it. - if previousChecksum != nil { - for k, v := range previousChecksum { - _, ok := checksums[k] - if !ok && v[0] == v[1] { - os.Remove(k) - deletions = append(deletions, strings.TrimPrefix(strings.TrimPrefix(k, r.templatesConfig.TemplatesDirectory), "/")) - } + for k, v := range previousChecksum { + _, ok := checksums[k] + if !ok && v[0] == v[1] { + os.Remove(k) + deletions = append(deletions, strings.TrimPrefix(strings.TrimPrefix(k, r.templatesConfig.TemplatesDirectory), "/")) } } + r.printUpdateChangelog(additions, modifications, deletions, version, totalCount) return writeTemplatesChecksum(checksumFile, checksums) } @@ -342,10 +341,10 @@ func writeTemplatesChecksum(file string, checksum map[string]string) error { defer f.Close() for k, v := range checksum { - f.WriteString(k) - f.WriteString(",") - f.WriteString(v) - f.WriteString("\n") + _, _ = f.WriteString(k) + _, _ = f.WriteString(",") + _, _ = f.WriteString(v) + _, _ = f.WriteString("\n") } return nil } diff --git a/v2/internal/testutils/integration.go b/v2/internal/testutils/integration.go index 5ef7091b8..f41ec5ae5 100644 --- a/v2/internal/testutils/integration.go +++ b/v2/internal/testutils/integration.go @@ -8,10 +8,10 @@ import ( ) // RunNucleiAndGetResults returns a list of results for a template -func RunNucleiAndGetResults(template string, URL string, debug bool) ([]string, error) { - cmd := exec.Command("./nuclei", "-t", template, "-target", URL) +func RunNucleiAndGetResults(template, url string, debug bool) ([]string, error) { + cmd := exec.Command("./nuclei", "-t", template, "-target", url) if debug { - cmd = exec.Command("./nuclei", "-t", template, "-target", URL, "-debug") + cmd = exec.Command("./nuclei", "-t", template, "-target", url, "-debug") cmd.Stderr = os.Stderr } data, err := cmd.Output() @@ -30,7 +30,7 @@ func RunNucleiAndGetResults(template string, URL string, debug bool) ([]string, // TestCase is a single integration test case type TestCase interface { - // Execute executes a test case and returns any errors if occured + // Execute executes a test case and returns any errors if occurred Execute(filePath string) error } diff --git a/v2/internal/testutils/testutils.go b/v2/internal/testutils/testutils.go index 949de4cde..8569c491e 100644 --- a/v2/internal/testutils/testutils.go +++ b/v2/internal/testutils/testutils.go @@ -3,7 +3,7 @@ package testutils import ( "github.com/logrusorgru/aurora" "github.com/projectdiscovery/nuclei/v2/internal/progress" - "github.com/projectdiscovery/nuclei/v2/pkg/catalogue" + "github.com/projectdiscovery/nuclei/v2/pkg/catalog" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit" @@ -13,7 +13,7 @@ import ( // Init initializes the protocols and their configurations func Init(options *types.Options) { - protocolinit.Init(options) + _ = protocolinit.Init(options) } // DefaultOptions is the default options structure for nuclei during mocking. @@ -102,18 +102,18 @@ type TemplateInfo struct { // NewMockExecuterOptions creates a new mock executeroptions struct func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecuterOptions { - progress, _ := progress.NewProgress(0, false, false, 0) + progressImpl, _ := progress.NewProgress(0, false, false, 0) executerOpts := &protocols.ExecuterOptions{ TemplateID: info.ID, TemplateInfo: info.Info, TemplatePath: info.Path, Output: NewMockOutputWriter(), Options: options, - Progress: progress, + Progress: progressImpl, ProjectFile: nil, IssuesClient: nil, Browser: nil, - Catalogue: catalogue.New(options.TemplatesDirectory), + Catalog: catalog.New(options.TemplatesDirectory), RateLimiter: ratelimit.New(options.RateLimit), } return executerOpts diff --git a/v2/pkg/catalog/catalogue.go b/v2/pkg/catalog/catalogue.go new file mode 100644 index 000000000..cab2857ff --- /dev/null +++ b/v2/pkg/catalog/catalogue.go @@ -0,0 +1,14 @@ +package catalog + +// Catalog is a template catalog helper implementation +type Catalog struct { + ignoreFiles []string + templatesDirectory string +} + +// New creates a new Catalog structure using provided input items +func New(directory string) *Catalog { + catalog := &Catalog{templatesDirectory: directory} + catalog.readNucleiIgnoreFile() + return catalog +} diff --git a/v2/pkg/catalogue/find.go b/v2/pkg/catalog/find.go similarity index 84% rename from v2/pkg/catalogue/find.go rename to v2/pkg/catalog/find.go index 446ff430b..2575b0cb3 100644 --- a/v2/pkg/catalogue/find.go +++ b/v2/pkg/catalog/find.go @@ -1,4 +1,4 @@ -package catalogue +package catalog import ( "os" @@ -12,7 +12,7 @@ import ( ) // GetTemplatesPath returns a list of absolute paths for the provided template list. -func (c *Catalogue) GetTemplatesPath(definitions []string) []string { +func (c *Catalog) GetTemplatesPath(definitions []string) []string { // keeps track of processed dirs and files processed := make(map[string]bool) allTemplates := []string{} @@ -38,7 +38,7 @@ func (c *Catalogue) GetTemplatesPath(definitions []string) []string { // GetTemplatePath parses the specified input template path and returns a compiled // list of finished absolute paths to the templates evaluating any glob patterns // or folders provided as in. -func (c *Catalogue) GetTemplatePath(target string) ([]string, error) { +func (c *Catalog) GetTemplatePath(target string) ([]string, error) { processed := make(map[string]struct{}) absPath, err := c.convertPathToAbsolute(target) @@ -48,9 +48,9 @@ func (c *Catalogue) GetTemplatePath(target string) ([]string, error) { // Template input includes a wildcard if strings.Contains(absPath, "*") { - matches, err := c.findGlobPathMatches(absPath, processed) - if err != nil { - return nil, errors.Wrap(err, "could not find glob matches") + matches, findErr := c.findGlobPathMatches(absPath, processed) + if findErr != nil { + return nil, errors.Wrap(findErr, "could not find glob matches") } if len(matches) == 0 { return nil, errors.Errorf("no templates found for path") @@ -84,7 +84,7 @@ func (c *Catalogue) GetTemplatePath(target string) ([]string, error) { // convertPathToAbsolute resolves the paths provided to absolute paths // before doing any operations on them regardless of them being blob, folders, files, etc. -func (c *Catalogue) convertPathToAbsolute(t string) (string, error) { +func (c *Catalog) convertPathToAbsolute(t string) (string, error) { if strings.Contains(t, "*") { file := path.Base(t) absPath, err := c.ResolvePath(path.Dir(t), "") @@ -97,7 +97,7 @@ func (c *Catalogue) convertPathToAbsolute(t string) (string, error) { } // findGlobPathMatches returns the matched files from a glob path -func (c *Catalogue) findGlobPathMatches(absPath string, processed map[string]struct{}) ([]string, error) { +func (c *Catalog) findGlobPathMatches(absPath string, processed map[string]struct{}) ([]string, error) { matches, err := filepath.Glob(absPath) if err != nil { return nil, errors.Errorf("wildcard found, but unable to glob: %s\n", err) @@ -114,7 +114,7 @@ func (c *Catalogue) findGlobPathMatches(absPath string, processed map[string]str // findFileMatches finds if a path is an absolute file. If the path // is a file, it returns true otherwise false with no errors. -func (c *Catalogue) findFileMatches(absPath string, processed map[string]struct{}) (string, bool, error) { +func (c *Catalog) findFileMatches(absPath string, processed map[string]struct{}) (match string, matched bool, err error) { info, err := os.Stat(absPath) if err != nil { return "", false, err @@ -130,7 +130,7 @@ func (c *Catalogue) findFileMatches(absPath string, processed map[string]struct{ } // findDirectoryMatches finds matches for templates from a directory -func (c *Catalogue) findDirectoryMatches(absPath string, processed map[string]struct{}) ([]string, error) { +func (c *Catalog) findDirectoryMatches(absPath string, processed map[string]struct{}) ([]string, error) { var results []string err := godirwalk.Walk(absPath, &godirwalk.Options{ Unsorted: true, diff --git a/v2/pkg/catalogue/ignore.go b/v2/pkg/catalog/ignore.go similarity index 88% rename from v2/pkg/catalogue/ignore.go rename to v2/pkg/catalog/ignore.go index 4110f3c82..fcc2c25bb 100644 --- a/v2/pkg/catalogue/ignore.go +++ b/v2/pkg/catalog/ignore.go @@ -1,4 +1,4 @@ -package catalogue +package catalog import ( "bufio" @@ -12,7 +12,7 @@ import ( const nucleiIgnoreFile = ".nuclei-ignore" // readNucleiIgnoreFile reads the nuclei ignore file marking it in map -func (c *Catalogue) readNucleiIgnoreFile() { +func (c *Catalog) readNucleiIgnoreFile() { file, err := os.Open(path.Join(c.templatesDirectory, nucleiIgnoreFile)) if err != nil { return @@ -33,7 +33,7 @@ func (c *Catalogue) readNucleiIgnoreFile() { } // checkIfInNucleiIgnore checks if a path falls under nuclei-ignore rules. -func (c *Catalogue) checkIfInNucleiIgnore(item string) bool { +func (c *Catalog) checkIfInNucleiIgnore(item string) bool { if c.templatesDirectory == "" { return false } @@ -54,7 +54,7 @@ func (c *Catalogue) checkIfInNucleiIgnore(item string) bool { } // ignoreFilesWithExcludes ignores results with exclude paths -func (c *Catalogue) ignoreFilesWithExcludes(results, excluded []string) []string { +func (c *Catalog) ignoreFilesWithExcludes(results, excluded []string) []string { var templates []string for _, result := range results { diff --git a/v2/pkg/catalogue/ignore_test.go b/v2/pkg/catalog/ignore_test.go similarity index 95% rename from v2/pkg/catalogue/ignore_test.go rename to v2/pkg/catalog/ignore_test.go index 136a95c7c..667a2608f 100644 --- a/v2/pkg/catalogue/ignore_test.go +++ b/v2/pkg/catalog/ignore_test.go @@ -1,4 +1,4 @@ -package catalogue +package catalog import ( "testing" @@ -7,7 +7,7 @@ import ( ) func TestIgnoreFilesIgnore(t *testing.T) { - c := &Catalogue{ + c := &Catalog{ ignoreFiles: []string{"workflows/", "cves/2020/cve-2020-5432.yaml"}, templatesDirectory: "test", } @@ -30,7 +30,7 @@ func TestIgnoreFilesIgnore(t *testing.T) { } func TestExcludeFilesIgnore(t *testing.T) { - c := &Catalogue{} + c := &Catalog{} excludes := []string{"workflows/", "cves/2020/cve-2020-5432.yaml"} paths := []string{"/Users/test/nuclei-templates/workflows/", "/Users/test/nuclei-templates/cves/2020/cve-2020-5432.yaml", "/Users/test/nuclei-templates/workflows/test-workflow.yaml", "/Users/test/nuclei-templates/cves/"} diff --git a/v2/pkg/catalogue/path.go b/v2/pkg/catalog/path.go similarity index 92% rename from v2/pkg/catalogue/path.go rename to v2/pkg/catalog/path.go index 2ff00d0e7..d3391fe9b 100644 --- a/v2/pkg/catalogue/path.go +++ b/v2/pkg/catalog/path.go @@ -1,4 +1,4 @@ -package catalogue +package catalog import ( "fmt" @@ -13,7 +13,7 @@ import ( // It checks if the filename is an absolute path, looks in the current directory // or checking the nuclei templates directory. If a second path is given, // it also tries to find paths relative to that second path. -func (c *Catalogue) ResolvePath(templateName, second string) (string, error) { +func (c *Catalog) ResolvePath(templateName, second string) (string, error) { if strings.HasPrefix(templateName, "/") || strings.Contains(templateName, ":\\") { return templateName, nil } diff --git a/v2/pkg/catalogue/catalogue.go b/v2/pkg/catalogue/catalogue.go deleted file mode 100644 index eaba68593..000000000 --- a/v2/pkg/catalogue/catalogue.go +++ /dev/null @@ -1,14 +0,0 @@ -package catalogue - -// Catalogue is a template catalouge helper implementation -type Catalogue struct { - ignoreFiles []string - templatesDirectory string -} - -// New creates a new catalogue structure using provided input items -func New(directory string) *Catalogue { - catalogue := &Catalogue{templatesDirectory: directory} - catalogue.readNucleiIgnoreFile() - return catalogue -} diff --git a/v2/pkg/operators/matchers/compile.go b/v2/pkg/operators/matchers/compile.go index 4d3fcdfcc..dede36652 100644 --- a/v2/pkg/operators/matchers/compile.go +++ b/v2/pkg/operators/matchers/compile.go @@ -14,8 +14,7 @@ func (m *Matcher) CompileMatchers() error { var ok bool // Support hexadecimal encoding for matchers too. - switch m.Encoding { - case "hex": + if m.Encoding == "hex" { for i, word := range m.Words { if decoded, err := hex.DecodeString(word); err == nil && len(decoded) > 0 { m.Words[i] = string(decoded) diff --git a/v2/pkg/output/format_screen.go b/v2/pkg/output/format_screen.go index 55781fd66..86d9cb3d2 100644 --- a/v2/pkg/output/format_screen.go +++ b/v2/pkg/output/format_screen.go @@ -7,7 +7,7 @@ import ( ) // formatScreen formats the output for showing on screen. -func (w *StandardWriter) formatScreen(output *ResultEvent) ([]byte, error) { +func (w *StandardWriter) formatScreen(output *ResultEvent) []byte { builder := &bytes.Buffer{} if !w.noMetadata { @@ -63,5 +63,5 @@ func (w *StandardWriter) formatScreen(output *ResultEvent) ([]byte, error) { } builder.WriteString("]") } - return builder.Bytes(), nil + return builder.Bytes() } diff --git a/v2/pkg/output/output.go b/v2/pkg/output/output.go index fe9979ce9..b877e8ba7 100644 --- a/v2/pkg/output/output.go +++ b/v2/pkg/output/output.go @@ -120,7 +120,7 @@ func (w *StandardWriter) Write(event *ResultEvent) error { if w.json { data, err = w.formatJSON(event) } else { - data, err = w.formatScreen(event) + data = w.formatScreen(event) } if err != nil { return errors.Wrap(err, "could not format output") diff --git a/v2/pkg/protocols/common/clusterer/clusterer_test.go b/v2/pkg/protocols/common/clusterer/clusterer_test.go index dd006c19e..6f69ec7be 100644 --- a/v2/pkg/protocols/common/clusterer/clusterer_test.go +++ b/v2/pkg/protocols/common/clusterer/clusterer_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/logrusorgru/aurora" - "github.com/projectdiscovery/nuclei/v2/pkg/catalogue" + "github.com/projectdiscovery/nuclei/v2/pkg/catalog" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit" @@ -16,18 +16,18 @@ import ( ) func TestHTTPRequestsCluster(t *testing.T) { - catalogue := catalogue.New("/Users/ice3man/nuclei-templates") - templatesList, err := catalogue.GetTemplatePath("/Users/ice3man/nuclei-templates") + catalogImpl := catalog.New("/Users/ice3man/nuclei-templates") + templatesList, err := catalogImpl.GetTemplatePath("/Users/ice3man/nuclei-templates") require.Nil(t, err, "could not get templates") - protocolinit.Init(&types.Options{}) + _ = protocolinit.Init(&types.Options{}) list := make(map[string]*templates.Template) for _, template := range templatesList { executerOpts := protocols.ExecuterOptions{ Output: &mockOutput{}, Options: &types.Options{}, Progress: nil, - Catalogue: catalogue, + Catalog: catalogImpl, RateLimiter: nil, IssuesClient: nil, ProjectFile: nil, @@ -45,8 +45,8 @@ func TestHTTPRequestsCluster(t *testing.T) { totalClusterCount := 0 totalRequestsSentNew := 0 - new := Cluster(list) - for i, cluster := range new { + newRequests := Cluster(list) + for i, cluster := range newRequests { if len(cluster) == 1 { continue } diff --git a/v2/pkg/protocols/common/clusterer/executer.go b/v2/pkg/protocols/common/clusterer/executer.go index 2ba2ccde0..84207ab11 100644 --- a/v2/pkg/protocols/common/clusterer/executer.go +++ b/v2/pkg/protocols/common/clusterer/executer.go @@ -76,7 +76,7 @@ func (e *Executer) Execute(input string) (bool, error) { gologger.Warning().Msgf("Could not create issue on tracker: %s", err) } } - e.options.Output.Write(r) + _ = e.options.Output.Write(r) e.options.Progress.IncrementMatched() } } diff --git a/v2/pkg/protocols/common/executer/executer.go b/v2/pkg/protocols/common/executer/executer.go index caf52ffa2..5e37d2bdb 100644 --- a/v2/pkg/protocols/common/executer/executer.go +++ b/v2/pkg/protocols/common/executer/executer.go @@ -48,6 +48,8 @@ func (e *Executer) Execute(input string) (bool, error) { dynamicValues := make(map[string]interface{}) previous := make(map[string]interface{}) for _, req := range e.requests { + req := req + err := req.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) { ID := req.GetID() if ID != "" { @@ -70,7 +72,7 @@ func (e *Executer) Execute(input string) (bool, error) { } } results = true - e.options.Output.Write(result) + _ = e.options.Output.Write(result) e.options.Progress.IncrementMatched() } }) @@ -87,6 +89,8 @@ func (e *Executer) ExecuteWithResults(input string, callback protocols.OutputEve previous := make(map[string]interface{}) for _, req := range e.requests { + req := req + err := req.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) { ID := req.GetID() if ID != "" { diff --git a/v2/pkg/protocols/common/generators/generators.go b/v2/pkg/protocols/common/generators/generators.go index e3e4b5f9d..b1f721f3a 100644 --- a/v2/pkg/protocols/common/generators/generators.go +++ b/v2/pkg/protocols/common/generators/generators.go @@ -32,7 +32,7 @@ var StringToType = map[string]Type{ } // New creates a new generator structure for payload generation -func New(payloads map[string]interface{}, Type Type, templatePath string) (*Generator, error) { +func New(payloads map[string]interface{}, payloadType Type, templatePath string) (*Generator, error) { generator := &Generator{} if err := generator.validate(payloads, templatePath); err != nil { return nil, err @@ -42,11 +42,11 @@ func New(payloads map[string]interface{}, Type Type, templatePath string) (*Gene if err != nil { return nil, err } - generator.Type = Type + generator.Type = payloadType generator.payloads = compiled // Validate the payload types - if Type == PitchFork { + if payloadType == PitchFork { var totalLength int for v := range compiled { if totalLength != 0 && totalLength != len(v) { @@ -110,7 +110,7 @@ func (i *Iterator) Total() int { case ClusterBomb: count = 1 for _, p := range i.payloads { - count = count * len(p.values) + count *= len(p.values) } } return count diff --git a/v2/pkg/protocols/common/replacer/replacer.go b/v2/pkg/protocols/common/replacer/replacer.go index 34dc70189..be83c6f83 100644 --- a/v2/pkg/protocols/common/replacer/replacer.go +++ b/v2/pkg/protocols/common/replacer/replacer.go @@ -13,7 +13,7 @@ const ( // Replace replaces placeholders in template with values on the fly. func Replace(template string, values map[string]interface{}) string { - new := fasttemplate.ExecuteStringStd(template, MarkerGeneral, MarkerGeneral, values) - final := fasttemplate.ExecuteStringStd(new, MarkerParenthesisOpen, MarkerParenthesisClose, values) + newResult := fasttemplate.ExecuteStringStd(template, MarkerGeneral, MarkerGeneral, values) + final := fasttemplate.ExecuteStringStd(newResult, MarkerParenthesisOpen, MarkerParenthesisClose, values) return final } diff --git a/v2/pkg/protocols/dns/dns.go b/v2/pkg/protocols/dns/dns.go index 20b35d460..5fdf49cc5 100644 --- a/v2/pkg/protocols/dns/dns.go +++ b/v2/pkg/protocols/dns/dns.go @@ -15,10 +15,11 @@ import ( // Request contains a DNS protocol request to be made from a template type Request struct { + // Operators for the current request go here. + operators.Operators `yaml:",inline"` + ID string `yaml:"id"` - // Recursion specifies whether to recurse all the answers. - Recursion bool `yaml:"recursion"` // Path contains the path/s for the request Name string `yaml:"name"` // Type is the type of DNS request to make @@ -28,15 +29,16 @@ type Request struct { // Retries is the number of retries for the DNS request Retries int `yaml:"retries"` - // Operators for the current request go here. - operators.Operators `yaml:",inline"` - CompiledOperators *operators.Operators + CompiledOperators *operators.Operators + dnsClient *retryabledns.Client + options *protocols.ExecuterOptions // cache any variables that may be needed for operation. - class uint16 - question uint16 - dnsClient *retryabledns.Client - options *protocols.ExecuterOptions + class uint16 + question uint16 + + // Recursion specifies whether to recurse all the answers. + Recursion bool `yaml:"recursion"` } // GetID returns the unique ID of the request if any. @@ -97,11 +99,11 @@ func (r *Request) Make(domain string) (*dns.Msg, error) { } // questionTypeToInt converts DNS question type to internal representation -func questionTypeToInt(Type string) uint16 { - Type = strings.TrimSpace(strings.ToUpper(Type)) +func questionTypeToInt(questionType string) uint16 { + questionType = strings.TrimSpace(strings.ToUpper(questionType)) question := dns.TypeA - switch Type { + switch questionType { case "A": question = dns.TypeA case "NS": @@ -119,7 +121,7 @@ func questionTypeToInt(Type string) uint16 { case "AAAA": question = dns.TypeAAAA } - return uint16(question) + return question } // classToInt converts a dns class name to it's internal representation diff --git a/v2/pkg/protocols/dns/dns_test.go b/v2/pkg/protocols/dns/dns_test.go index d5bf7ce55..38d262cf6 100644 --- a/v2/pkg/protocols/dns/dns_test.go +++ b/v2/pkg/protocols/dns/dns_test.go @@ -11,7 +11,7 @@ func TestDNSCompileMake(t *testing.T) { options := testutils.DefaultOptions testutils.Init(options) - templateID := "testing-dns" + const templateID = "testing-dns" request := &Request{ Type: "A", Class: "INET", diff --git a/v2/pkg/protocols/file/file.go b/v2/pkg/protocols/file/file.go index 103014a29..43b811d91 100644 --- a/v2/pkg/protocols/file/file.go +++ b/v2/pkg/protocols/file/file.go @@ -8,28 +8,30 @@ import ( // Request contains a File matching mechanism for local disk operations. type Request struct { - ID string `yaml:"id"` - - // MaxSize is the maximum size of the file to run request on. - // By default, nuclei will process 5MB files and not go more than that. - // It can be set to much lower or higher depending on use. - MaxSize int `yaml:"max-size"` - // NoRecursive specifies whether to not do recursive checks if folders are provided. - NoRecursive bool `yaml:"no-recursive"` + // Operators for the current request go here. + operators.Operators `yaml:",inline"` // Extensions is the list of extensions to perform matching on. Extensions []string `yaml:"extensions"` // ExtensionDenylist is the list of file extensions to deny during matching. ExtensionDenylist []string `yaml:"denylist"` - // Operators for the current request go here. - operators.Operators `yaml:",inline"` - CompiledOperators *operators.Operators + ID string `yaml:"id"` + + // MaxSize is the maximum size of the file to run request on. + // By default, nuclei will process 5MB files and not go more than that. + // It can be set to much lower or higher depending on use. + MaxSize int `yaml:"max-size"` + CompiledOperators *operators.Operators // cache any variables that may be needed for operation. options *protocols.ExecuterOptions extensions map[string]struct{} - allExtensions bool extensionDenylist map[string]struct{} + + // NoRecursive specifies whether to not do recursive checks if folders are provided. + NoRecursive bool `yaml:"no-recursive"` + + allExtensions bool } // defaultDenylist is the default list of extensions to be denied diff --git a/v2/pkg/protocols/file/operators.go b/v2/pkg/protocols/file/operators.go index e1c854f65..0adf6a0f0 100644 --- a/v2/pkg/protocols/file/operators.go +++ b/v2/pkg/protocols/file/operators.go @@ -62,7 +62,7 @@ func (r *Request) Extract(data map[string]interface{}, extractor *extractors.Ext } // responseToDSLMap converts a DNS response to a map for use in DSL matching -func (r *Request) responseToDSLMap(raw string, host, matched string) output.InternalEvent { +func (r *Request) responseToDSLMap(raw, host, matched string) output.InternalEvent { data := make(output.InternalEvent, 5) // Some data regarding the request metadata diff --git a/v2/pkg/protocols/headless/engine/engine.go b/v2/pkg/protocols/headless/engine/engine.go index 926bda45b..646273fdf 100644 --- a/v2/pkg/protocols/headless/engine/engine.go +++ b/v2/pkg/protocols/headless/engine/engine.go @@ -31,7 +31,7 @@ func New(options *types.Options) (*Browser, error) { if err != nil { return nil, errors.Wrap(err, "could not create temporary directory") } - launcher := launcher.New(). + chromeLauncher := launcher.New(). Leakless(false). Set("disable-gpu", "true"). Set("ignore-certificate-errors", "true"). @@ -47,21 +47,21 @@ func New(options *types.Options) (*Browser, error) { UserDataDir(dataStore) if options.ShowBrowser { - launcher = launcher.Headless(false) + chromeLauncher = chromeLauncher.Headless(false) } else { - launcher = launcher.Headless(true) + chromeLauncher = chromeLauncher.Headless(true) } if options.ProxyURL != "" { - launcher = launcher.Proxy(options.ProxyURL) + chromeLauncher = chromeLauncher.Proxy(options.ProxyURL) } - launcherURL, err := launcher.Launch() + launcherURL, err := chromeLauncher.Launch() if err != nil { return nil, err } browser := rod.New().ControlURL(launcherURL) - if err := browser.Connect(); err != nil { - return nil, err + if browserErr := browser.Connect(); browserErr != nil { + return nil, browserErr } customAgent := "" for _, option := range options.CustomHeaders { @@ -101,8 +101,8 @@ func (b *Browser) Close() { // killChromeProcesses any and all new chrome processes started after // headless process launch. func (b *Browser) killChromeProcesses() { - new := b.findChromeProcesses() - for id := range new { + newProcesses := b.findChromeProcesses() + for id := range newProcesses { if _, ok := b.previouspids[id]; ok { continue } diff --git a/v2/pkg/protocols/headless/engine/page.go b/v2/pkg/protocols/headless/engine/page.go index 381420eff..25e49807c 100644 --- a/v2/pkg/protocols/headless/engine/page.go +++ b/v2/pkg/protocols/headless/engine/page.go @@ -22,15 +22,15 @@ func (i *Instance) Run(baseURL *url.URL, actions []*Action) (map[string]string, return nil, nil, err } if i.browser.customAgent != "" { - if err := page.SetUserAgent(&proto.NetworkSetUserAgentOverride{UserAgent: i.browser.customAgent}); err != nil { - return nil, nil, err + if userAgentErr := page.SetUserAgent(&proto.NetworkSetUserAgentOverride{UserAgent: i.browser.customAgent}); userAgentErr != nil { + return nil, nil, userAgentErr } } createdPage := &Page{page: page, instance: i} router := page.HijackRequests() - if err := router.Add("*", "", createdPage.routingRuleHandler); err != nil { - return nil, nil, err + if routerErr := router.Add("*", "", createdPage.routingRuleHandler); routerErr != nil { + return nil, nil, routerErr } createdPage.router = router @@ -57,7 +57,7 @@ func (i *Instance) Run(baseURL *url.URL, actions []*Action) (map[string]string, // Close closes a browser page func (p *Page) Close() { - p.router.Stop() + _ = p.router.Stop() p.page.Close() } diff --git a/v2/pkg/protocols/headless/engine/page_actions.go b/v2/pkg/protocols/headless/engine/page_actions.go index 76038540f..215cdce8b 100644 --- a/v2/pkg/protocols/headless/engine/page_actions.go +++ b/v2/pkg/protocols/headless/engine/page_actions.go @@ -67,7 +67,7 @@ func (p *Page) ExecuteActions(baseURL *url.URL, actions []*Action) (map[string]s continue } if err != nil { - return nil, errors.Wrap(err, "error occured executing action") + return nil, errors.Wrap(err, "error occurred executing action") } } return outData, nil @@ -158,20 +158,20 @@ func (p *Page) ActionSetMethod(act *Action, out map[string]string) error { // NavigateURL executes an ActionLoadURL actions loading a URL for the page. func (p *Page) NavigateURL(action *Action, out map[string]string, parsed *url.URL) error { - url := action.GetArg("url") - if url == "" { + URL := action.GetArg("url") + if URL == "" { return errors.New("invalid arguments provided") } - // Handle the dynamic value substituion here. - url, parsed = baseURLWithTemplatePrefs(url, parsed) + // Handle the dynamic value substitution here. + URL, parsed = baseURLWithTemplatePrefs(URL, parsed) values := map[string]interface{}{"Hostname": parsed.Hostname()} - if strings.HasSuffix(parsed.Path, "/") && strings.Contains(url, "{{BaseURL}}/") { + if strings.HasSuffix(parsed.Path, "/") && strings.Contains(URL, "{{BaseURL}}/") { parsed.Path = strings.TrimSuffix(parsed.Path, "/") } parsedString := parsed.String() values["BaseURL"] = parsedString - final := fasttemplate.ExecuteStringStd(url, "{{", "}}", values) + final := fasttemplate.ExecuteStringStd(URL, "{{", "}}", values) err := p.page.Navigate(final) if err != nil { return errors.Wrap(err, "could not navigate") @@ -476,8 +476,6 @@ func selectorBy(selector string) rod.SelectorType { return rod.SelectorTypeCSSSector case "regex": return rod.SelectorTypeRegex - case "text": - fallthrough default: return rod.SelectorTypeText } diff --git a/v2/pkg/protocols/headless/engine/rules.go b/v2/pkg/protocols/headless/engine/rules.go index 5504fa183..a254902eb 100644 --- a/v2/pkg/protocols/headless/engine/rules.go +++ b/v2/pkg/protocols/headless/engine/rules.go @@ -27,7 +27,7 @@ func (p *Page) routingRuleHandler(ctx *rod.Hijack) { ctx.Request.SetBody(body) } } - ctx.LoadResponse(p.instance.browser.httpclient, true) + _ = ctx.LoadResponse(p.instance.browser.httpclient, true) for _, rule := range p.rules { if rule.Part != "response" { diff --git a/v2/pkg/protocols/headless/operators.go b/v2/pkg/protocols/headless/operators.go index 1d7ebb041..f1845a89e 100644 --- a/v2/pkg/protocols/headless/operators.go +++ b/v2/pkg/protocols/headless/operators.go @@ -62,7 +62,7 @@ func (r *Request) Extract(data map[string]interface{}, extractor *extractors.Ext } // responseToDSLMap converts a DNS response to a map for use in DSL matching -func (r *Request) responseToDSLMap(resp, req string, host, matched string) output.InternalEvent { +func (r *Request) responseToDSLMap(resp, req, host, matched string) output.InternalEvent { data := make(output.InternalEvent, 5) // Some data regarding the request metadata diff --git a/v2/pkg/protocols/http/build_request.go b/v2/pkg/protocols/http/build_request.go index dfb4f7177..0bdcabcaf 100644 --- a/v2/pkg/protocols/http/build_request.go +++ b/v2/pkg/protocols/http/build_request.go @@ -51,7 +51,7 @@ func (r *requestGenerator) Make(baseURL string, dynamicValues map[string]interfa data, parsed = baseURLWithTemplatePrefs(data, parsed) values := generators.MergeMaps(dynamicValues, map[string]interface{}{ - "Hostname": parsed.Hostname(), + "Hostname": parsed.Host, }) isRawRequest := len(r.request.Raw) > 0 diff --git a/v2/pkg/protocols/http/http.go b/v2/pkg/protocols/http/http.go index 53916f777..648d3e9b1 100644 --- a/v2/pkg/protocols/http/http.go +++ b/v2/pkg/protocols/http/http.go @@ -116,8 +116,8 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error { } if len(r.Matchers) > 0 || len(r.Extractors) > 0 { compiled := &r.Operators - if err := compiled.Compile(); err != nil { - return errors.Wrap(err, "could not compile operators") + if compileErr := compiled.Compile(); compileErr != nil { + return errors.Wrap(compileErr, "could not compile operators") } r.CompiledOperators = compiled } @@ -131,16 +131,15 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error { // Resolve payload paths if they are files. for name, payload := range r.Payloads { - switch pt := payload.(type) { - case string: - final, err := options.Catalogue.ResolvePath(pt, options.TemplatePath) - if err != nil { - return errors.Wrap(err, "could not read payload file") + payloadStr, ok := payload.(string) + if ok { + final, resolveErr := options.Catalog.ResolvePath(payloadStr, options.TemplatePath) + if resolveErr != nil { + return errors.Wrap(resolveErr, "could not read payload file") } r.Payloads[name] = final } } - r.generator, err = generators.New(r.Payloads, r.attackType, r.options.TemplatePath) if err != nil { return errors.Wrap(err, "could not parse payloads") @@ -160,7 +159,7 @@ func (r *Request) Requests() int { if len(r.Raw) > 0 { requests := len(r.Raw) if requests == 1 && r.RaceNumberRequests != 0 { - requests = requests * r.RaceNumberRequests + requests *= r.RaceNumberRequests } return requests } diff --git a/v2/pkg/protocols/http/httpclientpool/clientpool.go b/v2/pkg/protocols/http/httpclientpool/clientpool.go index df27e88c2..e25d6e026 100644 --- a/v2/pkg/protocols/http/httpclientpool/clientpool.go +++ b/v2/pkg/protocols/http/httpclientpool/clientpool.go @@ -49,12 +49,12 @@ func Init(options *types.Options) error { // Configuration contains the custom configuration options for a client type Configuration struct { - // CookieReuse enables cookie reuse for the http client (cookiejar impl) - CookieReuse bool // Threads contains the threads for the client Threads int // MaxRedirects is the maximum number of redirects to follow MaxRedirects int + // CookieReuse enables cookie reuse for the http client (cookiejar impl) + CookieReuse bool // FollowRedirects specifies whether to follow redirects FollowRedirects bool } @@ -161,17 +161,17 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl if options.ProxySocksURL != "" { var proxyAuth *proxy.Auth - socksURL, err := url.Parse(options.ProxySocksURL) - if err == nil { + socksURL, proxyErr := url.Parse(options.ProxySocksURL) + if proxyErr == nil { proxyAuth = &proxy.Auth{} proxyAuth.User = socksURL.User.Username() proxyAuth.Password, _ = socksURL.User.Password() } - dialer, err := proxy.SOCKS5("tcp", fmt.Sprintf("%s:%s", socksURL.Hostname(), socksURL.Port()), proxyAuth, proxy.Direct) + dialer, proxyErr := proxy.SOCKS5("tcp", fmt.Sprintf("%s:%s", socksURL.Hostname(), socksURL.Port()), proxyAuth, proxy.Direct) dc := dialer.(interface { DialContext(ctx context.Context, network, addr string) (net.Conn, error) }) - if err == nil { + if proxyErr == nil { transport.DialContext = dc.DialContext } } diff --git a/v2/pkg/protocols/http/operators.go b/v2/pkg/protocols/http/operators.go index 5f74a0ffa..0b05b895b 100644 --- a/v2/pkg/protocols/http/operators.go +++ b/v2/pkg/protocols/http/operators.go @@ -94,7 +94,7 @@ func (r *Request) responseToDSLMap(resp *http.Response, host, matched, rawReq, r data[strings.ToLower(cookie.Name)] = cookie.Value } for k, v := range resp.Header { - k = strings.ToLower(strings.Replace(strings.TrimSpace(k), "-", "_", -1)) + k = strings.ToLower(strings.ReplaceAll(strings.TrimSpace(k), "-", "_")) data[k] = strings.Join(v, " ") } data["all_headers"] = headers diff --git a/v2/pkg/protocols/http/raw/raw.go b/v2/pkg/protocols/http/raw/raw.go index 8030925f8..79f88457a 100644 --- a/v2/pkg/protocols/http/raw/raw.go +++ b/v2/pkg/protocols/http/raw/raw.go @@ -41,7 +41,6 @@ func Parse(request, baseURL string, unsafe bool) (*Request, error) { } parts := strings.Split(s, " ") - //nolint:gomnd // this is not a magic number if len(parts) < 3 && !unsafe { return nil, fmt.Errorf("malformed request supplied") } diff --git a/v2/pkg/protocols/http/request.go b/v2/pkg/protocols/http/request.go index f4201fb0f..aef544ad2 100644 --- a/v2/pkg/protocols/http/request.go +++ b/v2/pkg/protocols/http/request.go @@ -26,7 +26,7 @@ import ( const defaultMaxWorkers = 150 // executeRaceRequest executes race condition request for a URL -func (r *Request) executeRaceRequest(reqURL string, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error { +func (r *Request) executeRaceRequest(reqURL string, previous output.InternalEvent, callback protocols.OutputEventCallback) error { generator := r.newGenerator() maxWorkers := r.RaceNumberRequests @@ -42,7 +42,7 @@ func (r *Request) executeRaceRequest(reqURL string, dynamicValues, previous outp for i := 0; i < r.RaceNumberRequests; i++ { swg.Add() go func(httpRequest *generatedRequest) { - err := r.executeRequest(reqURL, httpRequest, dynamicValues, previous, callback) + err := r.executeRequest(reqURL, httpRequest, previous, callback) mutex.Lock() if err != nil { requestErr = multierr.Append(requestErr, err) @@ -79,7 +79,7 @@ func (r *Request) executeParallelHTTP(reqURL string, dynamicValues, previous out defer swg.Done() r.options.RateLimiter.Take() - err := r.executeRequest(reqURL, httpRequest, dynamicValues, previous, callback) + err := r.executeRequest(reqURL, httpRequest, previous, callback) mutex.Lock() if err != nil { requestErr = multierr.Append(requestErr, err) @@ -138,7 +138,7 @@ func (r *Request) executeTurboHTTP(reqURL string, dynamicValues, previous output go func(httpRequest *generatedRequest) { defer swg.Done() - err := r.executeRequest(reqURL, httpRequest, dynamicValues, previous, callback) + err := r.executeRequest(reqURL, httpRequest, previous, callback) mutex.Lock() if err != nil { requestErr = multierr.Append(requestErr, err) @@ -160,7 +160,7 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp // verify if a basic race condition was requested if r.Race && r.RaceNumberRequests > 0 { - return r.executeRaceRequest(reqURL, dynamicValues, previous, callback) + return r.executeRaceRequest(reqURL, previous, callback) } // verify if parallel elaboration was requested @@ -183,7 +183,7 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp var gotOutput bool r.options.RateLimiter.Take() - err = r.executeRequest(reqURL, request, dynamicValues, previous, func(event *output.InternalWrappedEvent) { + err = r.executeRequest(reqURL, request, previous, func(event *output.InternalWrappedEvent) { // Add the extracts to the dynamic values if any. if event.OperatorsResult != nil { gotOutput = true @@ -206,8 +206,8 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp const drainReqSize = int64(8 * 1024) -// executeRequest executes the actual generated request and returns error if occured -func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynamicvalues, previous output.InternalEvent, callback protocols.OutputEventCallback) error { +// executeRequest executes the actual generated request and returns error if occurred +func (r *Request) executeRequest(reqURL string, request *generatedRequest, previous output.InternalEvent, callback protocols.OutputEventCallback) error { r.setCustomHeaders(request) var ( @@ -235,27 +235,26 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam timeStart := time.Now() if request.original.Pipeline { formedURL = request.rawRequest.FullURL - if parsed, err := url.Parse(formedURL); err == nil { - hostname = parsed.Hostname() + if parsed, parseErr := url.Parse(formedURL); parseErr == nil { + hostname = parsed.Host } resp, err = request.pipelinedClient.DoRaw(request.rawRequest.Method, reqURL, request.rawRequest.Path, generators.ExpandMapValues(request.rawRequest.Headers), ioutil.NopCloser(strings.NewReader(request.rawRequest.Data))) } else if request.original.Unsafe && request.rawRequest != nil { formedURL = request.rawRequest.FullURL - if parsed, err := url.Parse(formedURL); err == nil { - hostname = parsed.Hostname() + if parsed, parseErr := url.Parse(formedURL); parseErr == nil { + hostname = parsed.Host } options := request.original.rawhttpClient.Options options.FollowRedirects = r.Redirects - options.CustomRawBytes = []byte(request.rawRequest.UnsafeRawBytes) + options.CustomRawBytes = request.rawRequest.UnsafeRawBytes resp, err = request.original.rawhttpClient.DoRawWithOptions(request.rawRequest.Method, reqURL, request.rawRequest.Path, generators.ExpandMapValues(request.rawRequest.Headers), ioutil.NopCloser(strings.NewReader(request.rawRequest.Data)), options) } else { - hostname = request.request.URL.Hostname() + hostname = request.request.URL.Host formedURL = request.request.URL.String() // if nuclei-project is available check if the request was already sent previously if r.options.ProjectFile != nil { // if unavailable fail silently fromcache = true - // nolint:bodyclose // false positive the response is generated at runtime resp, err = r.options.ProjectFile.Get(dumpedRequest) if err != nil { fromcache = false @@ -278,6 +277,10 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam r.options.Progress.DecrementRequests(1) return err } + defer func() { + _, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize) + resp.Body.Close() + }() gologger.Verbose().Msgf("[%s] Sent HTTP request to %s", r.options.TemplateID, formedURL) r.options.Output.Request(r.options.TemplateID, reqURL, "http", err) @@ -286,8 +289,6 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam dumpedResponseHeaders, err := httputil.DumpResponse(resp, false) if err != nil { - _, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize) - resp.Body.Close() return errors.Wrap(err, "could not dump http response") } @@ -299,8 +300,6 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam } data, err := ioutil.ReadAll(bodyReader) if err != nil { - _, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize) - resp.Body.Close() return errors.Wrap(err, "could not read http body") } resp.Body.Close() @@ -364,8 +363,6 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam return nil } -const two = 2 - // setCustomHeaders sets the custom headers for generated request func (r *Request) setCustomHeaders(req *generatedRequest) { for k, v := range r.customHeaders { diff --git a/v2/pkg/protocols/http/request_generator.go b/v2/pkg/protocols/http/request_generator.go index ba3416783..c3199165a 100644 --- a/v2/pkg/protocols/http/request_generator.go +++ b/v2/pkg/protocols/http/request_generator.go @@ -26,12 +26,12 @@ func (r *Request) newGenerator() *requestGenerator { // nextValue returns the next path or the next raw request depending on user input // It returns false if all the inputs have been exhausted by the generator instance. -func (r *requestGenerator) nextValue() (string, map[string]interface{}, bool) { +func (r *requestGenerator) nextValue() (value string, payloads map[string]interface{}, result bool) { // If we have paths, return the next path. if len(r.request.Path) > 0 && r.currentIndex < len(r.request.Path) { - if item := r.request.Path[r.currentIndex]; item != "" { + if value := r.request.Path[r.currentIndex]; value != "" { r.currentIndex++ - return item, nil, true + return value, nil, true } } diff --git a/v2/pkg/protocols/http/utils.go b/v2/pkg/protocols/http/utils.go index c8c07467e..fa9747097 100644 --- a/v2/pkg/protocols/http/utils.go +++ b/v2/pkg/protocols/http/utils.go @@ -1,10 +1,8 @@ package http import ( - "bufio" "bytes" "compress/gzip" - "io" "io/ioutil" "net/http" "net/http/httputil" @@ -118,26 +116,3 @@ func handleDecompression(resp *http.Response, bodyOrig []byte) (bodyDec []byte, } return bodyOrig, nil } - -// rawHasBody checks if a RFC compliant request has the body -func rawHasBody(data string) bool { - b := bufio.NewReader(strings.NewReader(data)) - req, err := http.ReadRequest(b) - if err == io.EOF { - return false - } - if err != nil { - return false - } - - if req.Body == http.NoBody { - return false - } - - // It's enough to read a chunk to check the presence of the body - body, err := ioutil.ReadAll(io.LimitReader(req.Body, 512)) - if err != nil { - return false - } - return len(body) > 0 -} diff --git a/v2/pkg/protocols/network/network.go b/v2/pkg/protocols/network/network.go index c47a6cc9f..a0dd61cad 100644 --- a/v2/pkg/protocols/network/network.go +++ b/v2/pkg/protocols/network/network.go @@ -69,9 +69,9 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error { address = strings.TrimPrefix(address, "tls://") } if strings.Contains(address, ":") { - addressHost, addressPort, err := net.SplitHostPort(address) - if err != nil { - return errors.Wrap(err, "could not parse address") + addressHost, addressPort, portErr := net.SplitHostPort(address) + if portErr != nil { + return errors.Wrap(portErr, "could not parse address") } r.addresses = append(r.addresses, addressKV{ip: addressHost, port: addressPort, tls: shouldUseTLS}) } else { @@ -83,8 +83,8 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error { if input.Type != "" { continue } - if compiled, err := expressions.Evaluate(input.Data, map[string]interface{}{}); err == nil { - input.Data = string(compiled) + if compiled, evalErr := expressions.Evaluate(input.Data, map[string]interface{}{}); evalErr == nil { + input.Data = compiled } } diff --git a/v2/pkg/protocols/network/operators.go b/v2/pkg/protocols/network/operators.go index ce7078e94..135d9c027 100644 --- a/v2/pkg/protocols/network/operators.go +++ b/v2/pkg/protocols/network/operators.go @@ -62,7 +62,7 @@ func (r *Request) Extract(data map[string]interface{}, extractor *extractors.Ext } // responseToDSLMap converts a DNS response to a map for use in DSL matching -func (r *Request) responseToDSLMap(req, resp, raw string, host, matched string) output.InternalEvent { +func (r *Request) responseToDSLMap(req, resp, raw, host, matched string) output.InternalEvent { data := make(output.InternalEvent, 6) // Some data regarding the request metadata diff --git a/v2/pkg/protocols/network/request.go b/v2/pkg/protocols/network/request.go index 0f9d2da77..a255f8a5e 100644 --- a/v2/pkg/protocols/network/request.go +++ b/v2/pkg/protocols/network/request.go @@ -60,7 +60,7 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse err error ) - if host, _, err := net.SplitHostPort(actualAddress); err == nil { + if host, _, splitErr := net.SplitHostPort(actualAddress); splitErr == nil { hostname = host } @@ -75,7 +75,7 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse return errors.Wrap(err, "could not connect to server request") } defer conn.Close() - conn.SetReadDeadline(time.Now().Add(time.Duration(r.options.Options.Timeout) * time.Second)) + _ = conn.SetReadDeadline(time.Now().Add(time.Duration(r.options.Options.Timeout) * time.Second)) responseBuilder := &strings.Builder{} reqBuilder := &strings.Builder{} diff --git a/v2/pkg/protocols/offlinehttp/find_test.go b/v2/pkg/protocols/offlinehttp/find_test.go index 0fe0d4e60..f6851511a 100644 --- a/v2/pkg/protocols/offlinehttp/find_test.go +++ b/v2/pkg/protocols/offlinehttp/find_test.go @@ -21,7 +21,7 @@ func TestFindResponses(t *testing.T) { ID: templateID, Info: map[string]interface{}{"severity": "low", "name": "test"}, }) - executerOpts.Operators = []*operators.Operators{&operators.Operators{}} + executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") diff --git a/v2/pkg/protocols/offlinehttp/operators_test.go b/v2/pkg/protocols/offlinehttp/operators_test.go index d3b83bc4c..c685315c5 100644 --- a/v2/pkg/protocols/offlinehttp/operators_test.go +++ b/v2/pkg/protocols/offlinehttp/operators_test.go @@ -23,7 +23,7 @@ func TestResponseToDSLMap(t *testing.T) { ID: templateID, Info: map[string]interface{}{"severity": "low", "name": "test"}, }) - executerOpts.Operators = []*operators.Operators{&operators.Operators{}} + executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -49,7 +49,7 @@ func TestHTTPOperatorMatch(t *testing.T) { ID: templateID, Info: map[string]interface{}{"severity": "low", "name": "test"}, }) - executerOpts.Operators = []*operators.Operators{&operators.Operators{}} + executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -115,7 +115,7 @@ func TestHTTPOperatorExtract(t *testing.T) { ID: templateID, Info: map[string]interface{}{"severity": "low", "name": "test"}, }) - executerOpts.Operators = []*operators.Operators{&operators.Operators{}} + executerOpts.Operators = []*operators.Operators{{}} err := request.Compile(executerOpts) require.Nil(t, err, "could not compile file request") @@ -168,7 +168,7 @@ func TestHTTPMakeResult(t *testing.T) { ID: templateID, Info: map[string]interface{}{"severity": "low", "name": "test"}, }) - executerOpts.Operators = []*operators.Operators{&operators.Operators{ + executerOpts.Operators = []*operators.Operators{{ Matchers: []*matchers.Matcher{{ Name: "test", Part: "body", diff --git a/v2/pkg/protocols/offlinehttp/read_response.go b/v2/pkg/protocols/offlinehttp/read_response.go index 06035a11d..2e40a2429 100644 --- a/v2/pkg/protocols/offlinehttp/read_response.go +++ b/v2/pkg/protocols/offlinehttp/read_response.go @@ -17,7 +17,7 @@ func readResponseFromString(data string) (*http.Response, error) { if lastIndex == -1 { return nil, errors.New("malformed raw http response") } - final = data[:] // choose last http/ in case of it being later. + final = data // choose last http/ in case of it being later. } return http.ReadResponse(bufio.NewReader(strings.NewReader(final)), nil) } diff --git a/v2/pkg/protocols/protocols.go b/v2/pkg/protocols/protocols.go index b14d3aeb0..1d5073170 100644 --- a/v2/pkg/protocols/protocols.go +++ b/v2/pkg/protocols/protocols.go @@ -2,7 +2,7 @@ package protocols import ( "github.com/projectdiscovery/nuclei/v2/internal/progress" - "github.com/projectdiscovery/nuclei/v2/pkg/catalogue" + "github.com/projectdiscovery/nuclei/v2/pkg/catalog" "github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" @@ -44,8 +44,8 @@ type ExecuterOptions struct { Progress *progress.Progress // RateLimiter is a rate-limiter for limiting sent number of requests. RateLimiter ratelimit.Limiter - // Catalogue is a template catalogue implementation for nuclei - Catalogue *catalogue.Catalogue + // Catalog is a template catalog implementation for nuclei + Catalog *catalog.Catalog // ProjectFile is the project file for nuclei ProjectFile *projectfile.ProjectFile // Browser is a browser engine for running headless templates diff --git a/v2/pkg/reporting/issues/dedupe/dedupe.go b/v2/pkg/reporting/issues/dedupe/dedupe.go index 967c06a5d..151f449a5 100644 --- a/v2/pkg/reporting/issues/dedupe/dedupe.go +++ b/v2/pkg/reporting/issues/dedupe/dedupe.go @@ -22,8 +22,6 @@ type Storage struct { storage *leveldb.DB } -const storageFilename = "nuclei-events.db" - // New creates a new duplicate detecting storage for nuclei scan events. func New(dbPath string) (*Storage, error) { storage := &Storage{} @@ -65,29 +63,29 @@ func (s *Storage) Close() { func (s *Storage) Index(result *output.ResultEvent) (bool, error) { hasher := sha1.New() if result.TemplateID != "" { - hasher.Write(unsafeToBytes(result.TemplateID)) + _, _ = hasher.Write(unsafeToBytes(result.TemplateID)) } if result.MatcherName != "" { - hasher.Write(unsafeToBytes(result.MatcherName)) + _, _ = hasher.Write(unsafeToBytes(result.MatcherName)) } if result.ExtractorName != "" { - hasher.Write(unsafeToBytes(result.ExtractorName)) + _, _ = hasher.Write(unsafeToBytes(result.ExtractorName)) } if result.Type != "" { - hasher.Write(unsafeToBytes(result.Type)) + _, _ = hasher.Write(unsafeToBytes(result.Type)) } if result.Host != "" { - hasher.Write(unsafeToBytes(result.Host)) + _, _ = hasher.Write(unsafeToBytes(result.Host)) } if result.Matched != "" { - hasher.Write(unsafeToBytes(result.Matched)) + _, _ = hasher.Write(unsafeToBytes(result.Matched)) } for _, v := range result.ExtractedResults { - hasher.Write(unsafeToBytes(v)) + _, _ = hasher.Write(unsafeToBytes(v)) } for k, v := range result.Metadata { - hasher.Write(unsafeToBytes(k)) - hasher.Write(unsafeToBytes(types.ToString(v))) + _, _ = hasher.Write(unsafeToBytes(k)) + _, _ = hasher.Write(unsafeToBytes(types.ToString(v))) } hash := hasher.Sum(nil) diff --git a/v2/pkg/reporting/issues/format/format.go b/v2/pkg/reporting/issues/format/format.go index fc941a61c..1544ad519 100644 --- a/v2/pkg/reporting/issues/format/format.go +++ b/v2/pkg/reporting/issues/format/format.go @@ -10,62 +10,62 @@ import ( ) // Summary returns a formatted built one line summary of the event -func Summary(output *output.ResultEvent) string { - template := GetMatchedTemplate(output) +func Summary(event *output.ResultEvent) string { + template := GetMatchedTemplate(event) builder := &strings.Builder{} builder.WriteString("[") builder.WriteString(template) builder.WriteString("] [") - builder.WriteString(types.ToString(output.Info["severity"])) + builder.WriteString(types.ToString(event.Info["severity"])) builder.WriteString("] ") - builder.WriteString(types.ToString(output.Info["name"])) + builder.WriteString(types.ToString(event.Info["name"])) builder.WriteString(" found on ") - builder.WriteString(output.Host) + builder.WriteString(event.Host) data := builder.String() return data } // MarkdownDescription formats a short description of the generated // event by the nuclei scanner in Markdown format. -func MarkdownDescription(output *output.ResultEvent) string { - template := GetMatchedTemplate(output) +func MarkdownDescription(event *output.ResultEvent) string { + template := GetMatchedTemplate(event) builder := &bytes.Buffer{} builder.WriteString("**Details**: **") builder.WriteString(template) builder.WriteString("** ") builder.WriteString(" matched at ") - builder.WriteString(output.Host) + builder.WriteString(event.Host) builder.WriteString("\n\n**Protocol**: ") - builder.WriteString(strings.ToUpper(output.Type)) + builder.WriteString(strings.ToUpper(event.Type)) builder.WriteString("\n\n**Full URL**: ") - builder.WriteString(output.Matched) + builder.WriteString(event.Matched) builder.WriteString("\n\n**Timestamp**: ") - builder.WriteString(output.Timestamp.Format("Mon Jan 2 15:04:05 -0700 MST 2006")) + builder.WriteString(event.Timestamp.Format("Mon Jan 2 15:04:05 -0700 MST 2006")) builder.WriteString("\n\n**Template Information**\n\n| Key | Value |\n|---|---|\n") - for k, v := range output.Info { + for k, v := range event.Info { builder.WriteString(fmt.Sprintf("| %s | %s |\n", k, v)) } builder.WriteString("\n**Request**\n\n```\n") - builder.WriteString(output.Request) + builder.WriteString(event.Request) builder.WriteString("\n```\n\n
**Response**\n\n```\n") - builder.WriteString(output.Response) + builder.WriteString(event.Response) builder.WriteString("\n```\n\n") - if len(output.ExtractedResults) > 0 || len(output.Metadata) > 0 { + if len(event.ExtractedResults) > 0 || len(event.Metadata) > 0 { builder.WriteString("**Extra Information**\n\n") - if len(output.ExtractedResults) > 0 { + if len(event.ExtractedResults) > 0 { builder.WriteString("**Extracted results**:\n\n") - for _, v := range output.ExtractedResults { + for _, v := range event.ExtractedResults { builder.WriteString("- ") builder.WriteString(v) builder.WriteString("\n") } builder.WriteString("\n") } - if len(output.Metadata) > 0 { + if len(event.Metadata) > 0 { builder.WriteString("**Metadata**:\n\n") - for k, v := range output.Metadata { + for k, v := range event.Metadata { builder.WriteString("- ") builder.WriteString(k) builder.WriteString(": ") @@ -80,16 +80,16 @@ func MarkdownDescription(output *output.ResultEvent) string { } // GetMatchedTemplate returns the matched template from a result event -func GetMatchedTemplate(output *output.ResultEvent) string { +func GetMatchedTemplate(event *output.ResultEvent) string { builder := &strings.Builder{} - builder.WriteString(output.TemplateID) - if output.MatcherName != "" { + builder.WriteString(event.TemplateID) + if event.MatcherName != "" { builder.WriteString(":") - builder.WriteString(output.MatcherName) + builder.WriteString(event.MatcherName) } - if output.ExtractorName != "" { + if event.ExtractorName != "" { builder.WriteString(":") - builder.WriteString(output.ExtractorName) + builder.WriteString(event.ExtractorName) } template := builder.String() return template diff --git a/v2/pkg/reporting/issues/issues.go b/v2/pkg/reporting/issues/issues.go index acb34cbd4..66f781504 100644 --- a/v2/pkg/reporting/issues/issues.go +++ b/v2/pkg/reporting/issues/issues.go @@ -53,10 +53,7 @@ func (f *Filter) Compile() { func (f *Filter) GetMatch(event *output.ResultEvent) bool { severity := types.ToString(event.Info["severity"]) if len(f.severity) > 0 { - if stringSliceContains(f.severity, severity) { - return true - } - return false + return stringSliceContains(f.severity, severity) } tags := event.Info["tags"] @@ -94,8 +91,8 @@ func New(config, db string) (*Client, error) { defer file.Close() options := &Options{} - if err := yaml.NewDecoder(file).Decode(options); err != nil { - return nil, err + if parseErr := yaml.NewDecoder(file).Decode(options); parseErr != nil { + return nil, parseErr } if options.AllowList != nil { options.AllowList.Compile() @@ -143,7 +140,7 @@ func (c *Client) CreateIssue(event *output.ResultEvent) error { found, err := c.dedupe.Index(event) if err != nil { - c.tracker.CreateIssue(event) + _ = c.tracker.CreateIssue(event) return err } if found { diff --git a/v2/pkg/reporting/issues/jira/jira.go b/v2/pkg/reporting/issues/jira/jira.go index 735da2cd0..0a0bfc80a 100644 --- a/v2/pkg/reporting/issues/jira/jira.go +++ b/v2/pkg/reporting/issues/jira/jira.go @@ -75,45 +75,45 @@ func (i *Integration) CreateIssue(event *output.ResultEvent) error { // jiraFormatDescription formats a short description of the generated // event by the nuclei scanner in Jira format. -func jiraFormatDescription(output *output.ResultEvent) string { - template := format.GetMatchedTemplate(output) +func jiraFormatDescription(event *output.ResultEvent) string { + template := format.GetMatchedTemplate(event) builder := &bytes.Buffer{} builder.WriteString("*Details*: *") builder.WriteString(template) builder.WriteString("* ") builder.WriteString(" matched at ") - builder.WriteString(output.Host) + builder.WriteString(event.Host) builder.WriteString("\n\n*Protocol*: ") - builder.WriteString(strings.ToUpper(output.Type)) + builder.WriteString(strings.ToUpper(event.Type)) builder.WriteString("\n\n*Full URL*: ") - builder.WriteString(output.Matched) + builder.WriteString(event.Matched) builder.WriteString("\n\n*Timestamp*: ") - builder.WriteString(output.Timestamp.Format("Mon Jan 2 15:04:05 -0700 MST 2006")) + builder.WriteString(event.Timestamp.Format("Mon Jan 2 15:04:05 -0700 MST 2006")) builder.WriteString("\n\n*Template Information*\n\n| Key | Value |\n") - for k, v := range output.Info { + for k, v := range event.Info { builder.WriteString(fmt.Sprintf("| %s | %s |\n", k, v)) } builder.WriteString("\n*Request*\n\n{code}\n") - builder.WriteString(output.Request) + builder.WriteString(event.Request) builder.WriteString("\n{code}\n\n*Response*\n\n{code}\n") - builder.WriteString(output.Response) + builder.WriteString(event.Response) builder.WriteString("\n{code}\n\n") - if len(output.ExtractedResults) > 0 || len(output.Metadata) > 0 { + if len(event.ExtractedResults) > 0 || len(event.Metadata) > 0 { builder.WriteString("*Extra Information*\n\n") - if len(output.ExtractedResults) > 0 { + if len(event.ExtractedResults) > 0 { builder.WriteString("*Extracted results*:\n\n") - for _, v := range output.ExtractedResults { + for _, v := range event.ExtractedResults { builder.WriteString("- ") builder.WriteString(v) builder.WriteString("\n") } builder.WriteString("\n") } - if len(output.Metadata) > 0 { + if len(event.Metadata) > 0 { builder.WriteString("*Metadata*:\n\n") - for k, v := range output.Metadata { + for k, v := range event.Metadata { builder.WriteString("- ") builder.WriteString(k) builder.WriteString(": ") diff --git a/v2/pkg/templates/compile.go b/v2/pkg/templates/compile.go index 900351045..84be9765d 100644 --- a/v2/pkg/templates/compile.go +++ b/v2/pkg/templates/compile.go @@ -18,6 +18,7 @@ import ( ) // Parse parses a yaml request template file +//nolint:gocritic // this cannot be passed by pointer func Parse(filePath string, options protocols.ExecuterOptions) (*Template, error) { template := &Template{} @@ -84,12 +85,12 @@ func Parse(filePath string, options protocols.ExecuterOptions) (*Template, error } if len(template.RequestsHTTP) > 0 { if options.Options.OfflineHTTP { - operators := []*operators.Operators{} + operatorsList := []*operators.Operators{} for _, req := range template.RequestsHTTP { - operators = append(operators, &req.Operators) + operatorsList = append(operatorsList, &req.Operators) } - options.Operators = operators + options.Operators = operatorsList template.Executer = executer.NewExecuter([]protocols.Request{&offlinehttp.Request{}}, &options) } else { for _, req := range template.RequestsHTTP { @@ -130,8 +131,8 @@ func Parse(filePath string, options protocols.ExecuterOptions) (*Template, error } // compileWorkflow compiles the workflow for execution -func (t *Template) compileWorkflow(options *protocols.ExecuterOptions, workflows *workflows.Workflow) error { - for _, workflow := range workflows.Workflows { +func (t *Template) compileWorkflow(options *protocols.ExecuterOptions, workflow *workflows.Workflow) error { + for _, workflow := range workflow.Workflows { if err := t.parseWorkflow(workflow, options); err != nil { return err } @@ -161,7 +162,7 @@ func (t *Template) parseWorkflow(workflow *workflows.WorkflowTemplate, options * // parseWorkflowTemplate parses a workflow template creating an executer func (t *Template) parseWorkflowTemplate(workflow *workflows.WorkflowTemplate, options *protocols.ExecuterOptions) error { - paths, err := options.Catalogue.GetTemplatePath(workflow.Template) + paths, err := options.Catalog.GetTemplatePath(workflow.Template) if err != nil { return errors.Wrap(err, "could not get workflow template") } @@ -170,7 +171,7 @@ func (t *Template) parseWorkflowTemplate(workflow *workflows.WorkflowTemplate, o Output: options.Output, Options: options.Options, Progress: options.Progress, - Catalogue: options.Catalogue, + Catalog: options.Catalog, RateLimiter: options.RateLimiter, IssuesClient: options.IssuesClient, ProjectFile: options.ProjectFile, @@ -220,9 +221,7 @@ mainLoop: } // getKeyValue returns key value pair for a data string -func getKeyValue(data string) (string, string) { - var key, value string - +func getKeyValue(data string) (key, value string) { if strings.Contains(data, ":") { parts := strings.SplitN(data, ":", 2) if len(parts) == 2 { diff --git a/v2/pkg/types/interfaces.go b/v2/pkg/types/interfaces.go index 289f20f29..6b0b40f63 100644 --- a/v2/pkg/types/interfaces.go +++ b/v2/pkg/types/interfaces.go @@ -34,7 +34,7 @@ func ToString(data interface{}) string { case uint: return strconv.FormatUint(uint64(s), 10) case uint64: - return strconv.FormatUint(uint64(s), 10) + return strconv.FormatUint(s, 10) case uint32: return strconv.FormatUint(uint64(s), 10) case uint16: diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go index 40bdbcda9..1fe962d67 100644 --- a/v2/pkg/types/types.go +++ b/v2/pkg/types/types.go @@ -4,6 +4,69 @@ import "github.com/projectdiscovery/goflags" // Options contains the configuration options for nuclei scanner. type Options struct { + // Tags contains a list of tags to execute templates for. Multiple paths + // can be specified with -l flag and -tags can be used in combination with + // the -l flag. + Tags goflags.StringSlice + // Templates specifies the template/templates to use + Templates goflags.StringSlice + // ExcludedTemplates specifies the template/templates to exclude + ExcludedTemplates goflags.StringSlice + // CustomHeaders is the list of custom global headers to send with each request. + CustomHeaders goflags.StringSlice + // Severity filters templates based on their severity and only run the matching ones. + Severity goflags.StringSlice + InternalResolversList []string // normalized from resolvers flag as well as file provided. + // BurpCollaboratorBiid is the Burp Collaborator BIID for polling interactions. + BurpCollaboratorBiid string + // ProjectPath allows nuclei to use a user defined project folder + ProjectPath string + // Target is a single URL/Domain to scan using a template + Target string + // Targets specifies the targets to scan using templates. + Targets string + // Output is the file to write found results to. + Output string + // ProxyURL is the URL for the proxy server + ProxyURL string + // ProxySocksURL is the URL for the proxy socks server + ProxySocksURL string + // TemplatesDirectory is the directory to use for storing templates + TemplatesDirectory string + // TraceLogFile specifies a file to write with the trace of all requests + TraceLogFile string + // ReportingDB is the db for report storage as well as deduplication + ReportingDB string + // ReportingConfig is the config file for nuclei reporting module + ReportingConfig string + // ResolversFile is a file containing resolvers for nuclei. + ResolversFile string + // StatsInterval is the number of seconds to display stats after + StatsInterval int + // MetricsPort is the port to show metrics on + MetricsPort int + // BulkSize is the of targets analyzed in parallel for each template + BulkSize int + // TemplateThreads is the number of templates executed in parallel + TemplateThreads int + // Timeout is the seconds to wait for a response from the server. + Timeout int + // Retries is the number of times to retry the request + Retries int + // Rate-Limit is the maximum number of requests per specified target + RateLimit int + // OfflineHTTP is a flag that specific offline processing of http response + // using same matchers/extractors from http protocol without the need + // to send a new request, reading responses from a file. + OfflineHTTP bool + // Headless specifies whether to allow headless mode templates + Headless bool + // ShowBrowser specifies whether the show the browser in headless mode + ShowBrowser bool + // Workflows specifies if only to execute workflows (no normal templates will be run) + Workflows bool + // SytemResolvers enables override of nuclei's DNS client opting to use system resolver stack. + SystemResolvers bool // RandomAgent generates random User-Agent RandomAgent bool // Metrics enables display of metrics via an http endpoint @@ -42,68 +105,4 @@ type Options struct { NoMeta bool // Project is used to avoid sending same HTTP request multiple times Project bool - // MetricsPort is the port to show metrics on - MetricsPort int - // BulkSize is the of targets analyzed in parallel for each template - BulkSize int - // TemplateThreads is the number of templates executed in parallel - TemplateThreads int - // Timeout is the seconds to wait for a response from the server. - Timeout int - // Retries is the number of times to retry the request - Retries int - // Rate-Limit is the maximum number of requests per specified target - RateLimit int - // BurpCollaboratorBiid is the Burp Collaborator BIID for polling interactions. - BurpCollaboratorBiid string - // ProjectPath allows nuclei to use a user defined project folder - ProjectPath string - // Severity filters templates based on their severity and only run the matching ones. - Severity goflags.StringSlice - // Target is a single URL/Domain to scan using a template - Target string - // Targets specifies the targets to scan using templates. - Targets string - // Output is the file to write found results to. - Output string - // ProxyURL is the URL for the proxy server - ProxyURL string - // ProxySocksURL is the URL for the proxy socks server - ProxySocksURL string - // TemplatesDirectory is the directory to use for storing templates - TemplatesDirectory string - // TraceLogFile specifies a file to write with the trace of all requests - TraceLogFile string - // Templates specifies the template/templates to use - Templates goflags.StringSlice - // ExcludedTemplates specifies the template/templates to exclude - ExcludedTemplates goflags.StringSlice - // CustomHeaders is the list of custom global headers to send with each request. - CustomHeaders goflags.StringSlice - // ReportingDB is the db for report storage as well as deduplication - ReportingDB string - // ReportingConfig is the config file for nuclei reporting module - ReportingConfig string - // Tags contains a list of tags to execute templates for. Multiple paths - // can be specified with -l flag and -tags can be used in combination with - // the -l flag. - Tags goflags.StringSlice - // OfflineHTTP is a flag that specific offline processing of http response - // using same matchers/extractors from http protocol without the need - // to send a new request, reading responses from a file. - OfflineHTTP bool - // ResolversFile is a file containing resolvers for nuclei. - ResolversFile string - // Headless specifies whether to allow headless mode templates - Headless bool - // ShowBrowser specifies whether the show the browser in headless mode - ShowBrowser bool - // Workflows specifies if only to execute workflows (no normal templates will be run) - Workflows bool - // StatsInterval is the number of seconds to display stats after - StatsInterval int - // SytemResolvers enables override of nuclei's DNS client opting to use system resolver stack. - SystemResolvers bool - - InternalResolversList []string // normalized from resolvers flag as well as file provided. } diff --git a/v2/pkg/workflows/execute_test.go b/v2/pkg/workflows/execute_test.go index 86cc92d6c..37e7953bb 100644 --- a/v2/pkg/workflows/execute_test.go +++ b/v2/pkg/workflows/execute_test.go @@ -12,11 +12,11 @@ import ( ) func TestWorkflowsSimple(t *testing.T) { - progress, _ := progress.NewProgress(0, false, false, 0) + progressBar, _ := progress.NewProgress(0, false, false, 0) workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ {Executers: []*ProtocolExecuterPair{{ - Executer: &mockExecuter{result: true}, Options: &protocols.ExecuterOptions{Progress: progress}}, + Executer: &mockExecuter{result: true}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }}, }} @@ -25,19 +25,19 @@ func TestWorkflowsSimple(t *testing.T) { } func TestWorkflowsSimpleMultiple(t *testing.T) { - progress, _ := progress.NewProgress(0, false, false, 0) + progressBar, _ := progress.NewProgress(0, false, false, 0) var firstInput, secondInput string workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ {Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: true, executeHook: func(input string) { firstInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }}, {Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: true, executeHook: func(input string) { secondInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }}, }} @@ -49,18 +49,18 @@ func TestWorkflowsSimpleMultiple(t *testing.T) { } func TestWorkflowsSubtemplates(t *testing.T) { - progress, _ := progress.NewProgress(0, false, false, 0) + progressBar, _ := progress.NewProgress(0, false, false, 0) var firstInput, secondInput string workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ {Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: true, executeHook: func(input string) { firstInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }, Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: true, executeHook: func(input string) { secondInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }}}}, }} @@ -72,18 +72,18 @@ func TestWorkflowsSubtemplates(t *testing.T) { } func TestWorkflowsSubtemplatesNoMatch(t *testing.T) { - progress, _ := progress.NewProgress(0, false, false, 0) + progressBar, _ := progress.NewProgress(0, false, false, 0) var firstInput, secondInput string workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ {Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: false, executeHook: func(input string) { firstInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }, Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: true, executeHook: func(input string) { secondInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }}}}, }} @@ -95,7 +95,7 @@ func TestWorkflowsSubtemplatesNoMatch(t *testing.T) { } func TestWorkflowsSubtemplatesWithMatcher(t *testing.T) { - progress, _ := progress.NewProgress(0, false, false, 0) + progressBar, _ := progress.NewProgress(0, false, false, 0) var firstInput, secondInput string workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ @@ -107,11 +107,11 @@ func TestWorkflowsSubtemplatesWithMatcher(t *testing.T) { Matches: map[string]struct{}{"tomcat": {}}, Extracts: map[string][]string{}, }}, - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }, Matchers: []*Matcher{{Name: "tomcat", Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: true, executeHook: func(input string) { secondInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }}}}}}, }} @@ -123,7 +123,7 @@ func TestWorkflowsSubtemplatesWithMatcher(t *testing.T) { } func TestWorkflowsSubtemplatesWithMatcherNoMatch(t *testing.T) { - progress, _ := progress.NewProgress(0, false, false, 0) + progressBar, _ := progress.NewProgress(0, false, false, 0) var firstInput, secondInput string workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ @@ -135,11 +135,11 @@ func TestWorkflowsSubtemplatesWithMatcherNoMatch(t *testing.T) { Matches: map[string]struct{}{"tomcat": {}}, Extracts: map[string][]string{}, }}, - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }, Matchers: []*Matcher{{Name: "apache", Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ Executer: &mockExecuter{result: true, executeHook: func(input string) { secondInput = input - }}, Options: &protocols.ExecuterOptions{Progress: progress}}, + }}, Options: &protocols.ExecuterOptions{Progress: progressBar}}, }}}}}}, }}