Lint errors fix

This commit is contained in:
Ice3man543 2021-02-26 13:13:11 +05:30
parent b33bc83b0b
commit 8512b684c5
58 changed files with 364 additions and 432 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
cmd/nuclei/nuclei* cmd/nuclei/nuclei*
v2/cmd/nuclei/nuclei v2/cmd/nuclei/nuclei
.idea .idea
integration_tests/integration-test
integration_tests/nuclei
v2/cmd/integration-test/integration-test

View File

@ -6,9 +6,9 @@ linters-settings:
# funlen: # funlen:
# lines: 100 # lines: 100
# statements: 50 # statements: 50
goconst: #goconst:
min-len: 2 # min-len: 2
min-occurrences: 2 # min-occurrences: 2
gocritic: gocritic:
enabled-tags: enabled-tags:
- diagnostic - diagnostic
@ -56,18 +56,18 @@ linters:
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
disable-all: true disable-all: true
enable: enable:
- bodyclose #- bodyclose
- deadcode - deadcode
- dogsled - dogsled
- errcheck - errcheck
- exhaustive - exhaustive
- gochecknoinits - gochecknoinits
- goconst #- goconst
- gocritic - gocritic
- gofmt - gofmt
- goimports - goimports
- golint - golint
- gomnd #- gomnd
- goprintffuncname - goprintffuncname
- gosimple - gosimple
- govet - govet

View File

@ -41,7 +41,7 @@ func httpDebugRequestDump(r *http.Request) {
type httpGetHeaders struct{} 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 { func (h *httpGetHeaders) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 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{} 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 { func (h *httpGetQueryString) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 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{} 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 { func (h *httpGetRedirects) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
httpDebugRequestDump(r) 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) { router.GET("/redirected", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
httpDebugRequestDump(r) httpDebugRequestDump(r)
@ -115,7 +115,7 @@ func (h *httpGetRedirects) Execute(filePath string) error {
type httpGet struct{} 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 { func (h *httpGet) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { 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{} 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 { func (h *httpPostBody) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -170,7 +170,7 @@ func (h *httpPostBody) Execute(filePath string) error {
type httpPostJSONBody struct{} 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 { func (h *httpPostJSONBody) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -209,7 +209,7 @@ func (h *httpPostJSONBody) Execute(filePath string) error {
type httpPostMultipartBody struct{} 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 { func (h *httpPostMultipartBody) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -252,7 +252,7 @@ func (h *httpPostMultipartBody) Execute(filePath string) error {
type httpRawDynamicExtractor struct{} 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 { func (h *httpRawDynamicExtractor) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -291,7 +291,7 @@ func (h *httpRawDynamicExtractor) Execute(filePath string) error {
type httpRawGetQuery struct{} 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 { func (h *httpRawGetQuery) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -320,7 +320,7 @@ func (h *httpRawGetQuery) Execute(filePath string) error {
type httpRawGet struct{} 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 { func (h *httpRawGet) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -348,7 +348,7 @@ func (h *httpRawGet) Execute(filePath string) error {
type httpRawPayload struct{} 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 { func (h *httpRawPayload) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -384,7 +384,7 @@ func (h *httpRawPayload) Execute(filePath string) error {
type httpRawPostBody struct{} 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 { func (h *httpRawPostBody) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -417,7 +417,7 @@ func (h *httpRawPostBody) Execute(filePath string) error {
type httpRawCookieReuse struct{} 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 { func (h *httpRawCookieReuse) Execute(filePath string) error {
router := httprouter.New() router := httprouter.New()
var routerErr error var routerErr error
@ -466,14 +466,14 @@ func (h *httpRawCookieReuse) Execute(filePath string) error {
type httpRawUnsafeRequest struct{} 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 { func (h *httpRawUnsafeRequest) Execute(filePath string) error {
var routerErr error var routerErr error
ts := testutils.NewTCPServer(func(conn net.Conn) { ts := testutils.NewTCPServer(func(conn net.Conn) {
defer conn.Close() 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() defer ts.Close()

View File

@ -4,9 +4,6 @@ import (
"os" "os"
"path" "path"
"net/http"
_ "net/http/pprof"
"github.com/projectdiscovery/goflags" "github.com/projectdiscovery/goflags"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/internal/runner" "github.com/projectdiscovery/nuclei/v2/internal/runner"
@ -20,7 +17,6 @@ var (
func main() { func main() {
readConfig() readConfig()
go http.ListenAndServe(":6060", http.DefaultServeMux)
runner.ParseOptions(options) runner.ParseOptions(options)

View File

@ -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/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 h1:VAONbJw5jP+syI5smhsfkrq9XPGn4aiYy5pR6KR1wog=
github.com/projectdiscovery/hmap v0.0.1/go.mod h1:VDEfgzkKQdq7iGTKz8Ooul0NuYHQ8qiDs6r8bPD1Sb0= 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 h1:HbgPB1eKXQVV5F9sq0Uxflm95spWFyZYD8dgFpeOC9M=
github.com/projectdiscovery/rawhttp v0.0.6/go.mod h1:PQERZAhAv7yxI/hR6hdDPgK1WTU56l204BweXrBec+0= github.com/projectdiscovery/rawhttp v0.0.6/go.mod h1:PQERZAhAv7yxI/hR6hdDPgK1WTU56l204BweXrBec+0=
github.com/projectdiscovery/retryabledns v1.0.7 h1:fwbwrl+0XmWRvwiNzm/YSBjmUh7KwIsryScUK9juOuA= github.com/projectdiscovery/retryabledns v1.0.7 h1:fwbwrl+0XmWRvwiNzm/YSBjmUh7KwIsryScUK9juOuA=

View File

@ -9,7 +9,6 @@ type Colorizer struct {
const ( const (
fgOrange uint8 = 208 fgOrange uint8 = 208
undefined string = "undefined"
) )
// New returns a new severity based colorizer // New returns a new severity based colorizer

View File

@ -1,10 +1,6 @@
package runner package runner
import ( import (
"fmt"
"os"
"path"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/templates" "github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/remeh/sizedwaitgroup" "github.com/remeh/sizedwaitgroup"
@ -52,13 +48,3 @@ func (r *Runner) processWorkflowWithList(template *templates.Template) bool {
wg.Wait() wg.Wait()
return results.Load() 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)
}

View File

@ -12,7 +12,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/internal/collaborator" "github.com/projectdiscovery/nuclei/v2/internal/collaborator"
"github.com/projectdiscovery/nuclei/v2/internal/colorizer" "github.com/projectdiscovery/nuclei/v2/internal/colorizer"
"github.com/projectdiscovery/nuclei/v2/internal/progress" "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/output"
"github.com/projectdiscovery/nuclei/v2/pkg/projectfile" "github.com/projectdiscovery/nuclei/v2/pkg/projectfile"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols"
@ -35,7 +35,7 @@ type Runner struct {
templatesConfig *nucleiConfig templatesConfig *nucleiConfig
options *types.Options options *types.Options
projectFile *projectfile.ProjectFile projectFile *projectfile.ProjectFile
catalogue *catalogue.Catalogue catalog *catalog.Catalog
progress *progress.Progress progress *progress.Progress
colorizer aurora.Aurora colorizer aurora.Aurora
issuesClient *issues.Client issuesClient *issues.Client
@ -63,7 +63,7 @@ func New(options *types.Options) (*Runner, error) {
if runner.templatesConfig != nil { if runner.templatesConfig != nil {
runner.readNucleiIgnoreFile() runner.readNucleiIgnoreFile()
} }
runner.catalogue = catalogue.New(runner.options.TemplatesDirectory) runner.catalog = catalog.New(runner.options.TemplatesDirectory)
if options.ReportingConfig != "" { if options.ReportingConfig != "" {
if client, err := issues.New(options.ReportingConfig, options.ReportingDB); err != nil { 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 // 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 { if err != nil {
gologger.Fatal().Msgf("Could not create output file '%s': %s\n", options.Output, err) 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 // Creates the progress tracking object
var progressErr error var progressErr error
@ -200,8 +200,8 @@ func (r *Runner) RunEnumeration() {
if len(r.options.Templates) == 0 && len(r.options.Tags) > 0 { if len(r.options.Templates) == 0 && len(r.options.Tags) > 0 {
r.options.Templates = append(r.options.Templates, r.options.TemplatesDirectory) r.options.Templates = append(r.options.Templates, r.options.TemplatesDirectory)
} }
includedTemplates := r.catalogue.GetTemplatesPath(r.options.Templates) includedTemplates := r.catalog.GetTemplatesPath(r.options.Templates)
excludedTemplates := r.catalogue.GetTemplatesPath(r.options.ExcludedTemplates) excludedTemplates := r.catalog.GetTemplatesPath(r.options.ExcludedTemplates)
// defaults to all templates // defaults to all templates
allTemplates := includedTemplates allTemplates := includedTemplates
@ -245,7 +245,7 @@ func (r *Runner) RunEnumeration() {
Output: r.output, Output: r.output,
Options: r.options, Options: r.options,
Progress: r.progress, Progress: r.progress,
Catalogue: r.catalogue, Catalog: r.catalog,
RateLimiter: r.ratelimiter, RateLimiter: r.ratelimiter,
IssuesClient: r.issuesClient, IssuesClient: r.issuesClient,
Browser: r.browser, Browser: r.browser,
@ -261,9 +261,7 @@ func (r *Runner) RunEnumeration() {
}) })
clusterCount += len(cluster) clusterCount += len(cluster)
} else { } else {
for _, item := range cluster { finalTemplates = append(finalTemplates, cluster...)
finalTemplates = append(finalTemplates, item)
}
} }
} }

View File

@ -14,13 +14,12 @@ import (
// getParsedTemplatesFor parse the specified templates and returns a slice of the parsable ones, optionally filtered // 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. // by severity, along with a flag indicating if workflows are present.
func (r *Runner) getParsedTemplatesFor(templatePaths []string, severities []string) (map[string]*templates.Template, int) { func (r *Runner) getParsedTemplatesFor(templatePaths, severities []string) (parsedTemplates map[string]*templates.Template, workflowCount int) {
workflowCount := 0
filterBySeverity := len(severities) > 0 filterBySeverity := len(severities) > 0
gologger.Info().Msgf("Loading templates...") gologger.Info().Msgf("Loading templates...")
parsedTemplates := make(map[string]*templates.Template) parsedTemplates = make(map[string]*templates.Template)
for _, match := range templatePaths { for _, match := range templatePaths {
t, err := r.parseTemplateFile(match) t, err := r.parseTemplateFile(match)
if err != nil { if err != nil {
@ -50,7 +49,7 @@ func (r *Runner) parseTemplateFile(file string) (*templates.Template, error) {
Output: r.output, Output: r.output,
Options: r.options, Options: r.options,
Progress: r.progress, Progress: r.progress,
Catalogue: r.catalogue, Catalog: r.catalog,
IssuesClient: r.issuesClient, IssuesClient: r.issuesClient,
RateLimiter: r.ratelimiter, RateLimiter: r.ratelimiter,
ProjectFile: r.projectFile, ProjectFile: r.projectFile,
@ -143,20 +142,3 @@ func directoryWalker(fsPath string, callback func(fsPath string, d *godirwalk.Di
return nil 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
}

View File

@ -278,7 +278,6 @@ 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 // If we don't find a previous file in new download and it hasn't been
// changed on the disk, delete it. // changed on the disk, delete it.
if previousChecksum != nil {
for k, v := range previousChecksum { for k, v := range previousChecksum {
_, ok := checksums[k] _, ok := checksums[k]
if !ok && v[0] == v[1] { if !ok && v[0] == v[1] {
@ -286,7 +285,7 @@ func (r *Runner) downloadReleaseAndUnzip(ctx context.Context, version, downloadU
deletions = append(deletions, strings.TrimPrefix(strings.TrimPrefix(k, r.templatesConfig.TemplatesDirectory), "/")) deletions = append(deletions, strings.TrimPrefix(strings.TrimPrefix(k, r.templatesConfig.TemplatesDirectory), "/"))
} }
} }
}
r.printUpdateChangelog(additions, modifications, deletions, version, totalCount) r.printUpdateChangelog(additions, modifications, deletions, version, totalCount)
return writeTemplatesChecksum(checksumFile, checksums) return writeTemplatesChecksum(checksumFile, checksums)
} }
@ -342,10 +341,10 @@ func writeTemplatesChecksum(file string, checksum map[string]string) error {
defer f.Close() defer f.Close()
for k, v := range checksum { for k, v := range checksum {
f.WriteString(k) _, _ = f.WriteString(k)
f.WriteString(",") _, _ = f.WriteString(",")
f.WriteString(v) _, _ = f.WriteString(v)
f.WriteString("\n") _, _ = f.WriteString("\n")
} }
return nil return nil
} }

View File

@ -8,10 +8,10 @@ import (
) )
// RunNucleiAndGetResults returns a list of results for a template // RunNucleiAndGetResults returns a list of results for a template
func RunNucleiAndGetResults(template string, URL string, debug bool) ([]string, error) { func RunNucleiAndGetResults(template, url string, debug bool) ([]string, error) {
cmd := exec.Command("./nuclei", "-t", template, "-target", URL) cmd := exec.Command("./nuclei", "-t", template, "-target", url)
if debug { if debug {
cmd = exec.Command("./nuclei", "-t", template, "-target", URL, "-debug") cmd = exec.Command("./nuclei", "-t", template, "-target", url, "-debug")
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
} }
data, err := cmd.Output() data, err := cmd.Output()
@ -30,7 +30,7 @@ func RunNucleiAndGetResults(template string, URL string, debug bool) ([]string,
// TestCase is a single integration test case // TestCase is a single integration test case
type TestCase interface { 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 Execute(filePath string) error
} }

View File

@ -3,7 +3,7 @@ package testutils
import ( import (
"github.com/logrusorgru/aurora" "github.com/logrusorgru/aurora"
"github.com/projectdiscovery/nuclei/v2/internal/progress" "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/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
@ -13,7 +13,7 @@ import (
// Init initializes the protocols and their configurations // Init initializes the protocols and their configurations
func Init(options *types.Options) { func Init(options *types.Options) {
protocolinit.Init(options) _ = protocolinit.Init(options)
} }
// DefaultOptions is the default options structure for nuclei during mocking. // DefaultOptions is the default options structure for nuclei during mocking.
@ -102,18 +102,18 @@ type TemplateInfo struct {
// NewMockExecuterOptions creates a new mock executeroptions struct // NewMockExecuterOptions creates a new mock executeroptions struct
func NewMockExecuterOptions(options *types.Options, info *TemplateInfo) *protocols.ExecuterOptions { 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{ executerOpts := &protocols.ExecuterOptions{
TemplateID: info.ID, TemplateID: info.ID,
TemplateInfo: info.Info, TemplateInfo: info.Info,
TemplatePath: info.Path, TemplatePath: info.Path,
Output: NewMockOutputWriter(), Output: NewMockOutputWriter(),
Options: options, Options: options,
Progress: progress, Progress: progressImpl,
ProjectFile: nil, ProjectFile: nil,
IssuesClient: nil, IssuesClient: nil,
Browser: nil, Browser: nil,
Catalogue: catalogue.New(options.TemplatesDirectory), Catalog: catalog.New(options.TemplatesDirectory),
RateLimiter: ratelimit.New(options.RateLimit), RateLimiter: ratelimit.New(options.RateLimit),
} }
return executerOpts return executerOpts

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package catalogue package catalog
import ( import (
"os" "os"
@ -12,7 +12,7 @@ import (
) )
// GetTemplatesPath returns a list of absolute paths for the provided template list. // 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 // keeps track of processed dirs and files
processed := make(map[string]bool) processed := make(map[string]bool)
allTemplates := []string{} allTemplates := []string{}
@ -38,7 +38,7 @@ func (c *Catalogue) GetTemplatesPath(definitions []string) []string {
// GetTemplatePath parses the specified input template path and returns a compiled // GetTemplatePath parses the specified input template path and returns a compiled
// list of finished absolute paths to the templates evaluating any glob patterns // list of finished absolute paths to the templates evaluating any glob patterns
// or folders provided as in. // 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{}) processed := make(map[string]struct{})
absPath, err := c.convertPathToAbsolute(target) absPath, err := c.convertPathToAbsolute(target)
@ -48,9 +48,9 @@ func (c *Catalogue) GetTemplatePath(target string) ([]string, error) {
// Template input includes a wildcard // Template input includes a wildcard
if strings.Contains(absPath, "*") { if strings.Contains(absPath, "*") {
matches, err := c.findGlobPathMatches(absPath, processed) matches, findErr := c.findGlobPathMatches(absPath, processed)
if err != nil { if findErr != nil {
return nil, errors.Wrap(err, "could not find glob matches") return nil, errors.Wrap(findErr, "could not find glob matches")
} }
if len(matches) == 0 { if len(matches) == 0 {
return nil, errors.Errorf("no templates found for path") 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 // convertPathToAbsolute resolves the paths provided to absolute paths
// before doing any operations on them regardless of them being blob, folders, files, etc. // 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, "*") { if strings.Contains(t, "*") {
file := path.Base(t) file := path.Base(t)
absPath, err := c.ResolvePath(path.Dir(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 // 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) matches, err := filepath.Glob(absPath)
if err != nil { if err != nil {
return nil, errors.Errorf("wildcard found, but unable to glob: %s\n", err) 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 // findFileMatches finds if a path is an absolute file. If the path
// is a file, it returns true otherwise false with no errors. // 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) info, err := os.Stat(absPath)
if err != nil { if err != nil {
return "", false, err 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 // 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 var results []string
err := godirwalk.Walk(absPath, &godirwalk.Options{ err := godirwalk.Walk(absPath, &godirwalk.Options{
Unsorted: true, Unsorted: true,

View File

@ -1,4 +1,4 @@
package catalogue package catalog
import ( import (
"bufio" "bufio"
@ -12,7 +12,7 @@ import (
const nucleiIgnoreFile = ".nuclei-ignore" const nucleiIgnoreFile = ".nuclei-ignore"
// readNucleiIgnoreFile reads the nuclei ignore file marking it in map // 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)) file, err := os.Open(path.Join(c.templatesDirectory, nucleiIgnoreFile))
if err != nil { if err != nil {
return return
@ -33,7 +33,7 @@ func (c *Catalogue) readNucleiIgnoreFile() {
} }
// checkIfInNucleiIgnore checks if a path falls under nuclei-ignore rules. // 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 == "" { if c.templatesDirectory == "" {
return false return false
} }
@ -54,7 +54,7 @@ func (c *Catalogue) checkIfInNucleiIgnore(item string) bool {
} }
// ignoreFilesWithExcludes ignores results with exclude paths // 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 var templates []string
for _, result := range results { for _, result := range results {

View File

@ -1,4 +1,4 @@
package catalogue package catalog
import ( import (
"testing" "testing"
@ -7,7 +7,7 @@ import (
) )
func TestIgnoreFilesIgnore(t *testing.T) { func TestIgnoreFilesIgnore(t *testing.T) {
c := &Catalogue{ c := &Catalog{
ignoreFiles: []string{"workflows/", "cves/2020/cve-2020-5432.yaml"}, ignoreFiles: []string{"workflows/", "cves/2020/cve-2020-5432.yaml"},
templatesDirectory: "test", templatesDirectory: "test",
} }
@ -30,7 +30,7 @@ func TestIgnoreFilesIgnore(t *testing.T) {
} }
func TestExcludeFilesIgnore(t *testing.T) { func TestExcludeFilesIgnore(t *testing.T) {
c := &Catalogue{} c := &Catalog{}
excludes := []string{"workflows/", "cves/2020/cve-2020-5432.yaml"} 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/"} 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/"}

View File

@ -1,4 +1,4 @@
package catalogue package catalog
import ( import (
"fmt" "fmt"
@ -13,7 +13,7 @@ import (
// It checks if the filename is an absolute path, looks in the current directory // 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, // or checking the nuclei templates directory. If a second path is given,
// it also tries to find paths relative to that second path. // 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, ":\\") { if strings.HasPrefix(templateName, "/") || strings.Contains(templateName, ":\\") {
return templateName, nil return templateName, nil
} }

View File

@ -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
}

View File

@ -14,8 +14,7 @@ func (m *Matcher) CompileMatchers() error {
var ok bool var ok bool
// Support hexadecimal encoding for matchers too. // Support hexadecimal encoding for matchers too.
switch m.Encoding { if m.Encoding == "hex" {
case "hex":
for i, word := range m.Words { for i, word := range m.Words {
if decoded, err := hex.DecodeString(word); err == nil && len(decoded) > 0 { if decoded, err := hex.DecodeString(word); err == nil && len(decoded) > 0 {
m.Words[i] = string(decoded) m.Words[i] = string(decoded)

View File

@ -7,7 +7,7 @@ import (
) )
// formatScreen formats the output for showing on screen. // 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{} builder := &bytes.Buffer{}
if !w.noMetadata { if !w.noMetadata {
@ -63,5 +63,5 @@ func (w *StandardWriter) formatScreen(output *ResultEvent) ([]byte, error) {
} }
builder.WriteString("]") builder.WriteString("]")
} }
return builder.Bytes(), nil return builder.Bytes()
} }

View File

@ -120,7 +120,7 @@ func (w *StandardWriter) Write(event *ResultEvent) error {
if w.json { if w.json {
data, err = w.formatJSON(event) data, err = w.formatJSON(event)
} else { } else {
data, err = w.formatScreen(event) data = w.formatScreen(event)
} }
if err != nil { if err != nil {
return errors.Wrap(err, "could not format output") return errors.Wrap(err, "could not format output")

View File

@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/logrusorgru/aurora" "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/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
@ -16,18 +16,18 @@ import (
) )
func TestHTTPRequestsCluster(t *testing.T) { func TestHTTPRequestsCluster(t *testing.T) {
catalogue := catalogue.New("/Users/ice3man/nuclei-templates") catalogImpl := catalog.New("/Users/ice3man/nuclei-templates")
templatesList, err := catalogue.GetTemplatePath("/Users/ice3man/nuclei-templates") templatesList, err := catalogImpl.GetTemplatePath("/Users/ice3man/nuclei-templates")
require.Nil(t, err, "could not get templates") require.Nil(t, err, "could not get templates")
protocolinit.Init(&types.Options{}) _ = protocolinit.Init(&types.Options{})
list := make(map[string]*templates.Template) list := make(map[string]*templates.Template)
for _, template := range templatesList { for _, template := range templatesList {
executerOpts := protocols.ExecuterOptions{ executerOpts := protocols.ExecuterOptions{
Output: &mockOutput{}, Output: &mockOutput{},
Options: &types.Options{}, Options: &types.Options{},
Progress: nil, Progress: nil,
Catalogue: catalogue, Catalog: catalogImpl,
RateLimiter: nil, RateLimiter: nil,
IssuesClient: nil, IssuesClient: nil,
ProjectFile: nil, ProjectFile: nil,
@ -45,8 +45,8 @@ func TestHTTPRequestsCluster(t *testing.T) {
totalClusterCount := 0 totalClusterCount := 0
totalRequestsSentNew := 0 totalRequestsSentNew := 0
new := Cluster(list) newRequests := Cluster(list)
for i, cluster := range new { for i, cluster := range newRequests {
if len(cluster) == 1 { if len(cluster) == 1 {
continue continue
} }

View File

@ -76,7 +76,7 @@ func (e *Executer) Execute(input string) (bool, error) {
gologger.Warning().Msgf("Could not create issue on tracker: %s", err) 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() e.options.Progress.IncrementMatched()
} }
} }

View File

@ -48,6 +48,8 @@ func (e *Executer) Execute(input string) (bool, error) {
dynamicValues := make(map[string]interface{}) dynamicValues := make(map[string]interface{})
previous := make(map[string]interface{}) previous := make(map[string]interface{})
for _, req := range e.requests { for _, req := range e.requests {
req := req
err := req.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) { err := req.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) {
ID := req.GetID() ID := req.GetID()
if ID != "" { if ID != "" {
@ -70,7 +72,7 @@ func (e *Executer) Execute(input string) (bool, error) {
} }
} }
results = true results = true
e.options.Output.Write(result) _ = e.options.Output.Write(result)
e.options.Progress.IncrementMatched() e.options.Progress.IncrementMatched()
} }
}) })
@ -87,6 +89,8 @@ func (e *Executer) ExecuteWithResults(input string, callback protocols.OutputEve
previous := make(map[string]interface{}) previous := make(map[string]interface{})
for _, req := range e.requests { for _, req := range e.requests {
req := req
err := req.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) { err := req.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) {
ID := req.GetID() ID := req.GetID()
if ID != "" { if ID != "" {

View File

@ -32,7 +32,7 @@ var StringToType = map[string]Type{
} }
// New creates a new generator structure for payload generation // 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{} generator := &Generator{}
if err := generator.validate(payloads, templatePath); err != nil { if err := generator.validate(payloads, templatePath); err != nil {
return nil, err return nil, err
@ -42,11 +42,11 @@ func New(payloads map[string]interface{}, Type Type, templatePath string) (*Gene
if err != nil { if err != nil {
return nil, err return nil, err
} }
generator.Type = Type generator.Type = payloadType
generator.payloads = compiled generator.payloads = compiled
// Validate the payload types // Validate the payload types
if Type == PitchFork { if payloadType == PitchFork {
var totalLength int var totalLength int
for v := range compiled { for v := range compiled {
if totalLength != 0 && totalLength != len(v) { if totalLength != 0 && totalLength != len(v) {
@ -110,7 +110,7 @@ func (i *Iterator) Total() int {
case ClusterBomb: case ClusterBomb:
count = 1 count = 1
for _, p := range i.payloads { for _, p := range i.payloads {
count = count * len(p.values) count *= len(p.values)
} }
} }
return count return count

View File

@ -13,7 +13,7 @@ const (
// Replace replaces placeholders in template with values on the fly. // Replace replaces placeholders in template with values on the fly.
func Replace(template string, values map[string]interface{}) string { func Replace(template string, values map[string]interface{}) string {
new := fasttemplate.ExecuteStringStd(template, MarkerGeneral, MarkerGeneral, values) newResult := fasttemplate.ExecuteStringStd(template, MarkerGeneral, MarkerGeneral, values)
final := fasttemplate.ExecuteStringStd(new, MarkerParenthesisOpen, MarkerParenthesisClose, values) final := fasttemplate.ExecuteStringStd(newResult, MarkerParenthesisOpen, MarkerParenthesisClose, values)
return final return final
} }

View File

@ -15,10 +15,11 @@ import (
// Request contains a DNS protocol request to be made from a template // Request contains a DNS protocol request to be made from a template
type Request struct { type Request struct {
// Operators for the current request go here.
operators.Operators `yaml:",inline"`
ID string `yaml:"id"` ID string `yaml:"id"`
// Recursion specifies whether to recurse all the answers.
Recursion bool `yaml:"recursion"`
// Path contains the path/s for the request // Path contains the path/s for the request
Name string `yaml:"name"` Name string `yaml:"name"`
// Type is the type of DNS request to make // 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 is the number of retries for the DNS request
Retries int `yaml:"retries"` 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. // cache any variables that may be needed for operation.
class uint16 class uint16
question uint16 question uint16
dnsClient *retryabledns.Client
options *protocols.ExecuterOptions // Recursion specifies whether to recurse all the answers.
Recursion bool `yaml:"recursion"`
} }
// GetID returns the unique ID of the request if any. // 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 // questionTypeToInt converts DNS question type to internal representation
func questionTypeToInt(Type string) uint16 { func questionTypeToInt(questionType string) uint16 {
Type = strings.TrimSpace(strings.ToUpper(Type)) questionType = strings.TrimSpace(strings.ToUpper(questionType))
question := dns.TypeA question := dns.TypeA
switch Type { switch questionType {
case "A": case "A":
question = dns.TypeA question = dns.TypeA
case "NS": case "NS":
@ -119,7 +121,7 @@ func questionTypeToInt(Type string) uint16 {
case "AAAA": case "AAAA":
question = dns.TypeAAAA question = dns.TypeAAAA
} }
return uint16(question) return question
} }
// classToInt converts a dns class name to it's internal representation // classToInt converts a dns class name to it's internal representation

View File

@ -11,7 +11,7 @@ func TestDNSCompileMake(t *testing.T) {
options := testutils.DefaultOptions options := testutils.DefaultOptions
testutils.Init(options) testutils.Init(options)
templateID := "testing-dns" const templateID = "testing-dns"
request := &Request{ request := &Request{
Type: "A", Type: "A",
Class: "INET", Class: "INET",

View File

@ -8,28 +8,30 @@ import (
// Request contains a File matching mechanism for local disk operations. // Request contains a File matching mechanism for local disk operations.
type Request struct { type Request struct {
// 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"`
ID string `yaml:"id"` ID string `yaml:"id"`
// MaxSize is the maximum size of the file to run request on. // 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. // 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. // It can be set to much lower or higher depending on use.
MaxSize int `yaml:"max-size"` MaxSize int `yaml:"max-size"`
// NoRecursive specifies whether to not do recursive checks if folders are provided.
NoRecursive bool `yaml:"no-recursive"`
// 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 CompiledOperators *operators.Operators
// cache any variables that may be needed for operation. // cache any variables that may be needed for operation.
options *protocols.ExecuterOptions options *protocols.ExecuterOptions
extensions map[string]struct{} extensions map[string]struct{}
allExtensions bool
extensionDenylist map[string]struct{} 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 // defaultDenylist is the default list of extensions to be denied

View File

@ -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 // 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) data := make(output.InternalEvent, 5)
// Some data regarding the request metadata // Some data regarding the request metadata

View File

@ -31,7 +31,7 @@ func New(options *types.Options) (*Browser, error) {
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not create temporary directory") return nil, errors.Wrap(err, "could not create temporary directory")
} }
launcher := launcher.New(). chromeLauncher := launcher.New().
Leakless(false). Leakless(false).
Set("disable-gpu", "true"). Set("disable-gpu", "true").
Set("ignore-certificate-errors", "true"). Set("ignore-certificate-errors", "true").
@ -47,21 +47,21 @@ func New(options *types.Options) (*Browser, error) {
UserDataDir(dataStore) UserDataDir(dataStore)
if options.ShowBrowser { if options.ShowBrowser {
launcher = launcher.Headless(false) chromeLauncher = chromeLauncher.Headless(false)
} else { } else {
launcher = launcher.Headless(true) chromeLauncher = chromeLauncher.Headless(true)
} }
if options.ProxyURL != "" { if options.ProxyURL != "" {
launcher = launcher.Proxy(options.ProxyURL) chromeLauncher = chromeLauncher.Proxy(options.ProxyURL)
} }
launcherURL, err := launcher.Launch() launcherURL, err := chromeLauncher.Launch()
if err != nil { if err != nil {
return nil, err return nil, err
} }
browser := rod.New().ControlURL(launcherURL) browser := rod.New().ControlURL(launcherURL)
if err := browser.Connect(); err != nil { if browserErr := browser.Connect(); browserErr != nil {
return nil, err return nil, browserErr
} }
customAgent := "" customAgent := ""
for _, option := range options.CustomHeaders { for _, option := range options.CustomHeaders {
@ -101,8 +101,8 @@ func (b *Browser) Close() {
// killChromeProcesses any and all new chrome processes started after // killChromeProcesses any and all new chrome processes started after
// headless process launch. // headless process launch.
func (b *Browser) killChromeProcesses() { func (b *Browser) killChromeProcesses() {
new := b.findChromeProcesses() newProcesses := b.findChromeProcesses()
for id := range new { for id := range newProcesses {
if _, ok := b.previouspids[id]; ok { if _, ok := b.previouspids[id]; ok {
continue continue
} }

View File

@ -22,15 +22,15 @@ func (i *Instance) Run(baseURL *url.URL, actions []*Action) (map[string]string,
return nil, nil, err return nil, nil, err
} }
if i.browser.customAgent != "" { if i.browser.customAgent != "" {
if err := page.SetUserAgent(&proto.NetworkSetUserAgentOverride{UserAgent: i.browser.customAgent}); err != nil { if userAgentErr := page.SetUserAgent(&proto.NetworkSetUserAgentOverride{UserAgent: i.browser.customAgent}); userAgentErr != nil {
return nil, nil, err return nil, nil, userAgentErr
} }
} }
createdPage := &Page{page: page, instance: i} createdPage := &Page{page: page, instance: i}
router := page.HijackRequests() router := page.HijackRequests()
if err := router.Add("*", "", createdPage.routingRuleHandler); err != nil { if routerErr := router.Add("*", "", createdPage.routingRuleHandler); routerErr != nil {
return nil, nil, err return nil, nil, routerErr
} }
createdPage.router = router createdPage.router = router
@ -57,7 +57,7 @@ func (i *Instance) Run(baseURL *url.URL, actions []*Action) (map[string]string,
// Close closes a browser page // Close closes a browser page
func (p *Page) Close() { func (p *Page) Close() {
p.router.Stop() _ = p.router.Stop()
p.page.Close() p.page.Close()
} }

View File

@ -67,7 +67,7 @@ func (p *Page) ExecuteActions(baseURL *url.URL, actions []*Action) (map[string]s
continue continue
} }
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error occured executing action") return nil, errors.Wrap(err, "error occurred executing action")
} }
} }
return outData, nil 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. // 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 { func (p *Page) NavigateURL(action *Action, out map[string]string, parsed *url.URL) error {
url := action.GetArg("url") URL := action.GetArg("url")
if url == "" { if URL == "" {
return errors.New("invalid arguments provided") return errors.New("invalid arguments provided")
} }
// Handle the dynamic value substituion here. // Handle the dynamic value substitution here.
url, parsed = baseURLWithTemplatePrefs(url, parsed) URL, parsed = baseURLWithTemplatePrefs(URL, parsed)
values := map[string]interface{}{"Hostname": parsed.Hostname()} 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, "/") parsed.Path = strings.TrimSuffix(parsed.Path, "/")
} }
parsedString := parsed.String() parsedString := parsed.String()
values["BaseURL"] = parsedString values["BaseURL"] = parsedString
final := fasttemplate.ExecuteStringStd(url, "{{", "}}", values) final := fasttemplate.ExecuteStringStd(URL, "{{", "}}", values)
err := p.page.Navigate(final) err := p.page.Navigate(final)
if err != nil { if err != nil {
return errors.Wrap(err, "could not navigate") return errors.Wrap(err, "could not navigate")
@ -476,8 +476,6 @@ func selectorBy(selector string) rod.SelectorType {
return rod.SelectorTypeCSSSector return rod.SelectorTypeCSSSector
case "regex": case "regex":
return rod.SelectorTypeRegex return rod.SelectorTypeRegex
case "text":
fallthrough
default: default:
return rod.SelectorTypeText return rod.SelectorTypeText
} }

View File

@ -27,7 +27,7 @@ func (p *Page) routingRuleHandler(ctx *rod.Hijack) {
ctx.Request.SetBody(body) ctx.Request.SetBody(body)
} }
} }
ctx.LoadResponse(p.instance.browser.httpclient, true) _ = ctx.LoadResponse(p.instance.browser.httpclient, true)
for _, rule := range p.rules { for _, rule := range p.rules {
if rule.Part != "response" { if rule.Part != "response" {

View File

@ -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 // 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) data := make(output.InternalEvent, 5)
// Some data regarding the request metadata // Some data regarding the request metadata

View File

@ -51,7 +51,7 @@ func (r *requestGenerator) Make(baseURL string, dynamicValues map[string]interfa
data, parsed = baseURLWithTemplatePrefs(data, parsed) data, parsed = baseURLWithTemplatePrefs(data, parsed)
values := generators.MergeMaps(dynamicValues, map[string]interface{}{ values := generators.MergeMaps(dynamicValues, map[string]interface{}{
"Hostname": parsed.Hostname(), "Hostname": parsed.Host,
}) })
isRawRequest := len(r.request.Raw) > 0 isRawRequest := len(r.request.Raw) > 0

View File

@ -116,8 +116,8 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error {
} }
if len(r.Matchers) > 0 || len(r.Extractors) > 0 { if len(r.Matchers) > 0 || len(r.Extractors) > 0 {
compiled := &r.Operators compiled := &r.Operators
if err := compiled.Compile(); err != nil { if compileErr := compiled.Compile(); compileErr != nil {
return errors.Wrap(err, "could not compile operators") return errors.Wrap(compileErr, "could not compile operators")
} }
r.CompiledOperators = compiled r.CompiledOperators = compiled
} }
@ -131,16 +131,15 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error {
// Resolve payload paths if they are files. // Resolve payload paths if they are files.
for name, payload := range r.Payloads { for name, payload := range r.Payloads {
switch pt := payload.(type) { payloadStr, ok := payload.(string)
case string: if ok {
final, err := options.Catalogue.ResolvePath(pt, options.TemplatePath) final, resolveErr := options.Catalog.ResolvePath(payloadStr, options.TemplatePath)
if err != nil { if resolveErr != nil {
return errors.Wrap(err, "could not read payload file") return errors.Wrap(resolveErr, "could not read payload file")
} }
r.Payloads[name] = final r.Payloads[name] = final
} }
} }
r.generator, err = generators.New(r.Payloads, r.attackType, r.options.TemplatePath) r.generator, err = generators.New(r.Payloads, r.attackType, r.options.TemplatePath)
if err != nil { if err != nil {
return errors.Wrap(err, "could not parse payloads") return errors.Wrap(err, "could not parse payloads")
@ -160,7 +159,7 @@ func (r *Request) Requests() int {
if len(r.Raw) > 0 { if len(r.Raw) > 0 {
requests := len(r.Raw) requests := len(r.Raw)
if requests == 1 && r.RaceNumberRequests != 0 { if requests == 1 && r.RaceNumberRequests != 0 {
requests = requests * r.RaceNumberRequests requests *= r.RaceNumberRequests
} }
return requests return requests
} }

View File

@ -49,12 +49,12 @@ func Init(options *types.Options) error {
// Configuration contains the custom configuration options for a client // Configuration contains the custom configuration options for a client
type Configuration struct { type Configuration struct {
// CookieReuse enables cookie reuse for the http client (cookiejar impl)
CookieReuse bool
// Threads contains the threads for the client // Threads contains the threads for the client
Threads int Threads int
// MaxRedirects is the maximum number of redirects to follow // MaxRedirects is the maximum number of redirects to follow
MaxRedirects int MaxRedirects int
// CookieReuse enables cookie reuse for the http client (cookiejar impl)
CookieReuse bool
// FollowRedirects specifies whether to follow redirects // FollowRedirects specifies whether to follow redirects
FollowRedirects bool FollowRedirects bool
} }
@ -161,17 +161,17 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
if options.ProxySocksURL != "" { if options.ProxySocksURL != "" {
var proxyAuth *proxy.Auth var proxyAuth *proxy.Auth
socksURL, err := url.Parse(options.ProxySocksURL) socksURL, proxyErr := url.Parse(options.ProxySocksURL)
if err == nil { if proxyErr == nil {
proxyAuth = &proxy.Auth{} proxyAuth = &proxy.Auth{}
proxyAuth.User = socksURL.User.Username() proxyAuth.User = socksURL.User.Username()
proxyAuth.Password, _ = socksURL.User.Password() 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 { dc := dialer.(interface {
DialContext(ctx context.Context, network, addr string) (net.Conn, error) DialContext(ctx context.Context, network, addr string) (net.Conn, error)
}) })
if err == nil { if proxyErr == nil {
transport.DialContext = dc.DialContext transport.DialContext = dc.DialContext
} }
} }

View File

@ -94,7 +94,7 @@ func (r *Request) responseToDSLMap(resp *http.Response, host, matched, rawReq, r
data[strings.ToLower(cookie.Name)] = cookie.Value data[strings.ToLower(cookie.Name)] = cookie.Value
} }
for k, v := range resp.Header { 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[k] = strings.Join(v, " ")
} }
data["all_headers"] = headers data["all_headers"] = headers

View File

@ -41,7 +41,6 @@ func Parse(request, baseURL string, unsafe bool) (*Request, error) {
} }
parts := strings.Split(s, " ") parts := strings.Split(s, " ")
//nolint:gomnd // this is not a magic number
if len(parts) < 3 && !unsafe { if len(parts) < 3 && !unsafe {
return nil, fmt.Errorf("malformed request supplied") return nil, fmt.Errorf("malformed request supplied")
} }

View File

@ -26,7 +26,7 @@ import (
const defaultMaxWorkers = 150 const defaultMaxWorkers = 150
// executeRaceRequest executes race condition request for a URL // 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() generator := r.newGenerator()
maxWorkers := r.RaceNumberRequests maxWorkers := r.RaceNumberRequests
@ -42,7 +42,7 @@ func (r *Request) executeRaceRequest(reqURL string, dynamicValues, previous outp
for i := 0; i < r.RaceNumberRequests; i++ { for i := 0; i < r.RaceNumberRequests; i++ {
swg.Add() swg.Add()
go func(httpRequest *generatedRequest) { go func(httpRequest *generatedRequest) {
err := r.executeRequest(reqURL, httpRequest, dynamicValues, previous, callback) err := r.executeRequest(reqURL, httpRequest, previous, callback)
mutex.Lock() mutex.Lock()
if err != nil { if err != nil {
requestErr = multierr.Append(requestErr, err) requestErr = multierr.Append(requestErr, err)
@ -79,7 +79,7 @@ func (r *Request) executeParallelHTTP(reqURL string, dynamicValues, previous out
defer swg.Done() defer swg.Done()
r.options.RateLimiter.Take() r.options.RateLimiter.Take()
err := r.executeRequest(reqURL, httpRequest, dynamicValues, previous, callback) err := r.executeRequest(reqURL, httpRequest, previous, callback)
mutex.Lock() mutex.Lock()
if err != nil { if err != nil {
requestErr = multierr.Append(requestErr, err) requestErr = multierr.Append(requestErr, err)
@ -138,7 +138,7 @@ func (r *Request) executeTurboHTTP(reqURL string, dynamicValues, previous output
go func(httpRequest *generatedRequest) { go func(httpRequest *generatedRequest) {
defer swg.Done() defer swg.Done()
err := r.executeRequest(reqURL, httpRequest, dynamicValues, previous, callback) err := r.executeRequest(reqURL, httpRequest, previous, callback)
mutex.Lock() mutex.Lock()
if err != nil { if err != nil {
requestErr = multierr.Append(requestErr, err) 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 // verify if a basic race condition was requested
if r.Race && r.RaceNumberRequests > 0 { 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 // verify if parallel elaboration was requested
@ -183,7 +183,7 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp
var gotOutput bool var gotOutput bool
r.options.RateLimiter.Take() 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. // Add the extracts to the dynamic values if any.
if event.OperatorsResult != nil { if event.OperatorsResult != nil {
gotOutput = true gotOutput = true
@ -206,8 +206,8 @@ func (r *Request) ExecuteWithResults(reqURL string, dynamicValues, previous outp
const drainReqSize = int64(8 * 1024) const drainReqSize = int64(8 * 1024)
// executeRequest executes the actual generated request and returns error if occured // executeRequest executes the actual generated request and returns error if occurred
func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynamicvalues, previous output.InternalEvent, callback protocols.OutputEventCallback) error { func (r *Request) executeRequest(reqURL string, request *generatedRequest, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
r.setCustomHeaders(request) r.setCustomHeaders(request)
var ( var (
@ -235,27 +235,26 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam
timeStart := time.Now() timeStart := time.Now()
if request.original.Pipeline { if request.original.Pipeline {
formedURL = request.rawRequest.FullURL formedURL = request.rawRequest.FullURL
if parsed, err := url.Parse(formedURL); err == nil { if parsed, parseErr := url.Parse(formedURL); parseErr == nil {
hostname = parsed.Hostname() 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))) 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 { } else if request.original.Unsafe && request.rawRequest != nil {
formedURL = request.rawRequest.FullURL formedURL = request.rawRequest.FullURL
if parsed, err := url.Parse(formedURL); err == nil { if parsed, parseErr := url.Parse(formedURL); parseErr == nil {
hostname = parsed.Hostname() hostname = parsed.Host
} }
options := request.original.rawhttpClient.Options options := request.original.rawhttpClient.Options
options.FollowRedirects = r.Redirects 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) 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 { } else {
hostname = request.request.URL.Hostname() hostname = request.request.URL.Host
formedURL = request.request.URL.String() formedURL = request.request.URL.String()
// if nuclei-project is available check if the request was already sent previously // if nuclei-project is available check if the request was already sent previously
if r.options.ProjectFile != nil { if r.options.ProjectFile != nil {
// if unavailable fail silently // if unavailable fail silently
fromcache = true fromcache = true
// nolint:bodyclose // false positive the response is generated at runtime
resp, err = r.options.ProjectFile.Get(dumpedRequest) resp, err = r.options.ProjectFile.Get(dumpedRequest)
if err != nil { if err != nil {
fromcache = false fromcache = false
@ -278,6 +277,10 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam
r.options.Progress.DecrementRequests(1) r.options.Progress.DecrementRequests(1)
return err 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) gologger.Verbose().Msgf("[%s] Sent HTTP request to %s", r.options.TemplateID, formedURL)
r.options.Output.Request(r.options.TemplateID, reqURL, "http", err) 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) dumpedResponseHeaders, err := httputil.DumpResponse(resp, false)
if err != nil { if err != nil {
_, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize)
resp.Body.Close()
return errors.Wrap(err, "could not dump http response") 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) data, err := ioutil.ReadAll(bodyReader)
if err != nil { if err != nil {
_, _ = io.CopyN(ioutil.Discard, resp.Body, drainReqSize)
resp.Body.Close()
return errors.Wrap(err, "could not read http body") return errors.Wrap(err, "could not read http body")
} }
resp.Body.Close() resp.Body.Close()
@ -364,8 +363,6 @@ func (r *Request) executeRequest(reqURL string, request *generatedRequest, dynam
return nil return nil
} }
const two = 2
// setCustomHeaders sets the custom headers for generated request // setCustomHeaders sets the custom headers for generated request
func (r *Request) setCustomHeaders(req *generatedRequest) { func (r *Request) setCustomHeaders(req *generatedRequest) {
for k, v := range r.customHeaders { for k, v := range r.customHeaders {

View File

@ -26,12 +26,12 @@ func (r *Request) newGenerator() *requestGenerator {
// nextValue returns the next path or the next raw request depending on user input // 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. // 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 we have paths, return the next path.
if len(r.request.Path) > 0 && r.currentIndex < len(r.request.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++ r.currentIndex++
return item, nil, true return value, nil, true
} }
} }

View File

@ -1,10 +1,8 @@
package http package http
import ( import (
"bufio"
"bytes" "bytes"
"compress/gzip" "compress/gzip"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@ -118,26 +116,3 @@ func handleDecompression(resp *http.Response, bodyOrig []byte) (bodyDec []byte,
} }
return bodyOrig, nil 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
}

View File

@ -69,9 +69,9 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error {
address = strings.TrimPrefix(address, "tls://") address = strings.TrimPrefix(address, "tls://")
} }
if strings.Contains(address, ":") { if strings.Contains(address, ":") {
addressHost, addressPort, err := net.SplitHostPort(address) addressHost, addressPort, portErr := net.SplitHostPort(address)
if err != nil { if portErr != nil {
return errors.Wrap(err, "could not parse address") return errors.Wrap(portErr, "could not parse address")
} }
r.addresses = append(r.addresses, addressKV{ip: addressHost, port: addressPort, tls: shouldUseTLS}) r.addresses = append(r.addresses, addressKV{ip: addressHost, port: addressPort, tls: shouldUseTLS})
} else { } else {
@ -83,8 +83,8 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error {
if input.Type != "" { if input.Type != "" {
continue continue
} }
if compiled, err := expressions.Evaluate(input.Data, map[string]interface{}{}); err == nil { if compiled, evalErr := expressions.Evaluate(input.Data, map[string]interface{}{}); evalErr == nil {
input.Data = string(compiled) input.Data = compiled
} }
} }

View File

@ -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 // 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) data := make(output.InternalEvent, 6)
// Some data regarding the request metadata // Some data regarding the request metadata

View File

@ -60,7 +60,7 @@ func (r *Request) executeAddress(actualAddress, address, input string, shouldUse
err error err error
) )
if host, _, err := net.SplitHostPort(actualAddress); err == nil { if host, _, splitErr := net.SplitHostPort(actualAddress); splitErr == nil {
hostname = host 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") return errors.Wrap(err, "could not connect to server request")
} }
defer conn.Close() 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{} responseBuilder := &strings.Builder{}
reqBuilder := &strings.Builder{} reqBuilder := &strings.Builder{}

View File

@ -21,7 +21,7 @@ func TestFindResponses(t *testing.T) {
ID: templateID, ID: templateID,
Info: map[string]interface{}{"severity": "low", "name": "test"}, Info: map[string]interface{}{"severity": "low", "name": "test"},
}) })
executerOpts.Operators = []*operators.Operators{&operators.Operators{}} executerOpts.Operators = []*operators.Operators{{}}
err := request.Compile(executerOpts) err := request.Compile(executerOpts)
require.Nil(t, err, "could not compile file request") require.Nil(t, err, "could not compile file request")

View File

@ -23,7 +23,7 @@ func TestResponseToDSLMap(t *testing.T) {
ID: templateID, ID: templateID,
Info: map[string]interface{}{"severity": "low", "name": "test"}, Info: map[string]interface{}{"severity": "low", "name": "test"},
}) })
executerOpts.Operators = []*operators.Operators{&operators.Operators{}} executerOpts.Operators = []*operators.Operators{{}}
err := request.Compile(executerOpts) err := request.Compile(executerOpts)
require.Nil(t, err, "could not compile file request") require.Nil(t, err, "could not compile file request")
@ -49,7 +49,7 @@ func TestHTTPOperatorMatch(t *testing.T) {
ID: templateID, ID: templateID,
Info: map[string]interface{}{"severity": "low", "name": "test"}, Info: map[string]interface{}{"severity": "low", "name": "test"},
}) })
executerOpts.Operators = []*operators.Operators{&operators.Operators{}} executerOpts.Operators = []*operators.Operators{{}}
err := request.Compile(executerOpts) err := request.Compile(executerOpts)
require.Nil(t, err, "could not compile file request") require.Nil(t, err, "could not compile file request")
@ -115,7 +115,7 @@ func TestHTTPOperatorExtract(t *testing.T) {
ID: templateID, ID: templateID,
Info: map[string]interface{}{"severity": "low", "name": "test"}, Info: map[string]interface{}{"severity": "low", "name": "test"},
}) })
executerOpts.Operators = []*operators.Operators{&operators.Operators{}} executerOpts.Operators = []*operators.Operators{{}}
err := request.Compile(executerOpts) err := request.Compile(executerOpts)
require.Nil(t, err, "could not compile file request") require.Nil(t, err, "could not compile file request")
@ -168,7 +168,7 @@ func TestHTTPMakeResult(t *testing.T) {
ID: templateID, ID: templateID,
Info: map[string]interface{}{"severity": "low", "name": "test"}, Info: map[string]interface{}{"severity": "low", "name": "test"},
}) })
executerOpts.Operators = []*operators.Operators{&operators.Operators{ executerOpts.Operators = []*operators.Operators{{
Matchers: []*matchers.Matcher{{ Matchers: []*matchers.Matcher{{
Name: "test", Name: "test",
Part: "body", Part: "body",

View File

@ -17,7 +17,7 @@ func readResponseFromString(data string) (*http.Response, error) {
if lastIndex == -1 { if lastIndex == -1 {
return nil, errors.New("malformed raw http response") 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) return http.ReadResponse(bufio.NewReader(strings.NewReader(final)), nil)
} }

View File

@ -2,7 +2,7 @@ package protocols
import ( import (
"github.com/projectdiscovery/nuclei/v2/internal/progress" "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"
"github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors" "github.com/projectdiscovery/nuclei/v2/pkg/operators/extractors"
"github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers" "github.com/projectdiscovery/nuclei/v2/pkg/operators/matchers"
@ -44,8 +44,8 @@ type ExecuterOptions struct {
Progress *progress.Progress Progress *progress.Progress
// RateLimiter is a rate-limiter for limiting sent number of requests. // RateLimiter is a rate-limiter for limiting sent number of requests.
RateLimiter ratelimit.Limiter RateLimiter ratelimit.Limiter
// Catalogue is a template catalogue implementation for nuclei // Catalog is a template catalog implementation for nuclei
Catalogue *catalogue.Catalogue Catalog *catalog.Catalog
// ProjectFile is the project file for nuclei // ProjectFile is the project file for nuclei
ProjectFile *projectfile.ProjectFile ProjectFile *projectfile.ProjectFile
// Browser is a browser engine for running headless templates // Browser is a browser engine for running headless templates

View File

@ -22,8 +22,6 @@ type Storage struct {
storage *leveldb.DB storage *leveldb.DB
} }
const storageFilename = "nuclei-events.db"
// New creates a new duplicate detecting storage for nuclei scan events. // New creates a new duplicate detecting storage for nuclei scan events.
func New(dbPath string) (*Storage, error) { func New(dbPath string) (*Storage, error) {
storage := &Storage{} storage := &Storage{}
@ -65,29 +63,29 @@ func (s *Storage) Close() {
func (s *Storage) Index(result *output.ResultEvent) (bool, error) { func (s *Storage) Index(result *output.ResultEvent) (bool, error) {
hasher := sha1.New() hasher := sha1.New()
if result.TemplateID != "" { if result.TemplateID != "" {
hasher.Write(unsafeToBytes(result.TemplateID)) _, _ = hasher.Write(unsafeToBytes(result.TemplateID))
} }
if result.MatcherName != "" { if result.MatcherName != "" {
hasher.Write(unsafeToBytes(result.MatcherName)) _, _ = hasher.Write(unsafeToBytes(result.MatcherName))
} }
if result.ExtractorName != "" { if result.ExtractorName != "" {
hasher.Write(unsafeToBytes(result.ExtractorName)) _, _ = hasher.Write(unsafeToBytes(result.ExtractorName))
} }
if result.Type != "" { if result.Type != "" {
hasher.Write(unsafeToBytes(result.Type)) _, _ = hasher.Write(unsafeToBytes(result.Type))
} }
if result.Host != "" { if result.Host != "" {
hasher.Write(unsafeToBytes(result.Host)) _, _ = hasher.Write(unsafeToBytes(result.Host))
} }
if result.Matched != "" { if result.Matched != "" {
hasher.Write(unsafeToBytes(result.Matched)) _, _ = hasher.Write(unsafeToBytes(result.Matched))
} }
for _, v := range result.ExtractedResults { for _, v := range result.ExtractedResults {
hasher.Write(unsafeToBytes(v)) _, _ = hasher.Write(unsafeToBytes(v))
} }
for k, v := range result.Metadata { for k, v := range result.Metadata {
hasher.Write(unsafeToBytes(k)) _, _ = hasher.Write(unsafeToBytes(k))
hasher.Write(unsafeToBytes(types.ToString(v))) _, _ = hasher.Write(unsafeToBytes(types.ToString(v)))
} }
hash := hasher.Sum(nil) hash := hasher.Sum(nil)

View File

@ -10,62 +10,62 @@ import (
) )
// Summary returns a formatted built one line summary of the event // Summary returns a formatted built one line summary of the event
func Summary(output *output.ResultEvent) string { func Summary(event *output.ResultEvent) string {
template := GetMatchedTemplate(output) template := GetMatchedTemplate(event)
builder := &strings.Builder{} builder := &strings.Builder{}
builder.WriteString("[") builder.WriteString("[")
builder.WriteString(template) builder.WriteString(template)
builder.WriteString("] [") builder.WriteString("] [")
builder.WriteString(types.ToString(output.Info["severity"])) builder.WriteString(types.ToString(event.Info["severity"]))
builder.WriteString("] ") builder.WriteString("] ")
builder.WriteString(types.ToString(output.Info["name"])) builder.WriteString(types.ToString(event.Info["name"]))
builder.WriteString(" found on ") builder.WriteString(" found on ")
builder.WriteString(output.Host) builder.WriteString(event.Host)
data := builder.String() data := builder.String()
return data return data
} }
// MarkdownDescription formats a short description of the generated // MarkdownDescription formats a short description of the generated
// event by the nuclei scanner in Markdown format. // event by the nuclei scanner in Markdown format.
func MarkdownDescription(output *output.ResultEvent) string { func MarkdownDescription(event *output.ResultEvent) string {
template := GetMatchedTemplate(output) template := GetMatchedTemplate(event)
builder := &bytes.Buffer{} builder := &bytes.Buffer{}
builder.WriteString("**Details**: **") builder.WriteString("**Details**: **")
builder.WriteString(template) builder.WriteString(template)
builder.WriteString("** ") builder.WriteString("** ")
builder.WriteString(" matched at ") builder.WriteString(" matched at ")
builder.WriteString(output.Host) builder.WriteString(event.Host)
builder.WriteString("\n\n**Protocol**: ") 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("\n\n**Full URL**: ")
builder.WriteString(output.Matched) builder.WriteString(event.Matched)
builder.WriteString("\n\n**Timestamp**: ") 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") 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(fmt.Sprintf("| %s | %s |\n", k, v))
} }
builder.WriteString("\n**Request**\n\n```\n") builder.WriteString("\n**Request**\n\n```\n")
builder.WriteString(output.Request) builder.WriteString(event.Request)
builder.WriteString("\n```\n\n<details><summary>**Response**</summary>\n\n```\n") builder.WriteString("\n```\n\n<details><summary>**Response**</summary>\n\n```\n")
builder.WriteString(output.Response) builder.WriteString(event.Response)
builder.WriteString("\n```\n\n") 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") builder.WriteString("**Extra Information**\n\n")
if len(output.ExtractedResults) > 0 { if len(event.ExtractedResults) > 0 {
builder.WriteString("**Extracted results**:\n\n") builder.WriteString("**Extracted results**:\n\n")
for _, v := range output.ExtractedResults { for _, v := range event.ExtractedResults {
builder.WriteString("- ") builder.WriteString("- ")
builder.WriteString(v) builder.WriteString(v)
builder.WriteString("\n") builder.WriteString("\n")
} }
builder.WriteString("\n") builder.WriteString("\n")
} }
if len(output.Metadata) > 0 { if len(event.Metadata) > 0 {
builder.WriteString("**Metadata**:\n\n") builder.WriteString("**Metadata**:\n\n")
for k, v := range output.Metadata { for k, v := range event.Metadata {
builder.WriteString("- ") builder.WriteString("- ")
builder.WriteString(k) builder.WriteString(k)
builder.WriteString(": ") builder.WriteString(": ")
@ -80,16 +80,16 @@ func MarkdownDescription(output *output.ResultEvent) string {
} }
// GetMatchedTemplate returns the matched template from a result event // 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 := &strings.Builder{}
builder.WriteString(output.TemplateID) builder.WriteString(event.TemplateID)
if output.MatcherName != "" { if event.MatcherName != "" {
builder.WriteString(":") builder.WriteString(":")
builder.WriteString(output.MatcherName) builder.WriteString(event.MatcherName)
} }
if output.ExtractorName != "" { if event.ExtractorName != "" {
builder.WriteString(":") builder.WriteString(":")
builder.WriteString(output.ExtractorName) builder.WriteString(event.ExtractorName)
} }
template := builder.String() template := builder.String()
return template return template

View File

@ -53,10 +53,7 @@ func (f *Filter) Compile() {
func (f *Filter) GetMatch(event *output.ResultEvent) bool { func (f *Filter) GetMatch(event *output.ResultEvent) bool {
severity := types.ToString(event.Info["severity"]) severity := types.ToString(event.Info["severity"])
if len(f.severity) > 0 { if len(f.severity) > 0 {
if stringSliceContains(f.severity, severity) { return stringSliceContains(f.severity, severity)
return true
}
return false
} }
tags := event.Info["tags"] tags := event.Info["tags"]
@ -94,8 +91,8 @@ func New(config, db string) (*Client, error) {
defer file.Close() defer file.Close()
options := &Options{} options := &Options{}
if err := yaml.NewDecoder(file).Decode(options); err != nil { if parseErr := yaml.NewDecoder(file).Decode(options); parseErr != nil {
return nil, err return nil, parseErr
} }
if options.AllowList != nil { if options.AllowList != nil {
options.AllowList.Compile() options.AllowList.Compile()
@ -143,7 +140,7 @@ func (c *Client) CreateIssue(event *output.ResultEvent) error {
found, err := c.dedupe.Index(event) found, err := c.dedupe.Index(event)
if err != nil { if err != nil {
c.tracker.CreateIssue(event) _ = c.tracker.CreateIssue(event)
return err return err
} }
if found { if found {

View File

@ -75,45 +75,45 @@ func (i *Integration) CreateIssue(event *output.ResultEvent) error {
// jiraFormatDescription formats a short description of the generated // jiraFormatDescription formats a short description of the generated
// event by the nuclei scanner in Jira format. // event by the nuclei scanner in Jira format.
func jiraFormatDescription(output *output.ResultEvent) string { func jiraFormatDescription(event *output.ResultEvent) string {
template := format.GetMatchedTemplate(output) template := format.GetMatchedTemplate(event)
builder := &bytes.Buffer{} builder := &bytes.Buffer{}
builder.WriteString("*Details*: *") builder.WriteString("*Details*: *")
builder.WriteString(template) builder.WriteString(template)
builder.WriteString("* ") builder.WriteString("* ")
builder.WriteString(" matched at ") builder.WriteString(" matched at ")
builder.WriteString(output.Host) builder.WriteString(event.Host)
builder.WriteString("\n\n*Protocol*: ") 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("\n\n*Full URL*: ")
builder.WriteString(output.Matched) builder.WriteString(event.Matched)
builder.WriteString("\n\n*Timestamp*: ") 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") 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(fmt.Sprintf("| %s | %s |\n", k, v))
} }
builder.WriteString("\n*Request*\n\n{code}\n") 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("\n{code}\n\n*Response*\n\n{code}\n")
builder.WriteString(output.Response) builder.WriteString(event.Response)
builder.WriteString("\n{code}\n\n") 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") builder.WriteString("*Extra Information*\n\n")
if len(output.ExtractedResults) > 0 { if len(event.ExtractedResults) > 0 {
builder.WriteString("*Extracted results*:\n\n") builder.WriteString("*Extracted results*:\n\n")
for _, v := range output.ExtractedResults { for _, v := range event.ExtractedResults {
builder.WriteString("- ") builder.WriteString("- ")
builder.WriteString(v) builder.WriteString(v)
builder.WriteString("\n") builder.WriteString("\n")
} }
builder.WriteString("\n") builder.WriteString("\n")
} }
if len(output.Metadata) > 0 { if len(event.Metadata) > 0 {
builder.WriteString("*Metadata*:\n\n") builder.WriteString("*Metadata*:\n\n")
for k, v := range output.Metadata { for k, v := range event.Metadata {
builder.WriteString("- ") builder.WriteString("- ")
builder.WriteString(k) builder.WriteString(k)
builder.WriteString(": ") builder.WriteString(": ")

View File

@ -18,6 +18,7 @@ import (
) )
// Parse parses a yaml request template file // Parse parses a yaml request template file
//nolint:gocritic // this cannot be passed by pointer
func Parse(filePath string, options protocols.ExecuterOptions) (*Template, error) { func Parse(filePath string, options protocols.ExecuterOptions) (*Template, error) {
template := &Template{} template := &Template{}
@ -84,12 +85,12 @@ func Parse(filePath string, options protocols.ExecuterOptions) (*Template, error
} }
if len(template.RequestsHTTP) > 0 { if len(template.RequestsHTTP) > 0 {
if options.Options.OfflineHTTP { if options.Options.OfflineHTTP {
operators := []*operators.Operators{} operatorsList := []*operators.Operators{}
for _, req := range template.RequestsHTTP { 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) template.Executer = executer.NewExecuter([]protocols.Request{&offlinehttp.Request{}}, &options)
} else { } else {
for _, req := range template.RequestsHTTP { for _, req := range template.RequestsHTTP {
@ -130,8 +131,8 @@ func Parse(filePath string, options protocols.ExecuterOptions) (*Template, error
} }
// compileWorkflow compiles the workflow for execution // compileWorkflow compiles the workflow for execution
func (t *Template) compileWorkflow(options *protocols.ExecuterOptions, workflows *workflows.Workflow) error { func (t *Template) compileWorkflow(options *protocols.ExecuterOptions, workflow *workflows.Workflow) error {
for _, workflow := range workflows.Workflows { for _, workflow := range workflow.Workflows {
if err := t.parseWorkflow(workflow, options); err != nil { if err := t.parseWorkflow(workflow, options); err != nil {
return err return err
} }
@ -161,7 +162,7 @@ func (t *Template) parseWorkflow(workflow *workflows.WorkflowTemplate, options *
// parseWorkflowTemplate parses a workflow template creating an executer // parseWorkflowTemplate parses a workflow template creating an executer
func (t *Template) parseWorkflowTemplate(workflow *workflows.WorkflowTemplate, options *protocols.ExecuterOptions) error { 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 { if err != nil {
return errors.Wrap(err, "could not get workflow template") return errors.Wrap(err, "could not get workflow template")
} }
@ -170,7 +171,7 @@ func (t *Template) parseWorkflowTemplate(workflow *workflows.WorkflowTemplate, o
Output: options.Output, Output: options.Output,
Options: options.Options, Options: options.Options,
Progress: options.Progress, Progress: options.Progress,
Catalogue: options.Catalogue, Catalog: options.Catalog,
RateLimiter: options.RateLimiter, RateLimiter: options.RateLimiter,
IssuesClient: options.IssuesClient, IssuesClient: options.IssuesClient,
ProjectFile: options.ProjectFile, ProjectFile: options.ProjectFile,
@ -220,9 +221,7 @@ mainLoop:
} }
// getKeyValue returns key value pair for a data string // getKeyValue returns key value pair for a data string
func getKeyValue(data string) (string, string) { func getKeyValue(data string) (key, value string) {
var key, value string
if strings.Contains(data, ":") { if strings.Contains(data, ":") {
parts := strings.SplitN(data, ":", 2) parts := strings.SplitN(data, ":", 2)
if len(parts) == 2 { if len(parts) == 2 {

View File

@ -34,7 +34,7 @@ func ToString(data interface{}) string {
case uint: case uint:
return strconv.FormatUint(uint64(s), 10) return strconv.FormatUint(uint64(s), 10)
case uint64: case uint64:
return strconv.FormatUint(uint64(s), 10) return strconv.FormatUint(s, 10)
case uint32: case uint32:
return strconv.FormatUint(uint64(s), 10) return strconv.FormatUint(uint64(s), 10)
case uint16: case uint16:

View File

@ -4,6 +4,69 @@ import "github.com/projectdiscovery/goflags"
// Options contains the configuration options for nuclei scanner. // Options contains the configuration options for nuclei scanner.
type Options struct { 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 generates random User-Agent
RandomAgent bool RandomAgent bool
// Metrics enables display of metrics via an http endpoint // Metrics enables display of metrics via an http endpoint
@ -42,68 +105,4 @@ type Options struct {
NoMeta bool NoMeta bool
// Project is used to avoid sending same HTTP request multiple times // Project is used to avoid sending same HTTP request multiple times
Project bool 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.
} }

View File

@ -12,11 +12,11 @@ import (
) )
func TestWorkflowsSimple(t *testing.T) { 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{ workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{
{Executers: []*ProtocolExecuterPair{{ {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) { func TestWorkflowsSimpleMultiple(t *testing.T) {
progress, _ := progress.NewProgress(0, false, false, 0) progressBar, _ := progress.NewProgress(0, false, false, 0)
var firstInput, secondInput string var firstInput, secondInput string
workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{
{Executers: []*ProtocolExecuterPair{{ {Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: true, executeHook: func(input string) { Executer: &mockExecuter{result: true, executeHook: func(input string) {
firstInput = input firstInput = input
}}, Options: &protocols.ExecuterOptions{Progress: progress}}, }}, Options: &protocols.ExecuterOptions{Progress: progressBar}},
}}, }},
{Executers: []*ProtocolExecuterPair{{ {Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: true, executeHook: func(input string) { Executer: &mockExecuter{result: true, executeHook: func(input string) {
secondInput = input 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) { func TestWorkflowsSubtemplates(t *testing.T) {
progress, _ := progress.NewProgress(0, false, false, 0) progressBar, _ := progress.NewProgress(0, false, false, 0)
var firstInput, secondInput string var firstInput, secondInput string
workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{
{Executers: []*ProtocolExecuterPair{{ {Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: true, executeHook: func(input string) { Executer: &mockExecuter{result: true, executeHook: func(input string) {
firstInput = input firstInput = input
}}, Options: &protocols.ExecuterOptions{Progress: progress}}, }}, Options: &protocols.ExecuterOptions{Progress: progressBar}},
}, Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ }, Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: true, executeHook: func(input string) { Executer: &mockExecuter{result: true, executeHook: func(input string) {
secondInput = input 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) { func TestWorkflowsSubtemplatesNoMatch(t *testing.T) {
progress, _ := progress.NewProgress(0, false, false, 0) progressBar, _ := progress.NewProgress(0, false, false, 0)
var firstInput, secondInput string var firstInput, secondInput string
workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{
{Executers: []*ProtocolExecuterPair{{ {Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: false, executeHook: func(input string) { Executer: &mockExecuter{result: false, executeHook: func(input string) {
firstInput = input firstInput = input
}}, Options: &protocols.ExecuterOptions{Progress: progress}}, }}, Options: &protocols.ExecuterOptions{Progress: progressBar}},
}, Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ }, Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: true, executeHook: func(input string) { Executer: &mockExecuter{result: true, executeHook: func(input string) {
secondInput = input 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) { func TestWorkflowsSubtemplatesWithMatcher(t *testing.T) {
progress, _ := progress.NewProgress(0, false, false, 0) progressBar, _ := progress.NewProgress(0, false, false, 0)
var firstInput, secondInput string var firstInput, secondInput string
workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ 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": {}}, Matches: map[string]struct{}{"tomcat": {}},
Extracts: map[string][]string{}, Extracts: map[string][]string{},
}}, }},
}}, Options: &protocols.ExecuterOptions{Progress: progress}}, }}, Options: &protocols.ExecuterOptions{Progress: progressBar}},
}, Matchers: []*Matcher{{Name: "tomcat", Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ }, Matchers: []*Matcher{{Name: "tomcat", Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: true, executeHook: func(input string) { Executer: &mockExecuter{result: true, executeHook: func(input string) {
secondInput = input 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) { func TestWorkflowsSubtemplatesWithMatcherNoMatch(t *testing.T) {
progress, _ := progress.NewProgress(0, false, false, 0) progressBar, _ := progress.NewProgress(0, false, false, 0)
var firstInput, secondInput string var firstInput, secondInput string
workflow := &Workflow{Options: &protocols.ExecuterOptions{Options: &types.Options{TemplateThreads: 10}}, Workflows: []*WorkflowTemplate{ 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": {}}, Matches: map[string]struct{}{"tomcat": {}},
Extracts: map[string][]string{}, Extracts: map[string][]string{},
}}, }},
}}, Options: &protocols.ExecuterOptions{Progress: progress}}, }}, Options: &protocols.ExecuterOptions{Progress: progressBar}},
}, Matchers: []*Matcher{{Name: "apache", Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{ }, Matchers: []*Matcher{{Name: "apache", Subtemplates: []*WorkflowTemplate{{Executers: []*ProtocolExecuterPair{{
Executer: &mockExecuter{result: true, executeHook: func(input string) { Executer: &mockExecuter{result: true, executeHook: func(input string) {
secondInput = input secondInput = input
}}, Options: &protocols.ExecuterOptions{Progress: progress}}, }}, Options: &protocols.ExecuterOptions{Progress: progressBar}},
}}}}}}, }}}}}},
}} }}