diff --git a/.github/workflows/publish-docs.yaml b/.github/workflows/publish-docs.yaml index 4f534d428..e114e3797 100644 --- a/.github/workflows/publish-docs.yaml +++ b/.github/workflows/publish-docs.yaml @@ -2,7 +2,9 @@ name: ⏰ Publish Docs on: push: - pull_request: + branches: + - master + - dev workflow_dispatch: jobs: diff --git a/SYNTAX-REFERENCE.md b/SYNTAX-REFERENCE.md index a50d97658..cdb81ba4e 100755 --- a/SYNTAX-REFERENCE.md +++ b/SYNTAX-REFERENCE.md @@ -282,7 +282,7 @@ name: Nagios Default Credentials Check
-author StringSlice +author stringslice.StringSlice
@@ -307,7 +307,7 @@ author:
-tags StringSlice +tags stringslice.StringSlice
@@ -362,7 +362,7 @@ description: Subversion ALM for the enterprise before 8.8.2 allows reflected XSS
-reference StringSlice +reference stringslice.StringSlice
@@ -389,7 +389,7 @@ reference:
@@ -437,22 +437,90 @@ additional-fields:
+
+ +classification model.Classification + +
+
+ +Classification contains classification information about the template. + +
+ +
+ +
+ +remediation string + +
+
+ +Remediation steps for the template. + +You can go in-depth here on how to mitigate the problem found by this template. + + + +Examples: + + +```yaml +remediation: Change the default administrative username and password of Apache ActiveMQ by editing the file jetty-realm.properties +``` + + +
+ +
-## model.StringSlice + +## stringslice.StringSlice +StringSlice represents a single (in-lined) or multiple string value(s). + The unmarshaller does not automatically convert in-lined strings to []string, hence the interface{} type is required. Appears in: +- model.Info.author + +- model.Info.tags + +- model.Info.reference + +- model.Classification.cve-id + +- model.Classification.cwe-id + - workflows.WorkflowTemplate.tags +```yaml + +``` +```yaml +# Example tags +cve,cve2019,grafana,auth-bypass,dos +``` +```yaml +- https://github.com/strapi/strapi +- https://github.com/getgrav/grav +``` +```yaml +CVE-2020-14420 +``` +```yaml +CWE-22 +``` -## severity.SeverityHolder +## severity.Holder +Holder holds a Severity type. Required for un/marshalling purposes Appears in: @@ -463,6 +531,113 @@ Appears in: +## model.Classification + +Appears in: + + +- model.Info.classification + + + +
+ + +
+ +CVE ID for the template + + + +Examples: + + +```yaml +cve-id: CVE-2020-14420 +``` + + +
+ +
+ + +
+ +CWE ID for the template. + + + +Examples: + + +```yaml +cwe-id: CWE-22 +``` + + +
+ +
+ +
+ +cvss-metrics string + +
+
+ +CVSS Metrics for the template. + + + +Examples: + + +```yaml +cvss-metrics: 3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H +``` + + +
+ +
+ +
+ +cvss-score float64 + +
+
+ +CVSS Score for the template. + + + +Examples: + + +```yaml +cvss-score: "9.8" +``` + + +
+ +
+ + + + + ## http.Request Request contains a http request to be made from a template @@ -2617,7 +2792,7 @@ template: misconfigurations/aem
diff --git a/nuclei-jsonschema.json b/nuclei-jsonschema.json index 6092a125a..c26306c6a 100755 --- a/nuclei-jsonschema.json +++ b/nuclei-jsonschema.json @@ -2,17 +2,34 @@ "$schema": "http://json-schema.org/draft-04/schema#", "$ref": "#/definitions/templates.Template", "definitions": { - "severity.SeverityHolder": { - "enum": [ - "info", - "low", - "medium", - "high", - "critical" - ], - "type": "string", - "title": "severity of the template", - "description": "Seriousness of the implications of the template" + "model.Classification": { + "properties": { + "cve-id": { + "$ref": "#/definitions/stringslice.StringSlice", + "title": "cve ids for the template", + "description": "CVE IDs for the template" + }, + "cwe-id": { + "$ref": "#/definitions/stringslice.StringSlice", + "title": "cwe ids for the template", + "description": "CWE IDs for the template" + }, + "cvss-metrics": { + "type": "string", + "title": "cvss metrics for the template", + "description": "CVSS Metrics for the template", + "examples": [ + "3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + ] + }, + "cvss-score": { + "type": "number", + "title": "cvss score for the template", + "description": "CVSS Score for the template" + } + }, + "additionalProperties": false, + "type": "object" }, "model.Info": { "properties": { @@ -26,12 +43,12 @@ }, "author": { "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/model.StringSlice", + "$ref": "#/definitions/stringslice.StringSlice", "title": "author of the template", "description": "Author is the author of the template" }, "tags": { - "$ref": "#/definitions/model.StringSlice", + "$ref": "#/definitions/stringslice.StringSlice", "title": "tags of the template", "description": "Any tags for the template" }, @@ -44,13 +61,13 @@ ] }, "reference": { - "$ref": "#/definitions/model.StringSlice", + "$ref": "#/definitions/stringslice.StringSlice", "title": "references for the template", "description": "Links relevant to the template" }, "severity": { "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/severity.SeverityHolder" + "$ref": "#/definitions/severity.Holder" }, "additional-fields": { "patternProperties": { @@ -61,12 +78,38 @@ "type": "object", "title": "additional metadata for the template", "description": "Additional metadata fields for the template" + }, + "classification": { + "$schema": "http://json-schema.org/draft-04/schema#", + "$ref": "#/definitions/model.Classification", + "title": "classification info for the template", + "description": "Classification information for the template" + }, + "remediation": { + "type": "string", + "title": "remediation steps for the template", + "description": "In-depth explanation on how to fix the issues found by the template", + "examples": [ + "Change the default administrative username and password of Apache ActiveMQ by editing the file jetty-realm.properties" + ] } }, "additionalProperties": false, "type": "object" }, - "model.StringSlice": { + "severity.Holder": { + "enum": [ + "info", + "low", + "medium", + "high", + "critical" + ], + "type": "string", + "title": "severity of the template", + "description": "Seriousness of the implications of the template" + }, + "stringslice.StringSlice": { "oneOf": [ { "type": "string" @@ -885,7 +928,7 @@ "description": "Template or directory to execute as part of workflow" }, "tags": { - "$ref": "#/definitions/model.StringSlice", + "$ref": "#/definitions/stringslice.StringSlice", "title": "tags to execute", "description": "Tags to run template based on" }, diff --git a/v2/cmd/cve-annotate/main.go b/v2/cmd/cve-annotate/main.go new file mode 100644 index 000000000..3a0f1ddf8 --- /dev/null +++ b/v2/cmd/cve-annotate/main.go @@ -0,0 +1,159 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "regexp" + "strings" + + "github.com/Ice3man543/nvd" + "github.com/projectdiscovery/nuclei/v2/pkg/catalog" +) + +var ( + input = flag.String("i", "", "Templates to annotate") + templateDir = flag.String("d", "", "Custom template directory for update") +) + +func main() { + flag.Parse() + + if *input == "" || *templateDir == "" { + log.Fatalf("invalid input, see -h\n") + } + + if err := process(); err != nil { + log.Fatalf("could not process: %s\n", err) + } +} + +func process() error { + tempDir, err := ioutil.TempDir("", "nuclei-nvd-%s") + if err != nil { + return err + } + defer os.RemoveAll(tempDir) + + client, err := nvd.NewClient(tempDir) + if err != nil { + return err + } + catalog := catalog.New(*templateDir) + + paths, err := catalog.GetTemplatePath(*input) + if err != nil { + return err + } + for _, path := range paths { + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + getCVEData(client, path, string(data)) + } + return nil +} + +var ( + idRegex = regexp.MustCompile("id: ([C|c][V|v][E|e]-[0-9]+-[0-9]+)") + severityRegex = regexp.MustCompile(`severity: ([a-z]+)`) +) + +func getCVEData(client *nvd.Client, filePath, data string) { + matches := idRegex.FindAllStringSubmatch(data, 1) + if len(matches) == 0 { + return + } + cveName := matches[0][1] + + severityMatches := severityRegex.FindAllStringSubmatch(data, 1) + if len(matches) == 0 { + return + } + severityValue := severityMatches[0][1] + + cveItem, err := client.FetchCVE(cveName) + if err != nil { + log.Printf("Could not fetch cve %s: %s\n", cveName, err) + return + } + var cweID []string + for _, problemData := range cveItem.CVE.Problemtype.ProblemtypeData { + for _, description := range problemData.Description { + cweID = append(cweID, description.Value) + } + } + cvssScore := cveItem.Impact.BaseMetricV3.CvssV3.BaseScore + cvssMetrics := cveItem.Impact.BaseMetricV3.CvssV3.VectorString + + // Perform some hacky string replacement to place the metadata in templates + infoBlockIndexData := data[strings.Index(data, "info:"):] + requestsIndex := strings.Index(infoBlockIndexData, "requests:") + networkIndex := strings.Index(infoBlockIndexData, "network:") + if requestsIndex == -1 && networkIndex == -1 { + return + } + if networkIndex != -1 { + requestsIndex = networkIndex + } + infoBlockData := infoBlockIndexData[:requestsIndex] + infoBlockClean := strings.TrimRight(infoBlockData, "\n") + + newInfoBlock := infoBlockClean + var changed bool + + if newSeverity := isSeverityMatchingCvssScore(severityValue, cvssScore); newSeverity != "" { + changed = true + newInfoBlock = strings.ReplaceAll(newInfoBlock, severityMatches[0][0], "severity: "+newSeverity) + fmt.Printf("Adjusting severity for %s from %s=>%s (%.2f)\n", filePath, severityValue, newSeverity, cvssScore) + } + // Start with additional-fields as that is the one most likely to break stuff. + if !strings.Contains(infoBlockClean, "classification") && (cvssScore != 0 && cvssMetrics != "") { + changed = true + newInfoBlock = newInfoBlock + fmt.Sprintf("\n classification:\n cvss-metrics: %s\n cvss-score: %.2f\n cve-id: %s", cvssMetrics, cvssScore, cveName) + if len(cweID) > 0 && (cweID[0] != "NVD-CWE-Other" && cweID[0] != "NVD-CWE-noinfo") { + newInfoBlock = newInfoBlock + fmt.Sprintf("\n cwe-id: %s", strings.Join(cweID, ",")) + } + } + // If there is no description field, fill the description from CVE information + if !strings.Contains(infoBlockClean, "description:") { + changed = true + newInfoBlock = newInfoBlock + fmt.Sprintf("\n description: %s", fmt.Sprintf("%q", cveItem.CVE.Description.DescriptionData[0].Value)) + } + if !strings.Contains(infoBlockClean, "reference:") && len(cveItem.CVE.References.ReferenceData) > 0 { + changed = true + newInfoBlock = newInfoBlock + "\n reference:" + for _, reference := range cveItem.CVE.References.ReferenceData { + newInfoBlock = newInfoBlock + fmt.Sprintf("\n - %s", reference.URL) + } + } + newTemplate := strings.ReplaceAll(data, infoBlockClean, newInfoBlock) + if changed { + _ = ioutil.WriteFile(filePath, []byte(newTemplate), 0777) + fmt.Printf("Wrote updated template to %s\n", filePath) + } +} + +func isSeverityMatchingCvssScore(severity string, score float64) string { + if score == 0.0 { + return "" + } + var expected string + + if score >= 0.1 && score <= 3.9 { + expected = "low" + } else if score >= 4.0 && score <= 6.9 { + expected = "medium" + } else if score >= 7.0 && score <= 8.9 { + expected = "high" + } else if score >= 9.0 && score <= 10.0 { + expected = "critical" + } + if expected != "" && expected != severity { + return expected + } + return "" +} diff --git a/v2/go.mod b/v2/go.mod index a509f4c29..7a2b6c457 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -3,6 +3,7 @@ module github.com/projectdiscovery/nuclei/v2 go 1.16 require ( + github.com/Ice3man543/nvd v1.0.6 github.com/Knetic/govaluate v3.0.0+incompatible github.com/akrylysov/pogreb v0.10.1 // indirect github.com/alecthomas/jsonschema v0.0.0-20210818095345-1014919a589c @@ -13,7 +14,6 @@ require ( github.com/bluele/gcache v0.0.2 github.com/c4milo/unpackit v0.1.0 // indirect github.com/corpix/uarand v0.1.1 - github.com/davecgh/go-spew v1.1.1 github.com/go-rod/rod v0.91.1 github.com/google/go-github v17.0.0+incompatible github.com/gosuri/uilive v0.0.4 // indirect diff --git a/v2/go.sum b/v2/go.sum index 97e87b5d9..37e3bc6cb 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -37,6 +37,8 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIo github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Ice3man543/nvd v1.0.6 h1:QnCqnuYAA9tY2F38oNXp/kFV5fnYq+44mmcDFhKyawc= +github.com/Ice3man543/nvd v1.0.6/go.mod h1:0DxLJk6revOcJKiZxa2K+rNF/HO1zJO97lqQtXhXfSc= github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic= @@ -45,9 +47,10 @@ github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHS github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/PuerkitoBio/goquery v1.6.0 h1:j7taAbelrdcsOlGeMenZxc2AWXD5fieT1/znArdnx94= +github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/akrylysov/pogreb v0.10.0 h1:pVKi+uf3EzZUmiwr9bZnPk4W379KP8QsFzAa9IUuOog= github.com/akrylysov/pogreb v0.10.0/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w= github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= @@ -55,6 +58,8 @@ github.com/alecthomas/jsonschema v0.0.0-20210818095345-1014919a589c h1:oJsq4z4xK github.com/alecthomas/jsonschema v0.0.0-20210818095345-1014919a589c/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= +github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andygrunwald/go-jira v1.14.0 h1:7GT/3qhar2dGJ0kq8w0d63liNyHOnxZsUZ9Pe4+AKBI= github.com/andygrunwald/go-jira v1.14.0/go.mod h1:KMo2f4DgMZA1C9FdImuLc04x4WQhn5derQpnsuBFgqE= github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M= @@ -96,6 +101,8 @@ github.com/corpix/uarand v0.1.1 h1:RMr1TWc9F4n5jiPDzFHtmaUXLKLNUFK0SgCLo4BhX/U= github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/daehee/nvd v1.0.4 h1:qC0kJ68vAYS86v8GwBORReBhyC5yUaUzsBokxjlsT98= +github.com/daehee/nvd v1.0.4/go.mod h1:iBRJHIdIs+ylfq8630my2eMw8kwzH4Z7qsetjJZxCzs= github.com/dave/dst v0.26.2 h1:lnxLAKI3tx7MgLNVDirFCsDTlTG9nKTk7GcptKcWSwY= github.com/dave/dst v0.26.2/go.mod h1:UMDJuIRPfyUCC78eFuB+SV/WI8oDeyFDvM/JR6NI3IU= github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ= @@ -229,7 +236,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/itchyny/go-flags v1.5.0/go.mod h1:lenkYuCobuxLBAd/HGFE4LRoW8D3B6iXRQfWYJ+MNbA= github.com/itchyny/gojq v0.12.4 h1:8zgOZWMejEWCLjbF/1mWY7hY7QEARm7dtuhC6Bp4R8o= @@ -276,13 +282,11 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -510,6 +514,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -614,7 +619,6 @@ golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -705,7 +709,6 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/v2/internal/runner/banner.go b/v2/internal/runner/banner.go index eed5277d8..b75f09c33 100644 --- a/v2/internal/runner/banner.go +++ b/v2/internal/runner/banner.go @@ -20,6 +20,6 @@ func showBanner() { gologger.Print().Msgf("%s\n", banner) gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n") - gologger.Error().Label("WRN").Msgf("Use with caution. You are responsible for your actions\n") + gologger.Error().Label("WRN").Msgf("Use with caution. You are responsible for your actions.\n") gologger.Error().Label("WRN").Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n") } diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go index 2617c90c2..c2c791e8b 100644 --- a/v2/internal/runner/runner.go +++ b/v2/internal/runner/runner.go @@ -189,7 +189,7 @@ func New(options *types.Options) (*Runner, error) { } // Create the output file if asked - outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.NoTimestamp, options.JSON, options.Output, options.TraceLogFile) + outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.NoTimestamp, options.JSON, options.JSONRequests, options.Output, options.TraceLogFile) if err != nil { return nil, errors.Wrap(err, "could not create output file") } @@ -439,7 +439,7 @@ func (r *Runner) RunEnumeration() error { } templatesMap := make(map[string]*templates.Template) for _, v := range store.Templates() { - templatesMap[v.ID] = v + templatesMap[v.Path] = v } originalTemplatesCount := len(store.Templates()) clusterCount := 0 @@ -471,6 +471,7 @@ func (r *Runner) RunEnumeration() error { finalTemplates = append(finalTemplates, cluster...) } } + finalTemplates = append(finalTemplates, store.Workflows()...) var totalRequests int64 diff --git a/v2/nuclei-jsonschema.json b/v2/nuclei-jsonschema.json deleted file mode 100755 index 6092a125a..000000000 --- a/v2/nuclei-jsonschema.json +++ /dev/null @@ -1,914 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/templates.Template", - "definitions": { - "severity.SeverityHolder": { - "enum": [ - "info", - "low", - "medium", - "high", - "critical" - ], - "type": "string", - "title": "severity of the template", - "description": "Seriousness of the implications of the template" - }, - "model.Info": { - "properties": { - "name": { - "type": "string", - "title": "name of the template", - "description": "Name is a short summary of what the template does", - "examples": [ - "Nagios Default Credentials Check" - ] - }, - "author": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/model.StringSlice", - "title": "author of the template", - "description": "Author is the author of the template" - }, - "tags": { - "$ref": "#/definitions/model.StringSlice", - "title": "tags of the template", - "description": "Any tags for the template" - }, - "description": { - "type": "string", - "title": "description of the template", - "description": "In-depth explanation on what the template does", - "examples": [ - "Bower is a package manager which stores packages informations in bower.json file" - ] - }, - "reference": { - "$ref": "#/definitions/model.StringSlice", - "title": "references for the template", - "description": "Links relevant to the template" - }, - "severity": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/severity.SeverityHolder" - }, - "additional-fields": { - "patternProperties": { - ".*": { - "type": "string" - } - }, - "type": "object", - "title": "additional metadata for the template", - "description": "Additional metadata fields for the template" - } - }, - "additionalProperties": false, - "type": "object" - }, - "model.StringSlice": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "array" - } - ] - }, - "extractors.Extractor": { - "required": [ - "type" - ], - "properties": { - "name": { - "type": "string", - "title": "name of the extractor", - "description": "Name of the extractor" - }, - "type": { - "enum": [ - "regex", - "kval", - "json", - "xpath" - ], - "type": "string", - "title": "type of the extractor", - "description": "Type of the extractor" - }, - "regex": { - "items": { - "type": "string" - }, - "type": "array", - "title": "regex to extract from part", - "description": "Regex to extract from part" - }, - "group": { - "type": "integer", - "title": "group to extract from regex", - "description": "Group to extract from regex" - }, - "kval": { - "items": { - "type": "string" - }, - "type": "array", - "title": "kval pairs to extract from response", - "description": "Kval pairs to extract from response" - }, - "json": { - "items": { - "type": "string" - }, - "type": "array", - "title": "json jq expressions to extract data", - "description": "JSON JQ expressions to evaluate from response part" - }, - "xpath": { - "items": { - "type": "string" - }, - "type": "array", - "title": "html xpath expressions to extract data", - "description": "XPath allows using xpath expressions to extract items from html response" - }, - "attribute": { - "type": "string", - "title": "optional attribute to extract from xpath", - "description": "Optional attribute to extract from response XPath" - }, - "part": { - "type": "string", - "title": "part of response to extract data from", - "description": "Part of the request response to extract data from" - }, - "internal": { - "type": "boolean", - "title": "mark extracted value for internal variable use", - "description": "Internal when set to true will allow using the value extracted in the next request for some protocols" - } - }, - "additionalProperties": false, - "type": "object" - }, - "matchers.Matcher": { - "required": [ - "type" - ], - "properties": { - "type": { - "enum": [ - "status", - "size", - "word", - "regex", - "dsl" - ], - "type": "string", - "title": "type of matcher", - "description": "Type of the matcher" - }, - "condition": { - "enum": [ - "and", - "or" - ], - "type": "string", - "title": "condition between matcher variables", - "description": "Condition between the matcher variables" - }, - "part": { - "type": "string", - "title": "part of response to match", - "description": "Part of response to match data from" - }, - "negative": { - "type": "boolean", - "title": "negative specifies if match reversed", - "description": "Negative specifies if the match should be reversed. It will only match if the condition is not true" - }, - "name": { - "type": "string", - "title": "name of the matcher", - "description": "Name of the matcher" - }, - "status": { - "items": { - "type": "integer" - }, - "type": "array", - "title": "status to match", - "description": "Status to match for the response" - }, - "size": { - "items": { - "type": "integer" - }, - "type": "array", - "title": "acceptable size for response", - "description": "Size is the acceptable size for the response" - }, - "words": { - "items": { - "type": "string" - }, - "type": "array", - "title": "words to match in response", - "description": " Words contains word patterns required to be present in the response part" - }, - "regex": { - "items": { - "type": "string" - }, - "type": "array", - "title": "regex to match in response", - "description": "Regex contains regex patterns required to be present in the response part" - }, - "binary": { - "items": { - "type": "string" - }, - "type": "array", - "title": "binary patterns to match in response", - "description": "Binary are the binary patterns required to be present in the response part" - }, - "dsl": { - "items": { - "type": "string" - }, - "type": "array", - "title": "dsl expressions to match in response", - "description": "DSL are the dsl expressions that will be evaluated as part of nuclei matching rules" - }, - "encoding": { - "enum": [ - "hex" - ], - "type": "string", - "title": "encoding for word field", - "description": "Optional encoding for the word fields" - } - }, - "additionalProperties": false, - "type": "object" - }, - "dns.Request": { - "properties": { - "matchers": { - "items": { - "$ref": "#/definitions/matchers.Matcher" - }, - "type": "array", - "title": "matchers to run on response", - "description": "Detection mechanism to identify whether the request was successful by doing pattern matching" - }, - "extractors": { - "items": { - "$ref": "#/definitions/extractors.Extractor" - }, - "type": "array", - "title": "extractors to run on response", - "description": "Extractors contains the extraction mechanism for the request to identify and extract parts of the response" - }, - "matchers-condition": { - "enum": [ - "and", - "or" - ], - "type": "string", - "title": "condition between the matchers", - "description": "Conditions between the matchers" - }, - "id": { - "type": "string", - "title": "id of the dns request", - "description": "ID is the optional ID of the DNS Request" - }, - "name": { - "type": "string", - "title": "hostname to make dns request for", - "description": "Name is the Hostname to make DNS request for" - }, - "type": { - "enum": [ - "A", - "NS", - "DS", - "CNAME", - "SOA", - "PTR", - "MX", - "TXT", - "AAAA" - ], - "type": "string", - "title": "type of dns request to make", - "description": "Type is the type of DNS request to make" - }, - "class": { - "enum": [ - "inet", - "csnet", - "chaos", - "hesiod", - "none", - "any" - ], - "type": "string", - "title": "class of DNS request", - "description": "Class is the class of the DNS request" - }, - "retries": { - "type": "integer", - "title": "retries for dns request", - "description": "Retries is the number of retries for the DNS request" - }, - "recursion": { - "type": "boolean", - "title": "recurse all servers", - "description": "Recursion determines if resolver should recurse all records to get fresh results" - } - }, - "additionalProperties": false, - "type": "object" - }, - "file.Request": { - "properties": { - "matchers": { - "items": { - "$ref": "#/definitions/matchers.Matcher" - }, - "type": "array", - "title": "matchers to run on response", - "description": "Detection mechanism to identify whether the request was successful by doing pattern matching" - }, - "extractors": { - "items": { - "$ref": "#/definitions/extractors.Extractor" - }, - "type": "array", - "title": "extractors to run on response", - "description": "Extractors contains the extraction mechanism for the request to identify and extract parts of the response" - }, - "matchers-condition": { - "enum": [ - "and", - "or" - ], - "type": "string", - "title": "condition between the matchers", - "description": "Conditions between the matchers" - }, - "extensions": { - "items": { - "type": "string" - }, - "type": "array", - "title": "extensions to match", - "description": "List of extensions to perform matching on" - }, - "denylist": { - "items": { - "type": "string" - }, - "type": "array", - "title": "extensions to deny match", - "description": "List of file extensions to deny during matching" - }, - "id": { - "type": "string", - "title": "id of the request", - "description": "ID is the optional ID for the request" - }, - "max-size": { - "type": "integer", - "title": "max size data to run request on", - "description": "Maximum size of the file to run request on" - }, - "no-recursive": { - "type": "boolean", - "title": "do not perform recursion", - "description": "Specifies whether to not do recursive checks if folders are provided" - } - }, - "additionalProperties": false, - "type": "object" - }, - "headless.Request": { - "properties": { - "id": { - "type": "string", - "title": "id of the request", - "description": "Optional ID of the headless request" - }, - "steps": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/engine.Action" - }, - "type": "array", - "title": "list of actions for headless request", - "description": "List of actions to run for headless request" - }, - "matchers": { - "items": { - "$ref": "#/definitions/matchers.Matcher" - }, - "type": "array", - "title": "matchers to run on response", - "description": "Detection mechanism to identify whether the request was successful by doing pattern matching" - }, - "extractors": { - "items": { - "$ref": "#/definitions/extractors.Extractor" - }, - "type": "array", - "title": "extractors to run on response", - "description": "Extractors contains the extraction mechanism for the request to identify and extract parts of the response" - }, - "matchers-condition": { - "enum": [ - "and", - "or" - ], - "type": "string", - "title": "condition between the matchers", - "description": "Conditions between the matchers" - } - }, - "additionalProperties": false, - "type": "object" - }, - "engine.Action": { - "required": [ - "action" - ], - "properties": { - "args": { - "patternProperties": { - ".*": { - "type": "string" - } - }, - "type": "object", - "title": "arguments for headless action", - "description": "Args contain arguments for the headless action" - }, - "name": { - "type": "string", - "title": "name for headless action", - "description": "Name is the name assigned to the headless action" - }, - "description": { - "type": "string", - "title": "description for headless action", - "description": "Description of the headless action" - }, - "action": { - "enum": [ - "navigate", - "script", - "click", - "rightclick", - "text", - "screenshot", - "time", - "select", - "files", - "waitload", - "getresource", - "extract", - "setmethod", - "addheader", - "setheader", - "deleteheader", - "setbody", - "waitevent", - "keyboard", - "debug", - "sleep" - ], - "type": "string", - "title": "action to perform", - "description": "Type of actions to perform" - } - }, - "additionalProperties": false, - "type": "object" - }, - "http.Request": { - "properties": { - "matchers": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/matchers.Matcher" - }, - "type": "array", - "title": "matchers to run on response", - "description": "Detection mechanism to identify whether the request was successful by doing pattern matching" - }, - "extractors": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/extractors.Extractor" - }, - "type": "array", - "title": "extractors to run on response", - "description": "Extractors contains the extraction mechanism for the request to identify and extract parts of the response" - }, - "matchers-condition": { - "enum": [ - "and", - "or" - ], - "type": "string", - "title": "condition between the matchers", - "description": "Conditions between the matchers" - }, - "path": { - "items": { - "type": "string" - }, - "type": "array", - "title": "path(s) for the http request", - "description": "Path(s) to send http requests to" - }, - "raw": { - "items": { - "type": "string" - }, - "type": "array", - "description": "HTTP Requests in Raw Format" - }, - "id": { - "type": "string", - "title": "id for the http request", - "description": "ID for the HTTP Request" - }, - "name": { - "type": "string", - "title": "name for the http request", - "description": "Optional name for the HTTP Request" - }, - "attack": { - "enum": [ - "sniper", - "pitchfork", - "clusterbomb" - ], - "type": "string", - "title": "attack is the payload combination", - "description": "Attack is the type of payload combinations to perform" - }, - "method": { - "enum": [ - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "CONNECT", - "OPTIONS", - "TRACE", - "PATCH" - ], - "type": "string", - "title": "method is the http request method", - "description": "Method is the HTTP Request Method" - }, - "body": { - "type": "string", - "title": "body is the http request body", - "description": "Body is an optional parameter which contains HTTP Request body" - }, - "payloads": { - "patternProperties": { - ".*": { - "additionalProperties": true - } - }, - "type": "object", - "title": "payloads for the http request", - "description": "Payloads contains any payloads for the current request" - }, - "headers": { - "patternProperties": { - ".*": { - "type": "string" - } - }, - "type": "object", - "title": "headers to send with the http request", - "description": "Headers contains HTTP Headers to send with the request" - }, - "race_count": { - "type": "integer", - "title": "number of times to repeat request in race condition", - "description": "Number of times to send a request in Race Condition Attack" - }, - "max-redirects": { - "type": "integer", - "title": "maximum number of redirects to follow", - "description": "Maximum number of redirects that should be followed" - }, - "pipeline-concurrent-connections": { - "type": "integer", - "title": "number of pipelining connections", - "description": "Number of connections to create during pipelining" - }, - "pipeline-requests-per-connection": { - "type": "integer", - "title": "number of requests to send per pipelining connections", - "description": "Number of requests to send per connection when pipelining" - }, - "threads": { - "type": "integer", - "title": "threads for sending requests", - "description": "Threads specifies number of threads to use sending requests. This enables Connection Pooling" - }, - "max-size": { - "type": "integer", - "title": "maximum http response body size", - "description": "Maximum size of http response body to read in bytes" - }, - "cookie-reuse": { - "type": "boolean", - "title": "optional cookie reuse enable", - "description": "Optional setting that enables cookie reuse" - }, - "redirects": { - "type": "boolean", - "title": "follow http redirects", - "description": "Specifies whether redirects should be followed by the HTTP Client" - }, - "pipeline": { - "type": "boolean", - "title": "perform HTTP 1.1 pipelining", - "description": "Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining" - }, - "unsafe": { - "type": "boolean", - "title": "use rawhttp non-strict-rfc client", - "description": "Unsafe specifies whether to use rawhttp engine for sending Non RFC-Compliant requests" - }, - "race": { - "type": "boolean", - "title": "perform race-http request coordination attack", - "description": "Race determines if all the request have to be attempted at the same time (Race Condition)" - }, - "req-condition": { - "type": "boolean", - "title": "preserve request history", - "description": "Automatically assigns numbers to requests and preserves their history" - }, - "stop-at-first-match": { - "type": "boolean", - "title": "stop at first match", - "description": "Stop the execution after a match is found" - } - }, - "additionalProperties": false, - "type": "object" - }, - "network.Input": { - "properties": { - "data": { - "type": "string", - "title": "data to send as input", - "description": "Data is the data to send as the input" - }, - "type": { - "enum": [ - "hex", - "text" - ], - "type": "string", - "title": "type is the type of input data", - "description": "Type of input specified in data field" - }, - "read": { - "type": "integer", - "title": "bytes to read from socket", - "description": "Number of bytes to read from socket" - }, - "name": { - "type": "string", - "title": "optional name for data read", - "description": "Optional name of the data read to provide matching on" - } - }, - "additionalProperties": false, - "type": "object" - }, - "network.Request": { - "properties": { - "id": { - "type": "string", - "title": "id of the request", - "description": "ID of the network request" - }, - "host": { - "items": { - "type": "string" - }, - "type": "array", - "title": "host to send requests to", - "description": "Host to send network requests to" - }, - "attack": { - "enum": [ - "sniper", - "pitchfork", - "clusterbomb" - ], - "type": "string", - "title": "attack is the payload combination", - "description": "Attack is the type of payload combinations to perform" - }, - "payloads": { - "patternProperties": { - ".*": { - "additionalProperties": true - } - }, - "type": "object", - "title": "payloads for the network request", - "description": "Payloads contains any payloads for the current request" - }, - "inputs": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/network.Input" - }, - "type": "array", - "title": "inputs for the network request", - "description": "Inputs contains any input/output for the current request" - }, - "read-size": { - "type": "integer", - "title": "size of network response to read", - "description": "Size of response to read at the end. Default is 1024 bytes" - }, - "matchers": { - "items": { - "$ref": "#/definitions/matchers.Matcher" - }, - "type": "array", - "title": "matchers to run on response", - "description": "Detection mechanism to identify whether the request was successful by doing pattern matching" - }, - "extractors": { - "items": { - "$ref": "#/definitions/extractors.Extractor" - }, - "type": "array", - "title": "extractors to run on response", - "description": "Extractors contains the extraction mechanism for the request to identify and extract parts of the response" - }, - "matchers-condition": { - "enum": [ - "and", - "or" - ], - "type": "string", - "title": "condition between the matchers", - "description": "Conditions between the matchers" - } - }, - "additionalProperties": false, - "type": "object" - }, - "templates.Template": { - "required": [ - "id", - "info" - ], - "properties": { - "id": { - "type": "string", - "title": "id of the template", - "description": "The Unique ID for the template", - "examples": [ - "cve-2021-19520" - ] - }, - "info": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/model.Info", - "title": "info for the template", - "description": "Info contains metadata for the template" - }, - "requests": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/http.Request" - }, - "type": "array", - "title": "http requests to make", - "description": "HTTP requests to make for the template" - }, - "dns": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/dns.Request" - }, - "type": "array", - "title": "dns requests to make", - "description": "DNS requests to make for the template" - }, - "file": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/file.Request" - }, - "type": "array", - "title": "file requests to make", - "description": "File requests to make for the template" - }, - "network": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/network.Request" - }, - "type": "array", - "title": "network requests to make", - "description": "Network requests to make for the template" - }, - "headless": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/headless.Request" - }, - "type": "array", - "title": "headless requests to make", - "description": "Headless requests to make for the template" - }, - "workflows": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/workflows.WorkflowTemplate" - }, - "type": "array", - "title": "list of workflows to execute", - "description": "List of workflows to execute for template" - } - }, - "additionalProperties": false, - "type": "object" - }, - "workflows.Matcher": { - "properties": { - "name": { - "type": "string", - "title": "name of item to match", - "description": "Name of item to match" - }, - "subtemplates": { - "items": { - "$ref": "#/definitions/workflows.WorkflowTemplate" - }, - "type": "array", - "title": "templates to run after match", - "description": "Templates to run after match" - } - }, - "additionalProperties": false, - "type": "object" - }, - "workflows.WorkflowTemplate": { - "properties": { - "template": { - "type": "string", - "title": "template/directory to execute", - "description": "Template or directory to execute as part of workflow" - }, - "tags": { - "$ref": "#/definitions/model.StringSlice", - "title": "tags to execute", - "description": "Tags to run template based on" - }, - "matchers": { - "items": { - "$schema": "http://json-schema.org/draft-04/schema#", - "$ref": "#/definitions/workflows.Matcher" - }, - "type": "array", - "title": "name based template result matchers", - "description": "Matchers perform name based matching to run subtemplates for a workflow" - }, - "subtemplates": { - "items": { - "$ref": "#/definitions/workflows.WorkflowTemplate" - }, - "type": "array", - "title": "subtemplate based result matchers", - "description": "Subtemplates are ran if the template field Template matches" - } - }, - "additionalProperties": false, - "type": "object" - } - } -} diff --git a/v2/pkg/model/model.go b/v2/pkg/model/model.go index 9a1b8c13f..d6834c78e 100644 --- a/v2/pkg/model/model.go +++ b/v2/pkg/model/model.go @@ -65,4 +65,41 @@ type Info struct { // - value: > // map[string]string{"customField1":"customValue1"} AdditionalFields map[string]string `json:"additional-fields,omitempty" yaml:"additional-fields,omitempty" jsonschema:"title=additional metadata for the template,description=Additional metadata fields for the template"` + + // description: | + // Classification contains classification information about the template. + Classification *Classification `json:"classification,omitempty" yaml:"classification,omitempty" jsonschema:"title=classification info for the template,description=Classification information for the template"` + + // description: | + // Remediation steps for the template. + // + // You can go in-depth here on how to mitigate the problem found by this template. + // + // examples: + // - value: "\"Change the default administrative username and password of Apache ActiveMQ by editing the file jetty-realm.properties\"" + Remediation string `json:"remediation,omitempty" yaml:"remediation,omitempty" jsonschema:"title=remediation steps for the template,description=In-depth explanation on how to fix the issues found by the template,example=Change the default administrative username and password of Apache ActiveMQ by editing the file jetty-realm.properties"` +} + +// Classification contains the vulnerability classification data for a template. +type Classification struct { + // description: | + // CVE ID for the template + // examples: + // - value: "\"CVE-2020-14420\"" + CVEID stringslice.StringSlice `json:"cve-id,omitempty" yaml:"cve-id,omitempty" jsonschema:"title=cve ids for the template,description=CVE IDs for the template,example=CVE-2020-14420"` + // description: | + // CWE ID for the template. + // examples: + // - value: "\"CWE-22\"" + CWEID stringslice.StringSlice `json:"cwe-id,omitempty" yaml:"cwe-id,omitempty" jsonschema:"title=cwe ids for the template,description=CWE IDs for the template,example=CWE-22"` + // description: | + // CVSS Metrics for the template. + // examples: + // - value: "\"3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H\"" + CVSSMetrics string `json:"cvss-metrics,omitempty" yaml:"cvss-metrics,omitempty" jsonschema:"title=cvss metrics for the template,description=CVSS Metrics for the template,example=3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"` + // description: | + // CVSS Score for the template. + // examples: + // - value: "\"9.8\"" + CVSSScore float64 `json:"cvss-score,omitempty" yaml:"cvss-score,omitempty" jsonschema:"title=cvss score for the template,description=CVSS Score for the template,example=9.8"` } diff --git a/v2/pkg/output/format_json.go b/v2/pkg/output/format_json.go index 814bab1fd..29fd41e0e 100644 --- a/v2/pkg/output/format_json.go +++ b/v2/pkg/output/format_json.go @@ -6,5 +6,9 @@ import ( // formatJSON formats the output for json based formatting func (w *StandardWriter) formatJSON(output *ResultEvent) ([]byte, error) { + if !w.jsonReqResp { // don't show request-response in json if not asked + output.Request = "" + output.Response = "" + } return jsoniter.Marshal(output) } diff --git a/v2/pkg/output/output.go b/v2/pkg/output/output.go index 4f9ecbd0c..8f42646cf 100644 --- a/v2/pkg/output/output.go +++ b/v2/pkg/output/output.go @@ -33,6 +33,7 @@ type Writer interface { // StandardWriter is a writer writing output to file and screen for results. type StandardWriter struct { json bool + jsonReqResp bool noTimestamp bool noMetadata bool aurora aurora.Aurora @@ -94,7 +95,7 @@ type ResultEvent struct { } // NewStandardWriter creates a new output writer based on user configurations -func NewStandardWriter(colors, noMetadata, noTimestamp, json bool, file, traceFile string) (*StandardWriter, error) { +func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp bool, file, traceFile string) (*StandardWriter, error) { auroraColorizer := aurora.NewAurora(colors) var outputFile *fileWriter @@ -115,6 +116,7 @@ func NewStandardWriter(colors, noMetadata, noTimestamp, json bool, file, traceFi } writer := &StandardWriter{ json: json, + jsonReqResp: jsonReqResp, noMetadata: noMetadata, noTimestamp: noTimestamp, aurora: auroraColorizer, diff --git a/v2/pkg/protocols/common/interactsh/interactsh.go b/v2/pkg/protocols/common/interactsh/interactsh.go index 659e68092..c1435b2cd 100644 --- a/v2/pkg/protocols/common/interactsh/interactsh.go +++ b/v2/pkg/protocols/common/interactsh/interactsh.go @@ -6,6 +6,7 @@ import ( "net/url" "os" "strings" + "sync" "sync/atomic" "time" @@ -36,8 +37,9 @@ type Client struct { pollDuration time.Duration cooldownDuration time.Duration - generated uint32 // decide to wait if we have a generated url - matched bool + firstTimeGroup sync.Once + generated uint32 // decide to wait if we have a generated url + matched bool } var ( @@ -81,14 +83,6 @@ func New(options *Options) (*Client, error) { return nil, errors.Wrap(err, "could not parse server url") } - interactsh, err := client.New(&client.Options{ - ServerURL: options.ServerURL, - Token: options.Authorization, - PersistentSession: false, - }) - if err != nil { - return nil, errors.Wrap(err, "could not create client") - } configure := ccache.Configure() configure = configure.MaxSize(options.CacheSize) cache := ccache.New(configure) @@ -98,7 +92,6 @@ func New(options *Options) (*Client, error) { interactionsCache := ccache.New(interactionsCfg) interactClient := &Client{ - interactsh: interactsh, eviction: options.Eviction, interactions: interactionsCache, dotHostname: "." + parsed.Host, @@ -107,21 +100,34 @@ func New(options *Options) (*Client, error) { pollDuration: options.PollDuration, cooldownDuration: options.ColldownPeriod, } + return interactClient, nil +} - interactClient.interactsh.StartPolling(interactClient.pollDuration, func(interaction *server.Interaction) { - if options.Debug { +func (c *Client) firstTimeInitializeClient() error { + interactsh, err := client.New(&client.Options{ + ServerURL: c.options.ServerURL, + Token: c.options.Authorization, + PersistentSession: false, + }) + if err != nil { + return errors.Wrap(err, "could not create client") + } + c.interactsh = interactsh + + interactsh.StartPolling(c.pollDuration, func(interaction *server.Interaction) { + if c.options.Debug { debugPrintInteraction(interaction) } - item := interactClient.requests.Get(interaction.UniqueID) + item := c.requests.Get(interaction.UniqueID) if item == nil { // If we don't have any request for this ID, add it to temporary // lru cache, so we can correlate when we get an add request. - gotItem := interactClient.interactions.Get(interaction.UniqueID) + gotItem := c.interactions.Get(interaction.UniqueID) if gotItem == nil { - interactClient.interactions.Set(interaction.UniqueID, []*server.Interaction{interaction}, defaultInteractionDuration) + c.interactions.Set(interaction.UniqueID, []*server.Interaction{interaction}, defaultInteractionDuration) } else if items, ok := gotItem.Value().([]*server.Interaction); ok { items = append(items, interaction) - interactClient.interactions.Set(interaction.UniqueID, items, defaultInteractionDuration) + c.interactions.Set(interaction.UniqueID, items, defaultInteractionDuration) } return } @@ -129,9 +135,9 @@ func New(options *Options) (*Client, error) { if !ok { return } - _ = interactClient.processInteractionForRequest(interaction, request) + _ = c.processInteractionForRequest(interaction, request) }) - return interactClient, nil + return nil } // processInteractionForRequest processes an interaction for a request @@ -171,6 +177,11 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d // URL returns a new URL that can be interacted with func (c *Client) URL() string { + c.firstTimeGroup.Do(func() { + if err := c.firstTimeInitializeClient(); err != nil { + gologger.Error().Msgf("Could not initialize interactsh client: %s", err) + } + }) atomic.CompareAndSwapUint32(&c.generated, 0, 1) return c.interactsh.URL() } @@ -180,8 +191,10 @@ func (c *Client) Close() bool { if c.cooldownDuration > 0 && atomic.LoadUint32(&c.generated) == 1 { time.Sleep(c.cooldownDuration) } - c.interactsh.StopPolling() - c.interactsh.Close() + if c.interactsh != nil { + c.interactsh.StopPolling() + c.interactsh.Close() + } return c.matched } diff --git a/v2/pkg/protocols/dns/operators.go b/v2/pkg/protocols/dns/operators.go index 49fb3732a..5e5137420 100644 --- a/v2/pkg/protocols/dns/operators.go +++ b/v2/pkg/protocols/dns/operators.go @@ -147,10 +147,8 @@ func (r *Request) makeResultEventItem(wrapped *output.InternalWrappedEvent) *out Matched: types.ToString(wrapped.InternalEvent["matched"]), ExtractedResults: wrapped.OperatorsResult.OutputExtracts, Timestamp: time.Now(), - } - if r.options.Options.JSONRequests { - data.Request = types.ToString(wrapped.InternalEvent["request"]) - data.Response = types.ToString(wrapped.InternalEvent["raw"]) + Request: types.ToString(wrapped.InternalEvent["request"]), + Response: types.ToString(wrapped.InternalEvent["raw"]), } return data } diff --git a/v2/pkg/protocols/file/operators.go b/v2/pkg/protocols/file/operators.go index c56147763..6631aeba1 100644 --- a/v2/pkg/protocols/file/operators.go +++ b/v2/pkg/protocols/file/operators.go @@ -143,10 +143,8 @@ func (r *Request) makeResultEventItem(wrapped *output.InternalWrappedEvent) *out Matched: types.ToString(wrapped.InternalEvent["matched"]), Host: types.ToString(wrapped.InternalEvent["matched"]), ExtractedResults: wrapped.OperatorsResult.OutputExtracts, + Response: types.ToString(wrapped.InternalEvent["raw"]), Timestamp: time.Now(), } - if r.options.Options.JSONRequests { - data.Response = types.ToString(wrapped.InternalEvent["raw"]) - } return data } diff --git a/v2/pkg/protocols/headless/operators.go b/v2/pkg/protocols/headless/operators.go index e3c5dff41..776adb89c 100644 --- a/v2/pkg/protocols/headless/operators.go +++ b/v2/pkg/protocols/headless/operators.go @@ -116,10 +116,8 @@ func (r *Request) makeResultEventItem(wrapped *output.InternalWrappedEvent) *out ExtractedResults: wrapped.OperatorsResult.OutputExtracts, Timestamp: time.Now(), IP: types.ToString(wrapped.InternalEvent["ip"]), - } - if r.options.Options.JSONRequests { - data.Request = types.ToString(wrapped.InternalEvent["request"]) - data.Response = types.ToString(wrapped.InternalEvent["data"]) + Request: types.ToString(wrapped.InternalEvent["request"]), + Response: types.ToString(wrapped.InternalEvent["data"]), } return data } diff --git a/v2/pkg/protocols/http/operators.go b/v2/pkg/protocols/http/operators.go index 365f62d23..249bf3f3e 100644 --- a/v2/pkg/protocols/http/operators.go +++ b/v2/pkg/protocols/http/operators.go @@ -154,10 +154,8 @@ func (r *Request) makeResultEventItem(wrapped *output.InternalWrappedEvent) *out ExtractedResults: wrapped.OperatorsResult.OutputExtracts, Timestamp: time.Now(), IP: types.ToString(wrapped.InternalEvent["ip"]), - } - if r.options.Options.JSONRequests { - data.Request = types.ToString(wrapped.InternalEvent["request"]) - data.Response = types.ToString(wrapped.InternalEvent["response"]) + Request: types.ToString(wrapped.InternalEvent["request"]), + Response: types.ToString(wrapped.InternalEvent["response"]), } return data } diff --git a/v2/pkg/protocols/network/operators.go b/v2/pkg/protocols/network/operators.go index aa8e5e11a..81b5fcffe 100644 --- a/v2/pkg/protocols/network/operators.go +++ b/v2/pkg/protocols/network/operators.go @@ -118,10 +118,8 @@ func (r *Request) makeResultEventItem(wrapped *output.InternalWrappedEvent) *out Metadata: wrapped.OperatorsResult.PayloadValues, Timestamp: time.Now(), IP: types.ToString(wrapped.InternalEvent["ip"]), - } - if r.options.Options.JSONRequests { - data.Request = types.ToString(wrapped.InternalEvent["request"]) - data.Response = types.ToString(wrapped.InternalEvent["data"]) + Request: types.ToString(wrapped.InternalEvent["request"]), + Response: types.ToString(wrapped.InternalEvent["data"]), } return data } diff --git a/v2/pkg/protocols/offlinehttp/operators.go b/v2/pkg/protocols/offlinehttp/operators.go index 351c3a066..8aaf0663e 100644 --- a/v2/pkg/protocols/offlinehttp/operators.go +++ b/v2/pkg/protocols/offlinehttp/operators.go @@ -145,10 +145,8 @@ func (r *Request) makeResultEventItem(wrapped *output.InternalWrappedEvent) *out Metadata: wrapped.OperatorsResult.PayloadValues, ExtractedResults: wrapped.OperatorsResult.OutputExtracts, IP: types.ToString(wrapped.InternalEvent["ip"]), - } - if r.options.Options.JSONRequests { - data.Request = types.ToString(wrapped.InternalEvent["request"]) - data.Response = types.ToString(wrapped.InternalEvent["raw"]) + Request: types.ToString(wrapped.InternalEvent["request"]), + Response: types.ToString(wrapped.InternalEvent["raw"]), } return data } diff --git a/v2/pkg/reporting/format/format.go b/v2/pkg/reporting/format/format.go index a90130020..88492d2d3 100644 --- a/v2/pkg/reporting/format/format.go +++ b/v2/pkg/reporting/format/format.go @@ -3,9 +3,12 @@ package format import ( "bytes" "fmt" - "github.com/projectdiscovery/nuclei/v2/pkg/utils" + "strconv" "strings" + "github.com/projectdiscovery/nuclei/v2/pkg/catalog/config" + "github.com/projectdiscovery/nuclei/v2/pkg/utils" + "github.com/projectdiscovery/nuclei/v2/pkg/model" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/types" @@ -16,13 +19,10 @@ func Summary(event *output.ResultEvent) string { template := GetMatchedTemplate(event) builder := &strings.Builder{} - builder.WriteString("[") - builder.WriteString(template) - builder.WriteString("] [") - builder.WriteString(types.ToString(event.Info.SeverityHolder)) - builder.WriteString("] ") builder.WriteString(types.ToString(event.Info.Name)) - builder.WriteString(" found on ") + builder.WriteString(" (") + builder.WriteString(template) + builder.WriteString(") found on ") builder.WriteString(event.Host) data := builder.String() return data @@ -71,6 +71,7 @@ func MarkdownDescription(event *output.ResultEvent) string { // TODO remove the if len(event.ExtractedResults) > 0 || len(event.Metadata) > 0 { builder.WriteString("\n**Extra Information**\n\n") + if len(event.ExtractedResults) > 0 { builder.WriteString("**Extracted results**:\n\n") for _, v := range event.ExtractedResults { @@ -131,7 +132,7 @@ func MarkdownDescription(event *output.ResultEvent) string { // TODO remove the } } - builder.WriteString("\n---\nGenerated by [Nuclei](https://github.com/projectdiscovery/nuclei)") + builder.WriteString(fmt.Sprintf("\n---\nGenerated by [Nuclei %s](https://github.com/projectdiscovery/nuclei)", config.Version)) data := builder.String() return data } @@ -159,6 +160,16 @@ func ToMarkdownTableString(templateInfo *model.Info) string { fields.Set("Tags", templateInfo.Tags.String()) fields.Set("Severity", templateInfo.SeverityHolder.Severity.String()) fields.Set("Description", templateInfo.Description) + fields.Set("Remediation", templateInfo.Remediation) + + classification := templateInfo.Classification + if classification != nil { + if classification.CVSSMetrics != "" { + generateCVSSMetricsFromClassification(classification, fields) + } + generateCVECWEIDLinksFromClassification(classification, fields) + fields.Set("CVSS-Score", strconv.FormatFloat(classification.CVSSScore, 'f', 2, 64)) + } builder := &bytes.Buffer{} @@ -175,3 +186,44 @@ func ToMarkdownTableString(templateInfo *model.Info) string { return builder.String() } + +func generateCVSSMetricsFromClassification(classification *model.Classification, fields *utils.InsertionOrderedStringMap) { + // Generate cvss link + var cvssLinkPrefix string + if strings.Contains(classification.CVSSMetrics, "CVSS:3.0") { + cvssLinkPrefix = "https://www.first.org/cvss/calculator/3.0#" + } else if strings.Contains(classification.CVSSMetrics, "CVSS:3.1") { + cvssLinkPrefix = "https://www.first.org/cvss/calculator/3.1#" + } + if cvssLinkPrefix != "" { + fields.Set("CVSS-Metrics", fmt.Sprintf("[%s](%s%s)", classification.CVSSMetrics, cvssLinkPrefix, classification.CVSSMetrics)) + } else { + fields.Set("CVSS-Metrics", classification.CVSSMetrics) + } +} + +func generateCVECWEIDLinksFromClassification(classification *model.Classification, fields *utils.InsertionOrderedStringMap) { + cwes := classification.CWEID.ToSlice() + + cweIDs := make([]string, 0, len(cwes)) + for _, value := range cwes { + parts := strings.Split(value, "-") + if len(parts) != 2 { + continue + } + cweIDs = append(cweIDs, fmt.Sprintf("[%s](https://cwe.mitre.org/data/definitions/%s.html)", strings.ToUpper(value), parts[1])) + } + if len(cweIDs) > 0 { + fields.Set("CWE-ID", strings.Join(cweIDs, ",")) + } + + cves := classification.CVEID.ToSlice() + + cveIDs := make([]string, 0, len(cves)) + for _, value := range cves { + cveIDs = append(cveIDs, fmt.Sprintf("[%s](https://cve.mitre.org/cgi-bin/cvename.cgi?name=%s)", strings.ToUpper(value), value)) + } + if len(cveIDs) > 0 { + fields.Set("CVE-ID", strings.Join(cveIDs, ",")) + } +} diff --git a/v2/pkg/reporting/trackers/jira/jira.go b/v2/pkg/reporting/trackers/jira/jira.go index a3d50db55..1bfe2edd5 100644 --- a/v2/pkg/reporting/trackers/jira/jira.go +++ b/v2/pkg/reporting/trackers/jira/jira.go @@ -8,6 +8,7 @@ import ( "github.com/andygrunwald/go-jira" "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/nuclei/v2/pkg/catalog/config" "github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/reporting/format" "github.com/projectdiscovery/nuclei/v2/pkg/types" @@ -240,7 +241,7 @@ func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove th } } } - builder.WriteString("\n---\nGenerated by [Nuclei|https://github.com/projectdiscovery/nuclei]") + builder.WriteString(fmt.Sprintf("\n---\nGenerated by [Nuclei v%s](https://github.com/projectdiscovery/nuclei)", config.Version)) data := builder.String() return data } diff --git a/v2/pkg/templates/templates_doc.go b/v2/pkg/templates/templates_doc.go index dcbc37f5a..553b937ef 100644 --- a/v2/pkg/templates/templates_doc.go +++ b/v2/pkg/templates/templates_doc.go @@ -1,4 +1,3 @@ -// Package templates // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -12,8 +11,9 @@ import ( var ( TemplateDoc encoder.Doc MODELInfoDoc encoder.Doc - MODELStringSliceDoc encoder.Doc - SEVERITYSeverityHolderDoc encoder.Doc + STRINGSLICEStringSliceDoc encoder.Doc + SEVERITYHolderDoc encoder.Doc + MODELClassificationDoc encoder.Doc HTTPRequestDoc encoder.Doc MATCHERSMatcherDoc encoder.Doc EXTRACTORSExtractorDoc encoder.Doc @@ -96,7 +96,7 @@ func init() { FieldName: "info", }, } - MODELInfoDoc.Fields = make([]encoder.Doc, 7) + MODELInfoDoc.Fields = make([]encoder.Doc, 9) MODELInfoDoc.Fields[0].Name = "name" MODELInfoDoc.Fields[0].Type = "string" MODELInfoDoc.Fields[0].Note = "" @@ -107,14 +107,14 @@ func init() { MODELInfoDoc.Fields[0].AddExample("", "Nagios Default Credentials Check") MODELInfoDoc.Fields[1].Name = "author" - MODELInfoDoc.Fields[1].Type = "StringSlice" + MODELInfoDoc.Fields[1].Type = "stringslice.StringSlice" MODELInfoDoc.Fields[1].Note = "" MODELInfoDoc.Fields[1].Description = "Author of the template.\n\nMultiple values can also be specified separated by commas." MODELInfoDoc.Fields[1].Comments[encoder.LineComment] = "Author of the template." MODELInfoDoc.Fields[1].AddExample("", "") MODELInfoDoc.Fields[2].Name = "tags" - MODELInfoDoc.Fields[2].Type = "StringSlice" + MODELInfoDoc.Fields[2].Type = "stringslice.StringSlice" MODELInfoDoc.Fields[2].Note = "" MODELInfoDoc.Fields[2].Description = "Any tags for the template.\n\nMultiple values can also be specified separated by commas." MODELInfoDoc.Fields[2].Comments[encoder.LineComment] = "Any tags for the template." @@ -130,14 +130,14 @@ func init() { MODELInfoDoc.Fields[3].AddExample("", "Subversion ALM for the enterprise before 8.8.2 allows reflected XSS at multiple locations") MODELInfoDoc.Fields[4].Name = "reference" - MODELInfoDoc.Fields[4].Type = "StringSlice" + MODELInfoDoc.Fields[4].Type = "stringslice.StringSlice" MODELInfoDoc.Fields[4].Note = "" MODELInfoDoc.Fields[4].Description = "References for the template.\n\nThis should contain links relevant to the template." MODELInfoDoc.Fields[4].Comments[encoder.LineComment] = "References for the template." MODELInfoDoc.Fields[4].AddExample("", []string{"https://github.com/strapi/strapi", "https://github.com/getgrav/grav"}) MODELInfoDoc.Fields[5].Name = "severity" - MODELInfoDoc.Fields[5].Type = "severity.SeverityHolder" + MODELInfoDoc.Fields[5].Type = "severity.Holder" MODELInfoDoc.Fields[5].Note = "" MODELInfoDoc.Fields[5].Description = "Severity of the template." MODELInfoDoc.Fields[5].Comments[encoder.LineComment] = "Severity of the template." @@ -155,28 +155,109 @@ func init() { MODELInfoDoc.Fields[6].Comments[encoder.LineComment] = "AdditionalFields regarding metadata of the template." MODELInfoDoc.Fields[6].AddExample("", map[string]string{"customField1": "customValue1"}) + MODELInfoDoc.Fields[7].Name = "classification" + MODELInfoDoc.Fields[7].Type = "model.Classification" + MODELInfoDoc.Fields[7].Note = "" + MODELInfoDoc.Fields[7].Description = "Classification contains classification information about the template." + MODELInfoDoc.Fields[7].Comments[encoder.LineComment] = "Classification contains classification information about the template." + MODELInfoDoc.Fields[8].Name = "remediation" + MODELInfoDoc.Fields[8].Type = "string" + MODELInfoDoc.Fields[8].Note = "" + MODELInfoDoc.Fields[8].Description = "Remediation steps for the template.\n\nYou can go in-depth here on how to mitigate the problem found by this template." + MODELInfoDoc.Fields[8].Comments[encoder.LineComment] = "Remediation steps for the template." - MODELStringSliceDoc.Type = "model.StringSlice" - MODELStringSliceDoc.Comments[encoder.LineComment] = "" - MODELStringSliceDoc.Description = "" - MODELStringSliceDoc.AppearsIn = []encoder.Appearance{ + MODELInfoDoc.Fields[8].AddExample("", "Change the default administrative username and password of Apache ActiveMQ by editing the file jetty-realm.properties") + + STRINGSLICEStringSliceDoc.Type = "stringslice.StringSlice" + STRINGSLICEStringSliceDoc.Comments[encoder.LineComment] = " StringSlice represents a single (in-lined) or multiple string value(s)." + STRINGSLICEStringSliceDoc.Description = "StringSlice represents a single (in-lined) or multiple string value(s).\n The unmarshaller does not automatically convert in-lined strings to []string, hence the interface{} type is required." + + STRINGSLICEStringSliceDoc.AddExample("", "") + + STRINGSLICEStringSliceDoc.AddExample("Example tags", "cve,cve2019,grafana,auth-bypass,dos") + + STRINGSLICEStringSliceDoc.AddExample("", []string{"https://github.com/strapi/strapi", "https://github.com/getgrav/grav"}) + + STRINGSLICEStringSliceDoc.AddExample("", "CVE-2020-14420") + + STRINGSLICEStringSliceDoc.AddExample("", "CWE-22") + STRINGSLICEStringSliceDoc.AppearsIn = []encoder.Appearance{ + { + TypeName: "model.Info", + FieldName: "author", + }, + { + TypeName: "model.Info", + FieldName: "tags", + }, + { + TypeName: "model.Info", + FieldName: "reference", + }, + { + TypeName: "model.Classification", + FieldName: "cve-id", + }, + { + TypeName: "model.Classification", + FieldName: "cwe-id", + }, { TypeName: "workflows.WorkflowTemplate", FieldName: "tags", }, } - MODELStringSliceDoc.Fields = make([]encoder.Doc, 0) + STRINGSLICEStringSliceDoc.Fields = make([]encoder.Doc, 0) - SEVERITYSeverityHolderDoc.Type = "severity.SeverityHolder" - SEVERITYSeverityHolderDoc.Comments[encoder.LineComment] = "" - SEVERITYSeverityHolderDoc.Description = "" - SEVERITYSeverityHolderDoc.AppearsIn = []encoder.Appearance{ + SEVERITYHolderDoc.Type = "severity.Holder" + SEVERITYHolderDoc.Comments[encoder.LineComment] = " Holder holds a Severity type. Required for un/marshalling purposes" + SEVERITYHolderDoc.Description = "Holder holds a Severity type. Required for un/marshalling purposes" + SEVERITYHolderDoc.AppearsIn = []encoder.Appearance{ { TypeName: "model.Info", FieldName: "severity", }, } - SEVERITYSeverityHolderDoc.Fields = make([]encoder.Doc, 0) + SEVERITYHolderDoc.Fields = make([]encoder.Doc, 0) + + MODELClassificationDoc.Type = "model.Classification" + MODELClassificationDoc.Comments[encoder.LineComment] = "" + MODELClassificationDoc.Description = "" + MODELClassificationDoc.AppearsIn = []encoder.Appearance{ + { + TypeName: "model.Info", + FieldName: "classification", + }, + } + MODELClassificationDoc.Fields = make([]encoder.Doc, 4) + MODELClassificationDoc.Fields[0].Name = "cve-id" + MODELClassificationDoc.Fields[0].Type = "stringslice.StringSlice" + MODELClassificationDoc.Fields[0].Note = "" + MODELClassificationDoc.Fields[0].Description = "CVE ID for the template" + MODELClassificationDoc.Fields[0].Comments[encoder.LineComment] = "CVE ID for the template" + + MODELClassificationDoc.Fields[0].AddExample("", "CVE-2020-14420") + MODELClassificationDoc.Fields[1].Name = "cwe-id" + MODELClassificationDoc.Fields[1].Type = "stringslice.StringSlice" + MODELClassificationDoc.Fields[1].Note = "" + MODELClassificationDoc.Fields[1].Description = "CWE ID for the template." + MODELClassificationDoc.Fields[1].Comments[encoder.LineComment] = "CWE ID for the template." + + MODELClassificationDoc.Fields[1].AddExample("", "CWE-22") + MODELClassificationDoc.Fields[2].Name = "cvss-metrics" + MODELClassificationDoc.Fields[2].Type = "string" + MODELClassificationDoc.Fields[2].Note = "" + MODELClassificationDoc.Fields[2].Description = "CVSS Metrics for the template." + MODELClassificationDoc.Fields[2].Comments[encoder.LineComment] = "CVSS Metrics for the template." + + MODELClassificationDoc.Fields[2].AddExample("", "3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H") + MODELClassificationDoc.Fields[3].Name = "cvss-score" + MODELClassificationDoc.Fields[3].Type = "float64" + MODELClassificationDoc.Fields[3].Note = "" + MODELClassificationDoc.Fields[3].Description = "CVSS Score for the template." + MODELClassificationDoc.Fields[3].Comments[encoder.LineComment] = "CVSS Score for the template." + + MODELClassificationDoc.Fields[3].AddExample("", "9.8") HTTPRequestDoc.Type = "http.Request" HTTPRequestDoc.Comments[encoder.LineComment] = " Request contains a http request to be made from a template" @@ -971,7 +1052,7 @@ func init() { WORKFLOWSWorkflowTemplateDoc.Fields[0].AddExample("A template directory", "misconfigurations/aem") WORKFLOWSWorkflowTemplateDoc.Fields[1].Name = "tags" - WORKFLOWSWorkflowTemplateDoc.Fields[1].Type = "model.StringSlice" + WORKFLOWSWorkflowTemplateDoc.Fields[1].Type = "stringslice.StringSlice" WORKFLOWSWorkflowTemplateDoc.Fields[1].Note = "" WORKFLOWSWorkflowTemplateDoc.Fields[1].Description = "Tags to run templates based on." WORKFLOWSWorkflowTemplateDoc.Fields[1].Comments[encoder.LineComment] = "Tags to run templates based on." @@ -1016,8 +1097,9 @@ func GetTemplateDoc() *encoder.FileDoc { Structs: []*encoder.Doc{ &TemplateDoc, &MODELInfoDoc, - &MODELStringSliceDoc, - &SEVERITYSeverityHolderDoc, + &STRINGSLICEStringSliceDoc, + &SEVERITYHolderDoc, + &MODELClassificationDoc, &HTTPRequestDoc, &MATCHERSMatcherDoc, &EXTRACTORSExtractorDoc, diff --git a/v2/syntax-reference.md b/v2/syntax-reference.md deleted file mode 100755 index 006885fb9..000000000 --- a/v2/syntax-reference.md +++ /dev/null @@ -1,2701 +0,0 @@ - - - - -## Template -Template is a YAML input file which defines all the requests and - other metadata for a template. - - - - -
- -
- -id string - -
-
- -ID is the unique id for the template. IDs must be lowercase -and must not contain spaces in it. - -#### Good IDs - -A good ID uniquely identifies what the requests in the template -are doing. Let's say you have a template that identifies a git-config -file on the webservers, a good name would be `git-config-exposure`. Another -example name is `azure-apps-nxdomain-takeover`. - - - -Examples: - - -```yaml -# ID Example -id: cve-2021-19520 -``` - - -
- -
- -
- -info model.Info - -
-
- -Info contains metadata information about the template. - - - -Examples: - - -```yaml -info: - name: Argument Injection in Ruby Dragonfly - author: 0xspara - tags: cve,cve2021,rce,ruby - reference: https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/ - severity: high -``` - - -
- -
- -
- -requests []http.Request - -
-
- -Requests contains the http request to make in the template. - - - -Examples: - - -```yaml -requests: - matchers: - - type: word - words: - - '[core]' - - type: dsl - condition: and - dsl: - - '!contains(tolower(body), '' - -
- -
- -dns []dns.Request - -
-
- -DNS contains the dns request to make in the template - - - -Examples: - - -```yaml -dns: - extractors: - - type: regex - regex: - - ec2-[-\d]+\.compute[-\d]*\.amazonaws\.com - - ec2-[-\d]+\.[\w\d\-]+\.compute[-\d]*\.amazonaws\.com - name: '{{FQDN}}' - type: CNAME - class: inet - retries: 2 - recursion: true -``` - - -
- -
- -
- -file []file.Request - -
-
- -File contains the file request to make in the template - - - -Examples: - - -```yaml -file: - extractors: - - type: regex - regex: - - amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} - extensions: - - all -``` - - -
- -
- -
- -network []network.Request - -
-
- -Network contains the network request to make in the template - - - -Examples: - - -```yaml -network: - host: - - '{{Hostname}}' - - '{{Hostname}}:2181' - inputs: - - data: "envi\r\nquit\r\n" - read-size: 2048 - matchers: - - type: word - words: - - zookeeper.version -``` - - -
- -
- -
- -headless []headless.Request - -
-
- -Headless contains the headless request to make in the template. - -
- -
- -
- -workflows []workflows.WorkflowTemplate - -
-
- -Workflows is a list of workflows to execute for a template. - -
- -
- - - - - -## model.Info -Info contains metadata information about a template - -Appears in: - - -- Template.info - - -```yaml -name: Argument Injection in Ruby Dragonfly -author: 0xspara -tags: cve,cve2021,rce,ruby -reference: https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/ -severity: high -``` - -
- -
- -name string - -
-
- -Name should be good short summary that identifies what the template does. - - - -Examples: - - -```yaml -name: bower.json file disclosure -``` - -```yaml -name: Nagios Default Credentials Check -``` - - -
- -
- -
- -author StringSlice - -
-
- -Author of the template. - -Multiple values can also be specified separated by commas. - - - -Examples: - - -```yaml -author: -``` - - -
- -
- -
- -tags StringSlice - -
-
- -Any tags for the template. - -Multiple values can also be specified separated by commas. - - - -Examples: - - -```yaml -# Example tags -tags: cve,cve2019,grafana,auth-bypass,dos -``` - - -
- -
- -
- -description string - -
-
- -Description of the template. - -You can go in-depth here on what the template actually does. - - - -Examples: - - -```yaml -description: Bower is a package manager which stores packages informations in bower.json file -``` - -```yaml -description: Subversion ALM for the enterprise before 8.8.2 allows reflected XSS at multiple locations -``` - - -
- -
- -
- -reference StringSlice - -
-
- -References for the template. - -This should contain links relevant to the template. - - - -Examples: - - -```yaml -reference: - - https://github.com/strapi/strapi - - https://github.com/getgrav/grav -``` - - -
- -
- -
- -severity severity.SeverityHolder - -
-
- -Severity of the template. - - -Valid values: - - - - info - - - low - - - medium - - - high - - - critical -
- -
- -
- -additional-fields map[string]string - -
-
- -AdditionalFields regarding metadata of the template. - - - -Examples: - - -```yaml -additional-fields: - customField1: customValue1 -``` - - -
- -
- - - - - -## model.StringSlice - -Appears in: - - -- workflows.WorkflowTemplate.tags - - - - - -## severity.SeverityHolder - -Appears in: - - -- model.Info.severity - - - - - -## http.Request -Request contains a http request to be made from a template - -Appears in: - - -- Template.requests - - -```yaml -matchers: - - type: word - words: - - '[core]' - - type: dsl - condition: and - dsl: - - '!contains(tolower(body), '' - -
- -matchers []matchers.Matcher - -
-
- -Matchers contains the detection mechanism for the request to identify -whether the request was successful by doing pattern matching -on request/responses. - -Multiple matchers can be combined together with `matcher-condition` flag -which accepts either `and` or `or` as argument. - -
- -
- -
- -extractors []extractors.Extractor - -
-
- -Extractors contains the extraction mechanism for the request to identify -and extract parts of the response. - -
- -
- -
- -matchers-condition string - -
-
- -MatchersCondition is the condition between the matchers. Default is OR. - - -Valid values: - - - - and - - - or -
- -
- -
- -path []string - -
-
- -Path contains the path/s for the HTTP requests. It supports variables -as placeholders. - - - -Examples: - - -```yaml -# Some example path values -path: - - '{{BaseURL}}' - - '{{BaseURL}}/+CSCOU+/../+CSCOE+/files/file_list.json?path=/sessions' -``` - - -
- -
- -
- -raw []string - -
-
- -Raw contains HTTP Requests in Raw format. - - - -Examples: - - -```yaml -# Some example raw requests -raw: - - |- - GET /etc/passwd HTTP/1.1 - Host: - Content-Length: 4 - - |- - POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.1 - Host: {{Hostname}} - User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0 - Content-Length: 1 - Connection: close - - echo - echo - cat /etc/passwd 2>&1 -``` - - -
- -
- -
- -id string - -
-
- -ID is the the optional id of the request - -
- -
- -
- -name string - -
-
- -Name is the optional name of the request. - -If a name is specified, all the named request in a template can be matched upon -in a combined manner allowing multirequest based matchers. - -
- -
- -
- -attack string - -
-
- -Attack is the type of payload combinations to perform. - -Sniper is each payload once, pitchfork combines multiple payload sets and clusterbomb generates -permutations and combinations for all payloads. - - -Valid values: - - - - sniper - - - pitchfork - - - clusterbomb -
- -
- -
- -method string - -
-
- -Method is the HTTP Request Method. - - -Valid values: - - - - GET - - - HEAD - - - POST - - - PUT - - - DELETE - - - CONNECT - - - OPTIONS - - - TRACE - - - PATCH -
- -
- -
- -body string - -
-
- -Body is an optional parameter which contains HTTP Request body. - - - -Examples: - - -```yaml -# Same Body for a Login POST request -body: username=test&password=test -``` - - -
- -
- -
- -payloads map[string]interface{} - -
-
- -Payloads contains any payloads for the current request. - -Payloads support both key-values combinations where a list -of payloads is provided, or optionally a single file can also -be provided as payload which will be read on run-time. - -
- -
- -
- -headers map[string]string - -
-
- -Headers contains HTTP Headers to send with the request. - - - -Examples: - - -```yaml -headers: - Any-Header: Any-Value - Content-Length: "1" - Content-Type: application/x-www-form-urlencoded -``` - - -
- -
- -
- -race_count int - -
-
- -RaceCount is the number of times to send a request in Race Condition Attack. - - - -Examples: - - -```yaml -# Send a request 5 times -race_count: 5 -``` - - -
- -
- -
- -max-redirects int - -
-
- -MaxRedirects is the maximum number of redirects that should be followed. - - - -Examples: - - -```yaml -# Follow upto 5 redirects -max-redirects: 5 -``` - - -
- -
- -
- -pipeline-concurrent-connections int - -
-
- -PipelineConcurrentConnections is number of connections to create during pipelining. - - - -Examples: - - -```yaml -# Create 40 concurrent connections -pipeline-concurrent-connections: 40 -``` - - -
- -
- -
- -pipeline-requests-per-connection int - -
-
- -PipelineRequestsPerConnection is number of requests to send per connection when pipelining. - - - -Examples: - - -```yaml -# Send 100 requests per pipeline connection -pipeline-requests-per-connection: 100 -``` - - -
- -
- -
- -threads int - -
-
- -Threads specifies number of threads to use sending requests. This enables Connection Pooling. - -Connection: Close attribute must not be used in request while using threads flag, otherwise -pooling will fail and engine will continue to close connections after requests. - - - -Examples: - - -```yaml -# Send requests using 10 concurrent threads -threads: 10 -``` - - -
- -
- -
- -max-size int - -
-
- -MaxSize is the maximum size of http response body to read in bytes. - - - -Examples: - - -```yaml -# Read max 2048 bytes of the response -max-size: 2048 -``` - - -
- -
- -
- -cookie-reuse bool - -
-
- -CookieReuse is an optional setting that enables cookie reuse for -all requests defined in raw section. - -
- -
- -
- -redirects bool - -
-
- -Redirects specifies whether redirects should be followed by the HTTP Client. - -This can be used in conjunction with `max-redirects` to control the HTTP request redirects. - -
- -
- -
- -pipeline bool - -
-
- -Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining - -All requests must be indempotent (GET/POST). This can be used for race conditions/billions requests. - -
- -
- -
- -unsafe bool - -
-
- -Unsafe specifies whether to use rawhttp engine for sending Non RFC-Compliant requests. - -This uses the [rawhttp](https://github.com/projectdiscovery/rawhttp) engine to achieve complete -control over the request, with no normalization performed by the client. - -
- -
- -
- -race bool - -
-
- -Race determines if all the request have to be attempted at the same time (Race Condition) - -The actual number of requests that will be sent is determined by the `race_count` field. - -
- -
- -
- -req-condition bool - -
-
- -ReqCondition automatically assigns numbers to requests and preserves their history. - -This allows matching on them later for multi-request conditions. - -
- -
- -
- -stop-at-first-match bool - -
-
- -StopAtFirstMatch stops the execution of the requests and template as soon as a match is found. - -
- -
- - - - - -## matchers.Matcher -Matcher is used to match a part in the output from a protocol. - -Appears in: - - -- http.Request.matchers - -- dns.Request.matchers - -- file.Request.matchers - -- network.Request.matchers - -- headless.Request.matchers - - - -
- -
- -type string - -
-
- -Type is the type of the matcher. - - -Valid values: - - - - status - - - size - - - word - - - regex - - - binary - - - dsl -
- -
- -
- -condition string - -
-
- -Condition is the optional condition between two matcher variables. By default, -the condition is assumed to be OR. - - -Valid values: - - - - and - - - or -
- -
- -
- -part string - -
-
- -Part is the part of the request response to match data from. - -Each protocol exposes a lot of different parts which are well -documented in docs for each request type. - - - -Examples: - - -```yaml -part: body -``` - -```yaml -part: raw -``` - - -
- -
- -
- -negative bool - -
-
- -Negative specifies if the match should be reversed -It will only match if the condition is not true. - -
- -
- -
- -name string - -
-
- -Name of the matcher. Name should be lowercase and must not contain -spaces or underscores (_). - - - -Examples: - - -```yaml -name: cookie-matcher -``` - - -
- -
- -
- -status []int - -
-
- -Status are the acceptable status codes for the response. - - - -Examples: - - -```yaml -status: - - 200 - - 302 -``` - - -
- -
- -
- -size []int - -
-
- -Size is the acceptable size for the response - - - -Examples: - - -```yaml -size: - - 3029 - - 2042 -``` - - -
- -
- -
- -words []string - -
-
- -Words contains word patterns required to be present in the response part. - - - -Examples: - - -```yaml -# Match for outlook mail protection domain -words: - - mail.protection.outlook.com -``` - -```yaml -# Match for application/json in response headers -words: - - application/json -``` - - -
- -
- -
- -regex []string - -
-
- -Regex contains Regular Expression patterns required to be present in the response part. - - - -Examples: - - -```yaml -# Match for Linkerd Service via Regex -regex: - - (?mi)^Via\\s*?:.*?linkerd.*$ -``` - -```yaml -# Match for Open Redirect via Location header -regex: - - (?m)^(?:Location\\s*?:\\s*?)(?:https?://|//)?(?:[a-zA-Z0-9\\-_\\.@]*)example\\.com.*$ -``` - - -
- -
- -
- -binary []string - -
-
- -Binary are the binary patterns required to be present in the response part. - - - -Examples: - - -```yaml -# Match for Springboot Heapdump Actuator "JAVA PROFILE", "HPROF", "Gunzip magic byte" -binary: - - 4a4156412050524f46494c45 - - 4850524f46 - - 1f8b080000000000 -``` - -```yaml -# Match for 7zip files -binary: - - 377ABCAF271C -``` - - -
- -
- -
- -dsl []string - -
-
- -DSL are the dsl expressions that will be evaluated as part of nuclei matching rules. -A list of these helper functions are available [here](https://nuclei.projectdiscovery.io/templating-guide/helper-functions/). - - - -Examples: - - -```yaml -# DSL Matcher for package.json file -dsl: - - contains(body, 'packages') && contains(tolower(all_headers), 'application/octet-stream') && status_code == 200 -``` - -```yaml -# DSL Matcher for missing strict transport security header -dsl: - - '!contains(tolower(all_headers), ''''strict-transport-security'''')' -``` - - -
- -
- -
- -encoding string - -
-
- -Encoding specifies the encoding for the words field if any. - - -Valid values: - - - - hex -
- -
- - - - - -## extractors.Extractor -Extractor is used to extract part of response using a regex. - -Appears in: - - -- http.Request.extractors - -- dns.Request.extractors - -- file.Request.extractors - -- network.Request.extractors - -- headless.Request.extractors - - - -
- -
- -name string - -
-
- -Name of the extractor. Name should be lowercase and must not contain -spaces or underscores (_). - - - -Examples: - - -```yaml -name: cookie-extractor -``` - - -
- -
- -
- -type string - -
-
- -Type is the type of the extractor. - - -Valid values: - - - - regex - - - kval - - - json - - - xpath -
- -
- -
- -regex []string - -
-
- -Regex contains the regular expression patterns to extract from a part. - -Go regex engine does not support lookaheads or lookbehinds, so as a result -they are also not supported in nuclei. - - - -Examples: - - -```yaml -# Braintree Access Token Regex -regex: - - access_token\$production\$[0-9a-z]{16}\$[0-9a-f]{32} -``` - -```yaml -# Wordpress Author Extraction regex -regex: - - Author:(?:[A-Za-z0-9 -\_="]+)? - -group int - -
-
- -Group specifies a numbered group to extract from the regex. - - - -Examples: - - -```yaml -# Example Regex Group -group: 1 -``` - - -
- -
- -
- -kval []string - -
-
- -description: | - kval contains the key-value pairs present in the HTTP response header. - kval extractor can be used to extract HTTP response header and cookie key-value pairs. - kval extractor inputs are case insensitive, and does not support dash (-) in input which can replaced with underscores (_) - For example, Content-Type should be replaced with content_type - - A list of supported parts is available in docs for request types. - examples: - - name: Extract Server Header From HTTP Response - value: > - []string{"server"} - - name: Extracting value of PHPSESSID Cookie - value: > - []string{"phpsessid"} - - name: Extracting value of Content-Type Cookie - value: > - []string{"content_type"} - -
- -
- -
- -json []string - -
-
- -JSON allows using jq-style syntax to extract items from json response - - - -Examples: - - -```yaml -json: - - .[] | .id -``` - -```yaml -json: - - .batters | .batter | .[] | .id -``` - - -
- -
- -
- -xpath []string - -
-
- -XPath allows using xpath expressions to extract items from html response - - - -Examples: - - -```yaml -xpath: - - /html/body/div/p[2]/a -``` - - -
- -
- -
- -attribute string - -
-
- -Attribute is an optional attribute to extract from response XPath. - - - -Examples: - - -```yaml -attribute: href -``` - - -
- -
- -
- -part string - -
-
- -Part is the part of the request response to extract data from. - -Each protocol exposes a lot of different parts which are well -documented in docs for each request type. - - - -Examples: - - -```yaml -part: body -``` - -```yaml -part: raw -``` - - -
- -
- -
- -internal bool - -
-
- -Internal, when set to true will allow using the value extracted -in the next request for some protocols (like HTTP). - -
- -
- - - - - -## dns.Request -Request contains a DNS protocol request to be made from a template - -Appears in: - - -- Template.dns - - -```yaml -extractors: - - type: regex - regex: - - ec2-[-\d]+\.compute[-\d]*\.amazonaws\.com - - ec2-[-\d]+\.[\w\d\-]+\.compute[-\d]*\.amazonaws\.com -name: '{{FQDN}}' -type: CNAME -class: inet -retries: 2 -recursion: true -``` - -
- -
- -matchers []matchers.Matcher - -
-
- -Matchers contains the detection mechanism for the request to identify -whether the request was successful by doing pattern matching -on request/responses. - -Multiple matchers can be combined together with `matcher-condition` flag -which accepts either `and` or `or` as argument. - -
- -
- -
- -extractors []extractors.Extractor - -
-
- -Extractors contains the extraction mechanism for the request to identify -and extract parts of the response. - -
- -
- -
- -matchers-condition string - -
-
- -MatchersCondition is the condition between the matchers. Default is OR. - - -Valid values: - - - - and - - - or -
- -
- -
- -id string - -
-
- -ID is the the optional id of the request - -
- -
- -
- -name string - -
-
- -Name is the Hostname to make DNS request for. - -Generally, it is set to {{FQDN}} which is the domain we get from input. - - - -Examples: - - -```yaml -name: '{{FQDN}}' -``` - - -
- -
- -
- -type string - -
-
- -Type is the type of DNS request to make. - - -Valid values: - - - - A - - - NS - - - DS - - - CNAME - - - SOA - - - PTR - - - MX - - - TXT - - - AAAA -
- -
- -
- -class string - -
-
- -Class is the class of the DNS request. - -Usually it's enough to just leave it as INET. - - -Valid values: - - - - inet - - - csnet - - - chaos - - - hesiod - - - none - - - any -
- -
- -
- -retries int - -
-
- -Retries is the number of retries for the DNS request - - - -Examples: - - -```yaml -# Use a retry of 3 to 5 generally -retries: 5 -``` - - -
- -
- -
- -recursion bool - -
-
- -Recursion determines if resolver should recurse all records to get fresh results. - -
- -
- - - - - -## file.Request -Request contains a File matching mechanism for local disk operations. - -Appears in: - - -- Template.file - - -```yaml -extractors: - - type: regex - regex: - - amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} -extensions: - - all -``` - -
- -
- -matchers []matchers.Matcher - -
-
- -Matchers contains the detection mechanism for the request to identify -whether the request was successful by doing pattern matching -on request/responses. - -Multiple matchers can be combined together with `matcher-condition` flag -which accepts either `and` or `or` as argument. - -
- -
- -
- -extractors []extractors.Extractor - -
-
- -Extractors contains the extraction mechanism for the request to identify -and extract parts of the response. - -
- -
- -
- -matchers-condition string - -
-
- -MatchersCondition is the condition between the matchers. Default is OR. - - -Valid values: - - - - and - - - or -
- -
- -
- -extensions []string - -
-
- -Extensions is the list of extensions to perform matching on. - - - -Examples: - - -```yaml -extensions: - - .txt - - .go - - .json -``` - - -
- -
- -
- -denylist []string - -
-
- -ExtensionDenylist is the list of file extensions to deny during matching. - -By default, it contains some non-interesting extensions that are hardcoded -in nuclei. - - - -Examples: - - -```yaml -denylist: - - .avi - - .mov - - .mp3 -``` - - -
- -
- -
- -id string - -
-
- -ID is the the optional id of the request - -
- -
- -
- -max-size int - -
-
- -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. - - - -Examples: - - -```yaml -max-size: 2048 -``` - - -
- -
- -
- -no-recursive bool - -
-
- -NoRecursive specifies whether to not do recursive checks if folders are provided. - -
- -
- - - - - -## network.Request -Request contains a Network protocol request to be made from a template - -Appears in: - - -- Template.network - - -```yaml -host: - - '{{Hostname}}' - - '{{Hostname}}:2181' -inputs: - - data: "envi\r\nquit\r\n" -read-size: 2048 -matchers: - - type: word - words: - - zookeeper.version -``` - -
- -
- -id string - -
-
- -ID is the the optional id of the request - -
- -
- -
- -host []string - -
-
- -Host to send network requests to. - -Usually it's set to `{{Hostname}}`. If you want to enable TLS for -TCP Connection, you can use `tls://{{Hostname}}`. - - - -Examples: - - -```yaml -host: - - '{{Hostname}}' -``` - - -
- -
- -
- -attack string - -
-
- -Attack is the type of payload combinations to perform. - -Sniper is each payload once, pitchfork combines multiple payload sets and clusterbomb generates -permutations and combinations for all payloads. - - -Valid values: - - - - sniper - - - pitchfork - - - clusterbomb -
- -
- -
- -payloads map[string]interface{} - -
-
- -Payloads contains any payloads for the current request. - -Payloads support both key-values combinations where a list -of payloads is provided, or optionally a single file can also -be provided as payload which will be read on run-time. - -
- -
- -
- -inputs []network.Input - -
-
- -Inputs contains inputs for the network socket - -
- -
- -
- -read-size int - -
-
- -ReadSize is the size of response to read at the end - -Default value for read-size is 1024. - - - -Examples: - - -```yaml -read-size: 2048 -``` - - -
- -
- -
- -matchers []matchers.Matcher - -
-
- -Matchers contains the detection mechanism for the request to identify -whether the request was successful by doing pattern matching -on request/responses. - -Multiple matchers can be combined together with `matcher-condition` flag -which accepts either `and` or `or` as argument. - -
- -
- -
- -extractors []extractors.Extractor - -
-
- -Extractors contains the extraction mechanism for the request to identify -and extract parts of the response. - -
- -
- -
- -matchers-condition string - -
-
- -MatchersCondition is the condition between the matchers. Default is OR. - - -Valid values: - - - - and - - - or -
- -
- - - - - -## network.Input - -Appears in: - - -- network.Request.inputs - - - -
- -
- -data string - -
-
- -Data is the data to send as the input. - -It supports DSL Helper Functions as well as normal expressions. - - - -Examples: - - -```yaml -data: TEST -``` - -```yaml -data: hex_decode('50494e47') -``` - - -
- -
- -
- -type string - -
-
- -Type is the type of input specified in `data` field. - -Default value is text, but hex can be used for hex formatted data. - - -Valid values: - - - - hex - - - text -
- -
- -
- -read int - -
-
- -Read is the number of bytes to read from socket. - -This can be used for protcols which expected an immediate response. You can -read and write responses one after another and evetually perform matching -on every data captured with `name` attribute. - -The [network docs](https://nuclei.projectdiscovery.io/templating-guide/protocols/network/) highlight more on how to do this. - - - -Examples: - - -```yaml -read: 1024 -``` - - -
- -
- -
- -name string - -
-
- -Name is the optional name of the data read to provide matching on. - - - -Examples: - - -```yaml -name: prefix -``` - - -
- -
- - - - - -## headless.Request -Request contains a Headless protocol request to be made from a template - -Appears in: - - -- Template.headless - - - -
- -
- -id string - -
-
- -ID is the the optional id of the request - -
- -
- -
- -steps []engine.Action - -
-
- -Steps is the list of actions to run for headless request - -
- -
- -
- -matchers []matchers.Matcher - -
-
- -Matchers contains the detection mechanism for the request to identify -whether the request was successful by doing pattern matching -on request/responses. - -Multiple matchers can be combined together with `matcher-condition` flag -which accepts either `and` or `or` as argument. - -
- -
- -
- -extractors []extractors.Extractor - -
-
- -Extractors contains the extraction mechanism for the request to identify -and extract parts of the response. - -
- -
- -
- -matchers-condition string - -
-
- -MatchersCondition is the condition between the matchers. Default is OR. - - -Valid values: - - - - and - - - or -
- -
- - - - - -## engine.Action -Action is an action taken by the browser to reach a navigation - - Each step that the browser executes is an action. Most navigations - usually start from the ActionLoadURL event, and further navigations - are discovered on the found page. We also keep track and only - scrape new navigation from pages we haven't crawled yet. - -Appears in: - - -- headless.Request.steps - - - -
- -
- -args map[string]string - -
-
- -Args contain arguments for the headless action. -Per action arguments are described in detail [here](https://nuclei.projectdiscovery.io/templating-guide/protocols/headless/). - -
- -
- -
- -name string - -
-
- -Name is the name assigned to the headless action. - -This can be used to execute code, for instance in browser -DOM using script action, and get the result in a variable -which can be matched upon by nuclei. An Example template [here](https://github.com/projectdiscovery/nuclei-templates/blob/master/headless/prototype-pollution-check.yaml). - -
- -
- -
- -description string - -
-
- -Description is the optional description of the headless action - -
- -
- -
- -action string - -
-
- -Action is the type of the action to perform. - - -Valid values: - - - - navigate - - - script - - - click - - - rightclick - - - text - - - screenshot - - - time - - - select - - - files - - - waitload - - - getresource - - - extract - - - setmethod - - - addheader - - - setheader - - - deleteheader - - - setbody - - - waitevent - - - keyboard - - - debug - - - sleep -
- -
- - - - - -## workflows.WorkflowTemplate - -Appears in: - - -- Template.workflows - -- workflows.WorkflowTemplate.subtemplates - -- workflows.Matcher.subtemplates - - - -
- -
- -template string - -
-
- -Template is a single template or directory to execute as part of workflow. - - - -Examples: - - -```yaml -# A single template -template: dns/worksites-detection.yaml -``` - -```yaml -# A template directory -template: misconfigurations/aem -``` - - -
- -
- -
- -tags model.StringSlice - -
-
- -Tags to run templates based on. - -
- -
- -
- -matchers []workflows.Matcher - -
-
- -Matchers perform name based matching to run subtemplates for a workflow. - -
- -
- -
- -subtemplates []workflows.WorkflowTemplate - -
-
- -Subtemplates are ran if the `template` field Template matches. - -
- -
- - - - - -## workflows.Matcher - -Appears in: - - -- workflows.WorkflowTemplate.matchers - - - -
- -
- -name string - -
-
- -Name is the name of the item to match. - -
- -
- -
- -subtemplates []workflows.WorkflowTemplate - -
-
- -Subtemplates are ran if the name of matcher matches. - -
- -
- - - -