mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 17:45:28 +00:00
Lint errors fix
This commit is contained in:
parent
b33bc83b0b
commit
8512b684c5
3
.gitignore
vendored
3
.gitignore
vendored
@ -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
|
||||||
@ -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
|
||||||
|
|||||||
@ -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()
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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=
|
||||||
|
|||||||
@ -8,8 +8,7 @@ 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
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@ -278,15 +278,14 @@ func (r *Runner) downloadReleaseAndUnzip(ctx context.Context, version, downloadU
|
|||||||
|
|
||||||
// If we don't find a previous file in new download and it hasn't been
|
// 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] {
|
os.Remove(k)
|
||||||
os.Remove(k)
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
14
v2/pkg/catalog/catalogue.go
Normal file
14
v2/pkg/catalog/catalogue.go
Normal 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
|
||||||
|
}
|
||||||
@ -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,
|
||||||
@ -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 {
|
||||||
@ -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/"}
|
||||||
|
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 != "" {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.
|
CompiledOperators *operators.Operators
|
||||||
operators.Operators `yaml:",inline"`
|
dnsClient *retryabledns.Client
|
||||||
CompiledOperators *operators.Operators
|
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
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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 {
|
||||||
ID string `yaml:"id"`
|
// Operators for the current request go here.
|
||||||
|
operators.Operators `yaml:",inline"`
|
||||||
// MaxSize is the maximum size of the file to run request on.
|
|
||||||
// By default, nuclei will process 5MB files and not go more than that.
|
|
||||||
// It can be set to much lower or higher depending on use.
|
|
||||||
MaxSize int `yaml:"max-size"`
|
|
||||||
// NoRecursive specifies whether to not do recursive checks if folders are provided.
|
|
||||||
NoRecursive bool `yaml:"no-recursive"`
|
|
||||||
// Extensions is the list of extensions to perform matching on.
|
// Extensions is the list of extensions to perform matching on.
|
||||||
Extensions []string `yaml:"extensions"`
|
Extensions []string `yaml:"extensions"`
|
||||||
// ExtensionDenylist is the list of file extensions to deny during matching.
|
// ExtensionDenylist is the list of file extensions to deny during matching.
|
||||||
ExtensionDenylist []string `yaml:"denylist"`
|
ExtensionDenylist []string `yaml:"denylist"`
|
||||||
|
|
||||||
// Operators for the current request go here.
|
ID string `yaml:"id"`
|
||||||
operators.Operators `yaml:",inline"`
|
|
||||||
CompiledOperators *operators.Operators
|
// MaxSize is the maximum size of the file to run request on.
|
||||||
|
// By default, nuclei will process 5MB files and not go more than that.
|
||||||
|
// It can be set to much lower or higher depending on use.
|
||||||
|
MaxSize int `yaml:"max-size"`
|
||||||
|
CompiledOperators *operators.Operators
|
||||||
|
|
||||||
// cache any variables that may be needed for operation.
|
// 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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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" {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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{}
|
||||||
|
|||||||
@ -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")
|
||||||
|
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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(": ")
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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.
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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}},
|
||||||
}}}}}},
|
}}}}}},
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user