Merge branch 'dev' into code_smells

This commit is contained in:
forgedhallpass 2021-09-01 17:41:42 +03:00
commit 0cabce518f
33 changed files with 377 additions and 151 deletions

View File

@ -13,7 +13,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16 go-version: 1.17
- name: Check out code - name: Check out code
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -13,7 +13,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.15 go-version: 1.17
- name: Check out code - name: Check out code
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -1,6 +1,8 @@
name: ⏰ Publish Docs name: ⏰ Publish Docs
on: on:
push:
pull_request:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@ -17,7 +19,7 @@ jobs:
- name: "Set up Go" - name: "Set up Go"
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16 go-version: 1.17
- name: Generate YAML Syntax Documentation - name: Generate YAML Syntax Documentation
id: generate-docs id: generate-docs
@ -28,7 +30,7 @@ jobs:
fi fi
go generate pkg/templates/templates.go go generate pkg/templates/templates.go
go build -o "cmd/docgen/docgen" cmd/docgen/docgen.go go build -o "cmd/docgen/docgen" cmd/docgen/docgen.go
./cmd/docgen/docgen syntax-reference.md nuclei-jsonschema.json ./cmd/docgen/docgen ../SYNTAX-REFERENCE.md ../nuclei-jsonschema.json
echo "::set-output name=changes::$(git status -s | wc -l)" echo "::set-output name=changes::$(git status -s | wc -l)"
working-directory: v2 working-directory: v2
@ -37,7 +39,7 @@ jobs:
run: | run: |
git config --local user.email "action@github.com" git config --local user.email "action@github.com"
git config --local user.name "GitHub Action" git config --local user.name "GitHub Action"
git add v2/syntax-reference.md v2/nuclei-jsonschema.json git add SYNTAX-REFERENCE.md nuclei-jsonschema.json
git commit -m "Auto Generate Syntax Docs + JSONSchema [$(date)] :robot:" -a git commit -m "Auto Generate Syntax Docs + JSONSchema [$(date)] :robot:" -a
- name: Push changes - name: Push changes

View File

@ -18,7 +18,7 @@ jobs:
name: "Set up Go" name: "Set up Go"
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16 go-version: 1.17
- -
env: env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -80,7 +80,7 @@ Nuclei is a fast, template based vulnerability scanner focusing
on extensive configurability, massive extensibility and ease of use. on extensive configurability, massive extensibility and ease of use.
Usage: Usage:
./nuclei [flags] nuclei [flags]
Flags: Flags:
TARGET: TARGET:
@ -100,7 +100,7 @@ FILTERING:
-etags, -exclude-tags string[] exclude templates with the provided tags -etags, -exclude-tags string[] exclude templates with the provided tags
-include-templates string[] templates to be executed even if they are excluded either by default or configuration -include-templates string[] templates to be executed even if they are excluded either by default or configuration
-exclude-templates, -exclude string[] template or template directory paths to exclude -exclude-templates, -exclude string[] template or template directory paths to exclude
-severity, -impact string[] execute templates that match the provided severities only -severity, -impact value[] Templates to run based on severity. Possible values: info, low, medium, high, critical
-author string[] execute templates that are (co-)created by the specified authors -author string[] execute templates that are (co-)created by the specified authors
OUTPUT: OUTPUT:
@ -111,7 +111,8 @@ OUTPUT:
-nc, -no-color disable output content coloring (ANSI escape codes) -nc, -no-color disable output content coloring (ANSI escape codes)
-json write output in JSONL(ines) format -json write output in JSONL(ines) format
-irr, -include-rr include request/response pairs in the JSONL output (for findings only) -irr, -include-rr include request/response pairs in the JSONL output (for findings only)
-nm, -no-meta don't display match metadata -nm, -no-meta don't display match metadata in CLI output
-nts, -no-timestamp don't display timestamp metadata in CLI output
-rdb, -report-db string local nuclei reporting database (always use this to persist report data) -rdb, -report-db string local nuclei reporting database (always use this to persist report data)
-me, -markdown-export string directory to export results in markdown format -me, -markdown-export string directory to export results in markdown format
-se, -sarif-export string file to export results in SARIF format -se, -sarif-export string file to export results in SARIF format
@ -124,7 +125,7 @@ CONFIGURATIONS:
-r, -resolvers string file containing resolver list for nuclei -r, -resolvers string file containing resolver list for nuclei
-system-resolvers use system DNS resolving as error fallback -system-resolvers use system DNS resolving as error fallback
-passive enable passive HTTP response processing mode -passive enable passive HTTP response processing mode
-env-vars Enable environment variables support -env-vars enable environment variables support
INTERACTSH: INTERACTSH:
-no-interactsh do not use interactsh server for blind interaction polling -no-interactsh do not use interactsh server for blind interaction polling
@ -143,8 +144,9 @@ RATE-LIMIT:
OPTIMIZATIONS: OPTIMIZATIONS:
-timeout int time to wait in seconds before timeout (default 5) -timeout int time to wait in seconds before timeout (default 5)
-retries int number of times to retry a failed request (default 1) -retries int number of times to retry a failed request (default 1)
-max-host-error int max errors for a host before skipping from scan (default 30)
-project use a project folder to avoid sending same request multiple times -project use a project folder to avoid sending same request multiple times
-project-path string set a specific project path (default "/var/folders/ml/m31ysb5x73l1s3kjlyn5g4180000gn/T/") -project-path string set a specific project path (default "$TMPDIR/")
-spm, -stop-at-first-path stop processing HTTP requests after the first match (may break template/workflow logic) -spm, -stop-at-first-path stop processing HTTP requests after the first match (may break template/workflow logic)
HEADLESS: HEADLESS:
@ -165,7 +167,7 @@ DEBUG:
UPDATE: UPDATE:
-update update nuclei to the latest released version -update update nuclei to the latest released version
-ut, -update-templates update the community templates to latest released version -ut, -update-templates update the community templates to latest released version
-nut, -no-update-templates Do not check for nuclei-templates updates -nut, -no-update-templates do not check for nuclei-templates updates
-ud, -update-directory string overwrite the default nuclei-templates directory (default "$HOME/nuclei-templates") -ud, -update-directory string overwrite the default nuclei-templates directory (default "$HOME/nuclei-templates")
STATISTICS: STATISTICS:

View File

@ -33,8 +33,10 @@
# jira contains configuration options for jira issue tracker # jira contains configuration options for jira issue tracker
#jira: #jira:
# # Cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used # # cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used
# cloud: true # cloud: true
# # update-existing is the boolean which tells if the existing, opened issue should be updated or new one should be created
# update-existing: false
# # URL is the jira application url # # URL is the jira application url
# url: "" # url: ""
# # account-id is the account-id of the jira user or username in case of on-prem Jira # # account-id is the account-id of the jira user or username in case of on-prem Jira

View File

@ -127,7 +127,7 @@ on extensive configurability, massive extensibility and ease of use.`)
createGroup(flagSet, "optimization", "Optimizations", createGroup(flagSet, "optimization", "Optimizations",
flagSet.IntVar(&options.Timeout, "timeout", 5, "time to wait in seconds before timeout"), flagSet.IntVar(&options.Timeout, "timeout", 5, "time to wait in seconds before timeout"),
flagSet.IntVar(&options.Retries, "retries", 1, "number of times to retry a failed request"), flagSet.IntVar(&options.Retries, "retries", 1, "number of times to retry a failed request"),
flagSet.IntVar(&options.HostMaxErrors, "host-max-error", 30, "max errors for a host before skipping from scan"), flagSet.IntVar(&options.MaxHostError, "max-host-error", 30, "max errors for a host before skipping from scan"),
flagSet.BoolVar(&options.Project, "project", false, "use a project folder to avoid sending same request multiple times"), flagSet.BoolVar(&options.Project, "project", false, "use a project folder to avoid sending same request multiple times"),
flagSet.StringVar(&options.ProjectPath, "project-path", os.TempDir(), "set a specific project path"), flagSet.StringVar(&options.ProjectPath, "project-path", os.TempDir(), "set a specific project path"),

View File

@ -13,6 +13,7 @@ require (
github.com/bluele/gcache v0.0.2 github.com/bluele/gcache v0.0.2
github.com/c4milo/unpackit v0.1.0 // indirect github.com/c4milo/unpackit v0.1.0 // indirect
github.com/corpix/uarand v0.1.1 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/go-rod/rod v0.91.1
github.com/google/go-github v17.0.0+incompatible github.com/google/go-github v17.0.0+incompatible
github.com/gosuri/uilive v0.0.4 // indirect github.com/gosuri/uilive v0.0.4 // indirect
@ -23,6 +24,7 @@ require (
github.com/karlseguin/ccache v2.0.3+incompatible github.com/karlseguin/ccache v2.0.3+incompatible
github.com/karrick/godirwalk v1.16.1 github.com/karrick/godirwalk v1.16.1
github.com/logrusorgru/aurora v2.0.3+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/miekg/dns v1.1.43 github.com/miekg/dns v1.1.43
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/owenrumney/go-sarif v1.0.11 github.com/owenrumney/go-sarif v1.0.11
@ -58,5 +60,7 @@ require (
go.uber.org/ratelimit v0.2.0 go.uber.org/ratelimit v0.2.0
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
golang.org/x/oauth2 v0.0.0-20210817223510-7df4dd6e12ab golang.org/x/oauth2 v0.0.0-20210817223510-7df4dd6e12ab
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )

View File

@ -96,6 +96,7 @@ github.com/corpix/uarand v0.1.1 h1:RMr1TWc9F4n5jiPDzFHtmaUXLKLNUFK0SgCLo4BhX/U=
github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU= 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/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/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= github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ=
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
@ -228,6 +229,7 @@ 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 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= 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/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/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/go-flags v1.5.0/go.mod h1:lenkYuCobuxLBAd/HGFE4LRoW8D3B6iXRQfWYJ+MNbA=
github.com/itchyny/gojq v0.12.4 h1:8zgOZWMejEWCLjbF/1mWY7hY7QEARm7dtuhC6Bp4R8o= github.com/itchyny/gojq v0.12.4 h1:8zgOZWMejEWCLjbF/1mWY7hY7QEARm7dtuhC6Bp4R8o=
@ -274,6 +276,7 @@ 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/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/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.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-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.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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@ -281,6 +284,8 @@ github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1y
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 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 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.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=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@ -359,6 +364,8 @@ github.com/projectdiscovery/yamldoc-go v1.0.2/go.mod h1:7uSxfMXaBmzvw8m5EhOEjB6n
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
@ -501,6 +508,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.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/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -608,6 +616,8 @@ golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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 h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -666,6 +676,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -696,6 +707,8 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 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=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -779,6 +792,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
mvdan.cc/gofumpt v0.1.1 h1:bi/1aS/5W00E2ny5q65w9SnKpWEF/UIOqDYBILpo9rA=
mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48= mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=

View File

@ -20,6 +20,6 @@ func showBanner() {
gologger.Print().Msgf("%s\n", banner) gologger.Print().Msgf("%s\n", banner)
gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n") gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n")
gologger.Warning().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.Warning().Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n") gologger.Error().Label("WRN").Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n")
} }

View File

@ -39,6 +39,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/templates" "github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils" "github.com/projectdiscovery/nuclei/v2/pkg/utils"
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
) )
// Runner is a client for running the enumeration process. // Runner is a client for running the enumeration process.
@ -71,6 +72,9 @@ func New(options *types.Options) (*Runner, error) {
} }
return nil, nil return nil, nil
} }
if options.Validate {
parsers.ShouldValidate = true
}
if err := runner.updateTemplates(); err != nil { if err := runner.updateTemplates(); err != nil {
gologger.Warning().Msgf("Could not update templates: %s\n", err) gologger.Warning().Msgf("Could not update templates: %s\n", err)
} }
@ -297,8 +301,8 @@ func (r *Runner) RunEnumeration() error {
r.options.ExcludedTemplates = append(r.options.ExcludedTemplates, ignoreFile.Files...) r.options.ExcludedTemplates = append(r.options.ExcludedTemplates, ignoreFile.Files...)
var cache *hosterrorscache.Cache var cache *hosterrorscache.Cache
if r.options.HostMaxErrors > 0 { if r.options.MaxHostError > 0 {
cache = hosterrorscache.New(r.options.HostMaxErrors, hosterrorscache.DefaultMaxHostsCount).SetVerbose(r.options.Verbose) cache = hosterrorscache.New(r.options.MaxHostError, hosterrorscache.DefaultMaxHostsCount).SetVerbose(r.options.Verbose)
} }
r.hostErrors = cache r.hostErrors = cache
executerOpts := protocols.ExecuterOptions{ executerOpts := protocols.ExecuterOptions{
@ -339,14 +343,23 @@ func (r *Runner) RunEnumeration() error {
if err != nil { if err != nil {
return errors.Wrap(err, "could not load templates from config") return errors.Wrap(err, "could not load templates from config")
} }
store.Load()
if r.options.Validate { if r.options.Validate {
if err := store.ValidateTemplates(r.options.Templates, r.options.Workflows); err != nil { if err := store.ValidateTemplates(r.options.Templates, r.options.Workflows); err != nil {
return err return err
} }
if stats.GetValue(parsers.SyntaxErrorStats) == 0 && stats.GetValue(parsers.SyntaxWarningStats) == 0 {
gologger.Info().Msgf("All templates validated successfully\n") gologger.Info().Msgf("All templates validated successfully\n")
} else {
return errors.New("encountered errors while performing template validation")
}
return nil // exit return nil // exit
} }
store.Load()
// Display stats for any loaded templates syntax warnings or errors
stats.Display(parsers.SyntaxWarningStats)
stats.Display(parsers.SyntaxErrorStats)
builder := &strings.Builder{} builder := &strings.Builder{}
if r.templatesConfig != nil && r.templatesConfig.NucleiLatestVersion != "" { if r.templatesConfig != nil && r.templatesConfig.NucleiLatestVersion != "" {
@ -386,10 +399,11 @@ func (r *Runner) RunEnumeration() error {
gologger.Info().Msgf("Using Interactsh Server %s", r.options.InteractshURL) gologger.Info().Msgf("Using Interactsh Server %s", r.options.InteractshURL)
} }
if len(store.Templates()) > 0 { if len(store.Templates()) > 0 {
gologger.Info().Msgf("Templates loaded: %d (New: %d)", len(store.Templates()), r.countNewTemplates()) gologger.Info().Msgf("Templates added in last update: %d", r.countNewTemplates())
gologger.Info().Msgf("Templates loaded for scan: %d", len(store.Templates()))
} }
if len(store.Workflows()) > 0 { if len(store.Workflows()) > 0 {
gologger.Info().Msgf("Workflows loaded: %d", len(store.Workflows())) gologger.Info().Msgf("Workflows loaded for scan: %d", len(store.Workflows()))
} }
// pre-parse all the templates, apply filters // pre-parse all the templates, apply filters

View File

@ -309,12 +309,12 @@
}, },
"class": { "class": {
"enum": [ "enum": [
"INET", "inet",
"CSNET", "csnet",
"CHAOS", "chaos",
"HESIOD", "hesiod",
"NONE", "none",
"ANY" "any"
], ],
"type": "string", "type": "string",
"title": "class of DNS request", "title": "class of DNS request",
@ -662,6 +662,11 @@
"type": "boolean", "type": "boolean",
"title": "preserve request history", "title": "preserve request history",
"description": "Automatically assigns numbers to requests and preserves their 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, "additionalProperties": false,

View File

@ -28,7 +28,7 @@ type Config struct {
const nucleiConfigFilename = ".templates-config.json" const nucleiConfigFilename = ".templates-config.json"
// Version is the current version of nuclei // Version is the current version of nuclei
const Version = `2.4.4-dev` const Version = `2.5.0`
func getConfigDetails() (string, error) { func getConfigDetails() (string, error) {
homeDir, err := os.UserHomeDir() homeDir, err := os.UserHomeDir()

View File

@ -107,18 +107,18 @@ func (store *Store) ValidateTemplates(templatesList, workflowsList []string) err
} }
func areWorkflowsValid(store *Store, filteredWorkflowPaths map[string]struct{}) bool { func areWorkflowsValid(store *Store, filteredWorkflowPaths map[string]struct{}) bool {
return areWorkflowOrTemplatesValid(store, filteredWorkflowPaths, func(templatePath string, tagFilter *filter.TagFilter) (bool, error) { return areWorkflowOrTemplatesValid(store, filteredWorkflowPaths, true, func(templatePath string, tagFilter *filter.TagFilter) (bool, error) {
return parsers.LoadWorkflow(templatePath) return parsers.LoadWorkflow(templatePath)
}) })
} }
func areTemplatesValid(store *Store, filteredTemplatePaths map[string]struct{}) bool { func areTemplatesValid(store *Store, filteredTemplatePaths map[string]struct{}) bool {
return areWorkflowOrTemplatesValid(store, filteredTemplatePaths, func(templatePath string, tagFilter *filter.TagFilter) (bool, error) { return areWorkflowOrTemplatesValid(store, filteredTemplatePaths, false, func(templatePath string, tagFilter *filter.TagFilter) (bool, error) {
return parsers.LoadTemplate(templatePath, store.tagFilter, nil) return parsers.LoadTemplate(templatePath, store.tagFilter, nil)
}) })
} }
func areWorkflowOrTemplatesValid(store *Store, filteredTemplatePaths map[string]struct{}, load func(templatePath string, tagFilter *filter.TagFilter) (bool, error)) bool { func areWorkflowOrTemplatesValid(store *Store, filteredTemplatePaths map[string]struct{}, isWorkflow bool, load func(templatePath string, tagFilter *filter.TagFilter) (bool, error)) bool {
areTemplatesValid := true areTemplatesValid := true
for templatePath := range filteredTemplatePaths { for templatePath := range filteredTemplatePaths {
if _, err := load(templatePath, store.tagFilter); err != nil { if _, err := load(templatePath, store.tagFilter); err != nil {
@ -128,10 +128,15 @@ func areWorkflowOrTemplatesValid(store *Store, filteredTemplatePaths map[string]
} }
} }
if _, err := templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions); err != nil { template, err := templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions)
if err != nil {
if isParsingError("Error occurred parsing template %s: %s\n", templatePath, err) { if isParsingError("Error occurred parsing template %s: %s\n", templatePath, err) {
areTemplatesValid = false areTemplatesValid = false
} }
} else {
if !isWorkflow && len(template.Workflows) > 0 {
return true
}
} }
} }
return areTemplatesValid return areTemplatesValid

View File

@ -22,6 +22,7 @@ type Info struct {
// description: | // description: |
// Author of the template. // Author of the template.
// //
// Multiple values can also be specified separated by commas.
// examples: // examples:
// - value: "\"<username>\"" // - value: "\"<username>\""
Authors StringSlice `json:"author,omitempty" yaml:"author,omitempty" jsonschema:"title=author of the template,description=Author is the author of the template,example=username"` Authors StringSlice `json:"author,omitempty" yaml:"author,omitempty" jsonschema:"title=author of the template,description=Author is the author of the template,example=username"`

View File

@ -17,6 +17,7 @@ import (
"time" "time"
"github.com/Knetic/govaluate" "github.com/Knetic/govaluate"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/deserialization" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/deserialization"
"github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/spaolacci/murmur3" "github.com/spaolacci/murmur3"
@ -241,6 +242,11 @@ var functions = map[string]govaluate.ExpressionFunction{
data := deserialization.GenerateJavaGadget(gadget, cmd, encoding) data := deserialization.GenerateJavaGadget(gadget, cmd, encoding)
return data, nil return data, nil
}, },
// for debug purposes
"print_debug": func(args ...interface{}) (interface{}, error) {
gologger.Info().Msgf("print_debug value: %s", fmt.Sprint(args))
return true, nil
},
} }
// HelperFunctions returns the dsl helper functions // HelperFunctions returns the dsl helper functions

View File

@ -10,7 +10,7 @@ import (
type Extractor struct { type Extractor struct {
// description: | // description: |
// Name of the extractor. Name should be lowercase and must not contain // Name of the extractor. Name should be lowercase and must not contain
// spaces or dashes (-). // spaces or underscores (_).
// examples: // examples:
// - value: "\"cookie-extractor\"" // - value: "\"cookie-extractor\""
Name string `yaml:"name,omitempty" jsonschema:"title=name of the extractor,description=Name of the extractor"` Name string `yaml:"name,omitempty" jsonschema:"title=name of the extractor,description=Name of the extractor"`
@ -48,18 +48,22 @@ type Extractor struct {
regexCompiled []*regexp.Regexp regexCompiled []*regexp.Regexp
// description: | // description: |
// kval contains the key-value pairs required in the response. // 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
// //
// Each protocol exposes a lot of different data in response. The kval // A list of supported parts is available in docs for request types.
// extractor can be used to extract those key-value pairs. A list of
// supported parts is available in docs for request types.
// examples: // examples:
// - name: Extract Server Header From HTTP Response // - name: Extract Server Header From HTTP Response
// value: > // value: >
// []string{"Server"} // []string{"server"}
// - name: Extracting value of PHPSESSID Cookie // - name: Extracting value of PHPSESSID Cookie
// value: > // value: >
// []string{"PHPSESSID"} // []string{"phpsessid"}
// - name: Extracting value of Content-Type Cookie
// value: >
// []string{"content_type"}
KVal []string `yaml:"kval,omitempty" jsonschema:"title=kval pairs to extract from response,description=Kval pairs to extract from response"` KVal []string `yaml:"kval,omitempty" jsonschema:"title=kval pairs to extract from response,description=Kval pairs to extract from response"`
// description: | // description: |
@ -77,8 +81,6 @@ type Extractor struct {
// examples: // examples:
// - value: > // - value: >
// []string{"/html/body/div/p[2]/a"} // []string{"/html/body/div/p[2]/a"}
// - value: >
// []string{".batters | .batter | .[] | .id"}
XPath []string `yaml:"xpath,omitempty" jsonschema:"title=html xpath expressions to extract data,description=XPath allows using xpath expressions to extract items from html response"` XPath []string `yaml:"xpath,omitempty" jsonschema:"title=html xpath expressions to extract data,description=XPath allows using xpath expressions to extract items from html response"`
// description: | // description: |
// Attribute is an optional attribute to extract from response XPath. // Attribute is an optional attribute to extract from response XPath.

View File

@ -43,7 +43,7 @@ type Matcher struct {
// description: | // description: |
// Name of the matcher. Name should be lowercase and must not contain // Name of the matcher. Name should be lowercase and must not contain
// spaces or dashes (-). // spaces or underscores (_).
// examples: // examples:
// - value: "\"cookie-matcher\"" // - value: "\"cookie-matcher\""
Name string `yaml:"name,omitempty" jsonschema:"title=name of the matcher,description=Name of the matcher"` Name string `yaml:"name,omitempty" jsonschema:"title=name of the matcher,description=Name of the matcher"`

View File

@ -4,14 +4,17 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"regexp"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader/filter" "github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader/filter"
"github.com/projectdiscovery/nuclei/v2/pkg/model" "github.com/projectdiscovery/nuclei/v2/pkg/model"
"github.com/projectdiscovery/nuclei/v2/pkg/templates" "github.com/projectdiscovery/nuclei/v2/pkg/templates"
"github.com/projectdiscovery/nuclei/v2/pkg/templates/cache" "github.com/projectdiscovery/nuclei/v2/pkg/templates/cache"
"github.com/projectdiscovery/nuclei/v2/pkg/utils" "github.com/projectdiscovery/nuclei/v2/pkg/utils"
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
) )
const mandatoryFieldMissingTemplate = "mandatory '%s' field is missing" const mandatoryFieldMissingTemplate = "mandatory '%s' field is missing"
@ -83,10 +86,23 @@ func validateMandatoryInfoFields(info *model.Info) error {
return nil return nil
} }
var parsedTemplatesCache *cache.Templates var (
parsedTemplatesCache *cache.Templates
ShouldValidate bool
fieldErrorRegexp = regexp.MustCompile(`not found in`)
)
const (
SyntaxWarningStats = "syntax-warnings"
SyntaxErrorStats = "syntax-errors"
)
func init() { func init() {
parsedTemplatesCache = cache.New() parsedTemplatesCache = cache.New()
stats.NewEntry(SyntaxWarningStats, "Found %d templates with syntax warning (use -validate flag for further examination)")
stats.NewEntry(SyntaxErrorStats, "Found %d templates with syntax error (use -validate flag for further examination)")
} }
// ParseTemplate parses a template and returns a *templates.Template structure // ParseTemplate parses a template and returns a *templates.Template structure
@ -107,9 +123,19 @@ func ParseTemplate(templatePath string) (*templates.Template, error) {
} }
template := &templates.Template{} template := &templates.Template{}
if err := yaml.Unmarshal(data, template); err != nil { if err := yaml.UnmarshalStrict(data, template); err != nil {
errString := err.Error()
if !fieldErrorRegexp.MatchString(errString) {
stats.Increment(SyntaxErrorStats)
return nil, err return nil, err
} }
stats.Increment(SyntaxWarningStats)
if ShouldValidate {
gologger.Error().Msgf("Syntax warnings for template %s: %s", templatePath, err)
} else {
gologger.Warning().Msgf("Syntax warnings for template %s: %s", templatePath, err)
}
}
parsedTemplatesCache.Store(templatePath, template, nil) parsedTemplatesCache.Store(templatePath, template, nil)
return template, nil return template, nil
} }

View File

@ -16,7 +16,7 @@ import (
// It uses an LRU cache internally for skipping unresponsive hosts // It uses an LRU cache internally for skipping unresponsive hosts
// that remain so for a duration. // that remain so for a duration.
type Cache struct { type Cache struct {
hostMaxErrors int MaxHostError int
verbose bool verbose bool
failedTargets gcache.Cache failedTargets gcache.Cache
} }
@ -24,11 +24,11 @@ type Cache struct {
const DefaultMaxHostsCount = 10000 const DefaultMaxHostsCount = 10000
// New returns a new host max errors cache // New returns a new host max errors cache
func New(hostMaxErrors, maxHostsCount int) *Cache { func New(MaxHostError, maxHostsCount int) *Cache {
gc := gcache.New(maxHostsCount). gc := gcache.New(maxHostsCount).
ARC(). ARC().
Build() Build()
return &Cache{failedTargets: gc, hostMaxErrors: hostMaxErrors} return &Cache{failedTargets: gc, MaxHostError: MaxHostError}
} }
// SetVerbose sets the cache to log at verbose level // SetVerbose sets the cache to log at verbose level
@ -88,7 +88,7 @@ func (c *Cache) Check(value string) bool {
if numberOfErrors == -1 { if numberOfErrors == -1 {
return true return true
} }
if numberOfErrorsValue >= c.hostMaxErrors { if numberOfErrorsValue >= c.MaxHostError {
_ = c.failedTargets.Set(finalValue, -1) _ = c.failedTargets.Set(finalValue, -1)
if c.verbose { if c.verbose {
gologger.Verbose().Msgf("Skipping %s as previously unresponsive %d times", finalValue, numberOfErrorsValue) gologger.Verbose().Msgf("Skipping %s as previously unresponsive %d times", finalValue, numberOfErrorsValue)

View File

@ -18,7 +18,7 @@ type Request struct {
// Operators for the current request go here. // Operators for the current request go here.
operators.Operators `yaml:",inline"` operators.Operators `yaml:",inline"`
// ID is the ID of the request // ID is the the optional id of the request
ID string `yaml:"id,omitempty" jsonschema:"title=id of the dns request,description=ID is the optional ID of the DNS Request"` ID string `yaml:"id,omitempty" jsonschema:"title=id of the dns request,description=ID is the optional ID of the DNS Request"`
// description: | // description: |

View File

@ -26,7 +26,7 @@ type Request struct {
// - value: '[]string{".avi", ".mov", ".mp3"}' // - value: '[]string{".avi", ".mov", ".mp3"}'
ExtensionDenylist []string `yaml:"denylist,omitempty" jsonschema:"title=extensions to deny match,description=List of file extensions to deny during matching"` ExtensionDenylist []string `yaml:"denylist,omitempty" jsonschema:"title=extensions to deny match,description=List of file extensions to deny during matching"`
// ID is the ID of the request // ID is the the optional id of the request
ID string `yaml:"id,omitempty" jsonschema:"title=id of the request,description=ID is the optional ID for the request"` ID string `yaml:"id,omitempty" jsonschema:"title=id of the request,description=ID is the optional ID for the request"`
// description: | // description: |

View File

@ -9,7 +9,7 @@ import (
// Request contains a Headless protocol request to be made from a template // Request contains a Headless protocol request to be made from a template
type Request struct { type Request struct {
// ID is the ID of the request // ID is the the optional id of the request
ID string `yaml:"id,omitempty" jsonschema:"title=id of the request,description=Optional ID of the headless request"` ID string `yaml:"id,omitempty" jsonschema:"title=id of the request,description=Optional ID of the headless request"`
// description: | // description: |

View File

@ -31,7 +31,7 @@ type Request struct {
// value: | // value: |
// []string{"GET /etc/passwd HTTP/1.1\nHost:\nContent-Length: 4", "POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.1\nHost: {{Hostname}}\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0\nContent-Length: 1\nConnection: close\n\necho\necho\ncat /etc/passwd 2>&1"} // []string{"GET /etc/passwd HTTP/1.1\nHost:\nContent-Length: 4", "POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.1\nHost: {{Hostname}}\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0\nContent-Length: 1\nConnection: close\n\necho\necho\ncat /etc/passwd 2>&1"}
Raw []string `yaml:"raw,omitempty" jsonschema:"http requests in raw format,description=HTTP Requests in Raw Format"` Raw []string `yaml:"raw,omitempty" jsonschema:"http requests in raw format,description=HTTP Requests in Raw Format"`
// ID is the ID of the request // ID is the the optional id of the request
ID string `yaml:"id,omitempty" jsonschema:"title=id for the http request,description=ID for the HTTP Request"` ID string `yaml:"id,omitempty" jsonschema:"title=id for the http request,description=ID for the HTTP Request"`
// description: | // description: |
// Name is the optional name of the request. // Name is the optional name of the request.
@ -162,7 +162,7 @@ type Request struct {
// This allows matching on them later for multi-request conditions. // This allows matching on them later for multi-request conditions.
ReqCondition bool `yaml:"req-condition,omitempty" jsonschema:"title=preserve request history,description=Automatically assigns numbers to requests and preserves their history"` ReqCondition bool `yaml:"req-condition,omitempty" jsonschema:"title=preserve request history,description=Automatically assigns numbers to requests and preserves their history"`
// description: | // description: |
// StopAtFirstMatch stops the execution of the requests as soon as a match is found. // StopAtFirstMatch stops the execution of the requests and template as soon as a match is found.
StopAtFirstMatch bool `yaml:"stop-at-first-match,omitempty" jsonschema:"title=stop at first match,description=Stop the execution after a match is found"` StopAtFirstMatch bool `yaml:"stop-at-first-match,omitempty" jsonschema:"title=stop at first match,description=Stop the execution after a match is found"`
} }

View File

@ -15,7 +15,7 @@ import (
// Request contains a Network protocol request to be made from a template // Request contains a Network protocol request to be made from a template
type Request struct { type Request struct {
// ID is the ID of the request // ID is the the optional id of the request
ID string `yaml:"id,omitempty" jsonschema:"title=id of the request,description=ID of the network request"` ID string `yaml:"id,omitempty" jsonschema:"title=id of the request,description=ID of the network request"`
// description: | // description: |

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
"github.com/andygrunwald/go-jira" "github.com/andygrunwald/go-jira"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/format" "github.com/projectdiscovery/nuclei/v2/pkg/reporting/format"
"github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/nuclei/v2/pkg/types"
@ -23,6 +23,8 @@ type Integration struct {
type Options struct { type Options struct {
// Cloud value is set to true when Jira cloud is used // Cloud value is set to true when Jira cloud is used
Cloud bool `yaml:"cloud"` Cloud bool `yaml:"cloud"`
// UpdateExisting value if true, the existing opened issue is updated
UpdateExisting bool `yaml:"update-existing"`
// URL is the URL of the jira server // URL is the URL of the jira server
URL string `yaml:"url"` URL string `yaml:"url"`
// AccountID is the accountID of the jira user. // AccountID is the accountID of the jira user.
@ -54,8 +56,8 @@ func New(options *Options) (*Integration, error) {
return &Integration{jira: jiraClient, options: options}, nil return &Integration{jira: jiraClient, options: options}, nil
} }
// CreateIssue creates an issue in the tracker // CreateNewIssue creates a new issue in the tracker
func (i *Integration) CreateIssue(event *output.ResultEvent) error { func (i *Integration) CreateNewIssue(event *output.ResultEvent) error {
summary := format.Summary(event) summary := format.Summary(event)
fields := &jira.IssueFields{ fields := &jira.IssueFields{
@ -92,6 +94,52 @@ func (i *Integration) CreateIssue(event *output.ResultEvent) error {
return nil return nil
} }
// CreateIssue creates an issue in the tracker or updates the existing one
func (i *Integration) CreateIssue(event *output.ResultEvent) error {
if i.options.UpdateExisting {
issueID, err := i.FindExistingIssue(event)
if err != nil {
return err
} else if issueID != "" {
_, _, err = i.jira.Issue.AddComment(issueID, &jira.Comment{
Body: jiraFormatDescription(event),
})
return err
}
}
return i.CreateNewIssue(event)
}
// FindExistingIssue checks if the issue already exists and returns its ID
func (i *Integration) FindExistingIssue(event *output.ResultEvent) (string, error) {
template := format.GetMatchedTemplate(event)
jql := fmt.Sprintf("summary ~ \"%s\" AND summary ~ \"%s\" AND status = \"Open\"", template, event.Host)
searchOptions := &jira.SearchOptions{
MaxResults: 1, // if any issue exists, then we won't create a new one
}
chunk, resp, err := i.jira.Issue.Search(jql, searchOptions)
if err != nil {
var data string
if resp != nil && resp.Body != nil {
d, _ := ioutil.ReadAll(resp.Body)
data = string(d)
}
return "", fmt.Errorf("%s => %s", err, data)
}
switch resp.Total {
case 0:
return "", nil
case 1:
return chunk[0].ID, nil
default:
gologger.Warning().Msgf("Discovered multiple opened issues %s for the host %s: The issue [%s] will be updated.", template, event.Host, chunk[0].ID)
return chunk[0].ID, nil
}
}
// jiraFormatDescription formats a short description of the generated // jiraFormatDescription formats a short description of the generated
// event by the nuclei scanner in Jira format. // event by the nuclei scanner in Jira format.
func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove the code duplication: format.go <-> jira.go func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove the code duplication: format.go <-> jira.go

View File

@ -4,13 +4,11 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"regexp"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/executer" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/executer"
@ -21,7 +19,6 @@ import (
var ( var (
ErrCreateTemplateExecutor = errors.New("cannot create template executer") ErrCreateTemplateExecutor = errors.New("cannot create template executer")
fieldErrorRegexp = regexp.MustCompile(`not found in`)
) )
var parsedTemplatesCache *cache.Templates var parsedTemplatesCache *cache.Templates
@ -56,12 +53,9 @@ func Parse(filePath string, preprocessor Preprocessor, options protocols.Execute
data = preprocessor.Process(data) data = preprocessor.Process(data)
} }
if err := yaml.UnmarshalStrict(data, template); err != nil { if err := yaml.Unmarshal(data, template); err != nil {
if !fieldErrorRegexp.MatchString(err.Error()) {
return nil, err return nil, err
} }
gologger.Warning().Msgf("Unrecognized fields in template %s: %s", filePath, err)
}
if utils.IsBlank(template.Info.Name) { if utils.IsBlank(template.Info.Name) {
return nil, errors.New("no template name field provided") return nil, errors.New("no template name field provided")

View File

@ -108,7 +108,7 @@ func init() {
MODELInfoDoc.Fields[1].Name = "author" MODELInfoDoc.Fields[1].Name = "author"
MODELInfoDoc.Fields[1].Type = "StringSlice" MODELInfoDoc.Fields[1].Type = "StringSlice"
MODELInfoDoc.Fields[1].Note = "" MODELInfoDoc.Fields[1].Note = ""
MODELInfoDoc.Fields[1].Description = "Author of the template." 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].Comments[encoder.LineComment] = "Author of the template."
MODELInfoDoc.Fields[1].AddExample("", "<username>") MODELInfoDoc.Fields[1].AddExample("", "<username>")
@ -188,7 +188,7 @@ func init() {
FieldName: "requests", FieldName: "requests",
}, },
} }
HTTPRequestDoc.Fields = make([]encoder.Doc, 24) HTTPRequestDoc.Fields = make([]encoder.Doc, 25)
HTTPRequestDoc.Fields[0].Name = "matchers" HTTPRequestDoc.Fields[0].Name = "matchers"
HTTPRequestDoc.Fields[0].Type = "[]matchers.Matcher" HTTPRequestDoc.Fields[0].Type = "[]matchers.Matcher"
HTTPRequestDoc.Fields[0].Note = "" HTTPRequestDoc.Fields[0].Note = ""
@ -225,8 +225,8 @@ func init() {
HTTPRequestDoc.Fields[5].Name = "id" HTTPRequestDoc.Fields[5].Name = "id"
HTTPRequestDoc.Fields[5].Type = "string" HTTPRequestDoc.Fields[5].Type = "string"
HTTPRequestDoc.Fields[5].Note = "" HTTPRequestDoc.Fields[5].Note = ""
HTTPRequestDoc.Fields[5].Description = "ID is the ID of the request" HTTPRequestDoc.Fields[5].Description = "ID is the the optional id of the request"
HTTPRequestDoc.Fields[5].Comments[encoder.LineComment] = " ID is the ID of the request" HTTPRequestDoc.Fields[5].Comments[encoder.LineComment] = " ID is the the optional id of the request"
HTTPRequestDoc.Fields[6].Name = "name" HTTPRequestDoc.Fields[6].Name = "name"
HTTPRequestDoc.Fields[6].Type = "string" HTTPRequestDoc.Fields[6].Type = "string"
HTTPRequestDoc.Fields[6].Note = "" HTTPRequestDoc.Fields[6].Note = ""
@ -349,6 +349,11 @@ func init() {
HTTPRequestDoc.Fields[23].Note = "" HTTPRequestDoc.Fields[23].Note = ""
HTTPRequestDoc.Fields[23].Description = "ReqCondition automatically assigns numbers to requests and preserves their history.\n\nThis allows matching on them later for multi-request conditions." HTTPRequestDoc.Fields[23].Description = "ReqCondition automatically assigns numbers to requests and preserves their history.\n\nThis allows matching on them later for multi-request conditions."
HTTPRequestDoc.Fields[23].Comments[encoder.LineComment] = "ReqCondition automatically assigns numbers to requests and preserves their history." HTTPRequestDoc.Fields[23].Comments[encoder.LineComment] = "ReqCondition automatically assigns numbers to requests and preserves their history."
HTTPRequestDoc.Fields[24].Name = "stop-at-first-match"
HTTPRequestDoc.Fields[24].Type = "bool"
HTTPRequestDoc.Fields[24].Note = ""
HTTPRequestDoc.Fields[24].Description = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
HTTPRequestDoc.Fields[24].Comments[encoder.LineComment] = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
MATCHERSMatcherDoc.Type = "matchers.Matcher" MATCHERSMatcherDoc.Type = "matchers.Matcher"
MATCHERSMatcherDoc.Comments[encoder.LineComment] = " Matcher is used to match a part in the output from a protocol." MATCHERSMatcherDoc.Comments[encoder.LineComment] = " Matcher is used to match a part in the output from a protocol."
@ -415,7 +420,7 @@ func init() {
MATCHERSMatcherDoc.Fields[4].Name = "name" MATCHERSMatcherDoc.Fields[4].Name = "name"
MATCHERSMatcherDoc.Fields[4].Type = "string" MATCHERSMatcherDoc.Fields[4].Type = "string"
MATCHERSMatcherDoc.Fields[4].Note = "" MATCHERSMatcherDoc.Fields[4].Note = ""
MATCHERSMatcherDoc.Fields[4].Description = "Name of the matcher. Name should be lowercase and must not contain\nspaces or dashes (-)." MATCHERSMatcherDoc.Fields[4].Description = "Name of the matcher. Name should be lowercase and must not contain\nspaces or underscores (_)."
MATCHERSMatcherDoc.Fields[4].Comments[encoder.LineComment] = "Name of the matcher. Name should be lowercase and must not contain" MATCHERSMatcherDoc.Fields[4].Comments[encoder.LineComment] = "Name of the matcher. Name should be lowercase and must not contain"
MATCHERSMatcherDoc.Fields[4].AddExample("", "cookie-matcher") MATCHERSMatcherDoc.Fields[4].AddExample("", "cookie-matcher")
@ -507,7 +512,7 @@ func init() {
EXTRACTORSExtractorDoc.Fields[0].Name = "name" EXTRACTORSExtractorDoc.Fields[0].Name = "name"
EXTRACTORSExtractorDoc.Fields[0].Type = "string" EXTRACTORSExtractorDoc.Fields[0].Type = "string"
EXTRACTORSExtractorDoc.Fields[0].Note = "" EXTRACTORSExtractorDoc.Fields[0].Note = ""
EXTRACTORSExtractorDoc.Fields[0].Description = "Name of the extractor. Name should be lowercase and must not contain\nspaces or dashes (-)." EXTRACTORSExtractorDoc.Fields[0].Description = "Name of the extractor. Name should be lowercase and must not contain\nspaces or underscores (_)."
EXTRACTORSExtractorDoc.Fields[0].Comments[encoder.LineComment] = "Name of the extractor. Name should be lowercase and must not contain" EXTRACTORSExtractorDoc.Fields[0].Comments[encoder.LineComment] = "Name of the extractor. Name should be lowercase and must not contain"
EXTRACTORSExtractorDoc.Fields[0].AddExample("", "cookie-extractor") EXTRACTORSExtractorDoc.Fields[0].AddExample("", "cookie-extractor")
@ -525,8 +530,8 @@ func init() {
EXTRACTORSExtractorDoc.Fields[2].Name = "regex" EXTRACTORSExtractorDoc.Fields[2].Name = "regex"
EXTRACTORSExtractorDoc.Fields[2].Type = "[]string" EXTRACTORSExtractorDoc.Fields[2].Type = "[]string"
EXTRACTORSExtractorDoc.Fields[2].Note = "" EXTRACTORSExtractorDoc.Fields[2].Note = ""
EXTRACTORSExtractorDoc.Fields[2].Description = "Regex contains the regular expression patterns to exract from a part.\n\nGo regex engine does not supports lookaheads or lookbehinds, so as a result\nthey are also not supported in nuclei." EXTRACTORSExtractorDoc.Fields[2].Description = "Regex contains the regular expression patterns to extract from a part.\n\nGo regex engine does not support lookaheads or lookbehinds, so as a result\nthey are also not supported in nuclei."
EXTRACTORSExtractorDoc.Fields[2].Comments[encoder.LineComment] = "Regex contains the regular expression patterns to exract from a part." EXTRACTORSExtractorDoc.Fields[2].Comments[encoder.LineComment] = "Regex contains the regular expression patterns to extract from a part."
EXTRACTORSExtractorDoc.Fields[2].AddExample("Braintree Access Token Regex", []string{"access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}"}) EXTRACTORSExtractorDoc.Fields[2].AddExample("Braintree Access Token Regex", []string{"access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}"})
@ -541,12 +546,8 @@ func init() {
EXTRACTORSExtractorDoc.Fields[4].Name = "kval" EXTRACTORSExtractorDoc.Fields[4].Name = "kval"
EXTRACTORSExtractorDoc.Fields[4].Type = "[]string" EXTRACTORSExtractorDoc.Fields[4].Type = "[]string"
EXTRACTORSExtractorDoc.Fields[4].Note = "" EXTRACTORSExtractorDoc.Fields[4].Note = ""
EXTRACTORSExtractorDoc.Fields[4].Description = "kval contains the key-value pairs required in the response.\n\nEach protocol exposes a lot of different data in response. The kval\nextractor can be used to extract those key-value pairs. A list of\nsupported parts is available in docs for request types." EXTRACTORSExtractorDoc.Fields[4].Description = "description: |\n kval contains the key-value pairs present in the HTTP response header.\n kval extractor can be used to extract HTTP response header and cookie key-value pairs.\n kval extractor inputs are case insensitive, and does not support dash (-) in input which can replaced with underscores (_)\n For example, Content-Type should be replaced with content_type\n\n A list of supported parts is available in docs for request types.\n examples:\n - name: Extract Server Header From HTTP Response\n value: >\n []string{\"server\"}\n - name: Extracting value of PHPSESSID Cookie\n value: >\n []string{\"phpsessid\"}\n - name: Extracting value of Content-Type Cookie\n value: >\n []string{\"content_type\"}"
EXTRACTORSExtractorDoc.Fields[4].Comments[encoder.LineComment] = "kval contains the key-value pairs required in the response." EXTRACTORSExtractorDoc.Fields[4].Comments[encoder.LineComment] = " description: |"
EXTRACTORSExtractorDoc.Fields[4].AddExample("Extract Server Header From HTTP Response", []string{"Server"})
EXTRACTORSExtractorDoc.Fields[4].AddExample("Extracting value of PHPSESSID Cookie", []string{"PHPSESSID"})
EXTRACTORSExtractorDoc.Fields[5].Name = "json" EXTRACTORSExtractorDoc.Fields[5].Name = "json"
EXTRACTORSExtractorDoc.Fields[5].Type = "[]string" EXTRACTORSExtractorDoc.Fields[5].Type = "[]string"
EXTRACTORSExtractorDoc.Fields[5].Note = "" EXTRACTORSExtractorDoc.Fields[5].Note = ""
@ -563,8 +564,6 @@ func init() {
EXTRACTORSExtractorDoc.Fields[6].Comments[encoder.LineComment] = "XPath allows using xpath expressions to extract items from html response" EXTRACTORSExtractorDoc.Fields[6].Comments[encoder.LineComment] = "XPath allows using xpath expressions to extract items from html response"
EXTRACTORSExtractorDoc.Fields[6].AddExample("", []string{"/html/body/div/p[2]/a"}) EXTRACTORSExtractorDoc.Fields[6].AddExample("", []string{"/html/body/div/p[2]/a"})
EXTRACTORSExtractorDoc.Fields[6].AddExample("", []string{".batters | .batter | .[] | .id"})
EXTRACTORSExtractorDoc.Fields[7].Name = "attribute" EXTRACTORSExtractorDoc.Fields[7].Name = "attribute"
EXTRACTORSExtractorDoc.Fields[7].Type = "string" EXTRACTORSExtractorDoc.Fields[7].Type = "string"
EXTRACTORSExtractorDoc.Fields[7].Note = "" EXTRACTORSExtractorDoc.Fields[7].Note = ""
@ -621,8 +620,8 @@ func init() {
DNSRequestDoc.Fields[3].Name = "id" DNSRequestDoc.Fields[3].Name = "id"
DNSRequestDoc.Fields[3].Type = "string" DNSRequestDoc.Fields[3].Type = "string"
DNSRequestDoc.Fields[3].Note = "" DNSRequestDoc.Fields[3].Note = ""
DNSRequestDoc.Fields[3].Description = "ID is the ID of the request" DNSRequestDoc.Fields[3].Description = "ID is the the optional id of the request"
DNSRequestDoc.Fields[3].Comments[encoder.LineComment] = " ID is the ID of the request" DNSRequestDoc.Fields[3].Comments[encoder.LineComment] = " ID is the the optional id of the request"
DNSRequestDoc.Fields[4].Name = "name" DNSRequestDoc.Fields[4].Name = "name"
DNSRequestDoc.Fields[4].Type = "string" DNSRequestDoc.Fields[4].Type = "string"
DNSRequestDoc.Fields[4].Note = "" DNSRequestDoc.Fields[4].Note = ""
@ -652,12 +651,12 @@ func init() {
DNSRequestDoc.Fields[6].Description = "Class is the class of the DNS request.\n\nUsually it's enough to just leave it as INET." DNSRequestDoc.Fields[6].Description = "Class is the class of the DNS request.\n\nUsually it's enough to just leave it as INET."
DNSRequestDoc.Fields[6].Comments[encoder.LineComment] = "Class is the class of the DNS request." DNSRequestDoc.Fields[6].Comments[encoder.LineComment] = "Class is the class of the DNS request."
DNSRequestDoc.Fields[6].Values = []string{ DNSRequestDoc.Fields[6].Values = []string{
"INET", "inet",
"CSNET", "csnet",
"CHAOS", "chaos",
"HESIOD", "hesiod",
"NONE", "none",
"ANY", "any",
} }
DNSRequestDoc.Fields[7].Name = "retries" DNSRequestDoc.Fields[7].Name = "retries"
DNSRequestDoc.Fields[7].Type = "int" DNSRequestDoc.Fields[7].Type = "int"
@ -720,8 +719,8 @@ func init() {
FILERequestDoc.Fields[5].Name = "id" FILERequestDoc.Fields[5].Name = "id"
FILERequestDoc.Fields[5].Type = "string" FILERequestDoc.Fields[5].Type = "string"
FILERequestDoc.Fields[5].Note = "" FILERequestDoc.Fields[5].Note = ""
FILERequestDoc.Fields[5].Description = "ID is the ID of the request" FILERequestDoc.Fields[5].Description = "ID is the the optional id of the request"
FILERequestDoc.Fields[5].Comments[encoder.LineComment] = " ID is the ID of the request" FILERequestDoc.Fields[5].Comments[encoder.LineComment] = " ID is the the optional id of the request"
FILERequestDoc.Fields[6].Name = "max-size" FILERequestDoc.Fields[6].Name = "max-size"
FILERequestDoc.Fields[6].Type = "int" FILERequestDoc.Fields[6].Type = "int"
FILERequestDoc.Fields[6].Note = "" FILERequestDoc.Fields[6].Note = ""
@ -750,8 +749,8 @@ func init() {
NETWORKRequestDoc.Fields[0].Name = "id" NETWORKRequestDoc.Fields[0].Name = "id"
NETWORKRequestDoc.Fields[0].Type = "string" NETWORKRequestDoc.Fields[0].Type = "string"
NETWORKRequestDoc.Fields[0].Note = "" NETWORKRequestDoc.Fields[0].Note = ""
NETWORKRequestDoc.Fields[0].Description = "ID is the ID of the request" NETWORKRequestDoc.Fields[0].Description = "ID is the the optional id of the request"
NETWORKRequestDoc.Fields[0].Comments[encoder.LineComment] = " ID is the ID of the request" NETWORKRequestDoc.Fields[0].Comments[encoder.LineComment] = " ID is the the optional id of the request"
NETWORKRequestDoc.Fields[1].Name = "host" NETWORKRequestDoc.Fields[1].Name = "host"
NETWORKRequestDoc.Fields[1].Type = "[]string" NETWORKRequestDoc.Fields[1].Type = "[]string"
NETWORKRequestDoc.Fields[1].Note = "" NETWORKRequestDoc.Fields[1].Note = ""
@ -862,8 +861,8 @@ func init() {
HEADLESSRequestDoc.Fields[0].Name = "id" HEADLESSRequestDoc.Fields[0].Name = "id"
HEADLESSRequestDoc.Fields[0].Type = "string" HEADLESSRequestDoc.Fields[0].Type = "string"
HEADLESSRequestDoc.Fields[0].Note = "" HEADLESSRequestDoc.Fields[0].Note = ""
HEADLESSRequestDoc.Fields[0].Description = "ID is the ID of the request" HEADLESSRequestDoc.Fields[0].Description = "ID is the the optional id of the request"
HEADLESSRequestDoc.Fields[0].Comments[encoder.LineComment] = " ID is the ID of the request" HEADLESSRequestDoc.Fields[0].Comments[encoder.LineComment] = " ID is the the optional id of the request"
HEADLESSRequestDoc.Fields[1].Name = "steps" HEADLESSRequestDoc.Fields[1].Name = "steps"
HEADLESSRequestDoc.Fields[1].Type = "[]engine.Action" HEADLESSRequestDoc.Fields[1].Type = "[]engine.Action"
HEADLESSRequestDoc.Fields[1].Note = "" HEADLESSRequestDoc.Fields[1].Note = ""

View File

@ -16,10 +16,10 @@ import (
var ( var (
exampleInfoStructure = model.Info{ exampleInfoStructure = model.Info{
Name: "Argument Injection in Ruby Dragonfly", Name: "Argument Injection in Ruby Dragonfly",
Authors: model.StringSlice{[]string{"0xspara"}}, Authors: model.StringSlice{"0xspara"},
SeverityHolder: severity.SeverityHolder{severity.High}, SeverityHolder: severity.SeverityHolder{severity.High},
Reference: model.StringSlice{"https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/"}, Reference: model.StringSlice{"https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/"},
Tags: model.StringSlice{[]string{"cve,cve2021,rce,ruby"}}, Tags: model.StringSlice{"cve,cve2021,rce,ruby"},
} }
exampleNormalHTTPRequest = &http.Request{ exampleNormalHTTPRequest = &http.Request{
Method: "GET", Method: "GET",

View File

@ -65,8 +65,8 @@ type Options struct {
StatsInterval int StatsInterval int
// MetricsPort is the port to show metrics on // MetricsPort is the port to show metrics on
MetricsPort int MetricsPort int
// HostMaxErrors is the maximum number of errors allowed for a host // MaxHostError is the maximum number of errors allowed for a host
HostMaxErrors int MaxHostError int
// BulkSize is the of targets analyzed in parallel for each template // BulkSize is the of targets analyzed in parallel for each template
BulkSize int BulkSize int
// TemplateThreads is the number of templates executed in parallel // TemplateThreads is the number of templates executed in parallel

View File

@ -0,0 +1,3 @@
// Package stats provides a storage mechanism for storing
// and display vital statistics of the engine at various durations.
package stats

View File

@ -0,0 +1,99 @@
package stats
import (
"sync"
"sync/atomic"
"github.com/projectdiscovery/gologger"
)
// Storage is a storage for storing statistics information
// about the nuclei engine displaying it at user-defined intervals.
type Storage struct {
data map[string]*storageDataItem
mutex *sync.RWMutex
}
type storageDataItem struct {
description string
value int64
}
var Default *Storage
func init() {
Default = New()
}
// NewEntry creates a new entry in the storage object
func NewEntry(name, description string) {
Default.NewEntry(name, description)
}
// Increment incrmements the value for a name string
func Increment(name string) {
Default.Increment(name)
}
// Display displays the stats for a name
func Display(name string) {
Default.Display(name)
}
// GetValue returns the value for a set variable
func GetValue(name string) int64 {
return Default.GetValue(name)
}
// New creates a new storage object
func New() *Storage {
return &Storage{data: make(map[string]*storageDataItem), mutex: &sync.RWMutex{}}
}
// NewEntry creates a new entry in the storage object
func (s *Storage) NewEntry(name, description string) {
s.mutex.Lock()
s.data[name] = &storageDataItem{description: description, value: 0}
s.mutex.Unlock()
}
// Increment incrmements the value for a name string
func (s *Storage) Increment(name string) {
s.mutex.RLock()
data, ok := s.data[name]
s.mutex.RUnlock()
if !ok {
return
}
atomic.AddInt64(&data.value, 1)
}
// Display displays the stats for a name
func (s *Storage) Display(name string) {
s.mutex.RLock()
data, ok := s.data[name]
s.mutex.RUnlock()
if !ok {
return
}
dataValue := atomic.LoadInt64(&data.value)
if dataValue == 0 {
return // don't show for nil stats
}
gologger.Error().Label("WRN").Msgf(data.description, dataValue)
}
// GetValue returns the value for a set variable
func (s *Storage) GetValue(name string) int64 {
s.mutex.RLock()
data, ok := s.data[name]
s.mutex.RUnlock()
if !ok {
return 0
}
dataValue := atomic.LoadInt64(&data.value)
return dataValue
}

View File

@ -60,10 +60,8 @@ Examples:
```yaml ```yaml
info: info:
name: Argument Injection in Ruby Dragonfly name: Argument Injection in Ruby Dragonfly
author: author: 0xspara
- 0xspara tags: cve,cve2021,rce,ruby
tags:
- cve,cve2021,rce,ruby
reference: https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/ reference: https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/
severity: high severity: high
``` ```
@ -248,10 +246,8 @@ Appears in:
```yaml ```yaml
name: Argument Injection in Ruby Dragonfly name: Argument Injection in Ruby Dragonfly
author: author: 0xspara
- 0xspara tags: cve,cve2021,rce,ruby
tags:
- cve,cve2021,rce,ruby
reference: https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/ reference: https://zxsecurity.co.nz/research/argunment-injection-ruby-dragonfly/
severity: high severity: high
``` ```
@ -294,6 +290,8 @@ name: Nagios Default Credentials Check
Author of the template. Author of the template.
Multiple values can also be specified separated by commas.
Examples: Examples:
@ -620,7 +618,7 @@ raw:
</div> </div>
<div class="dt"> <div class="dt">
ID is the ID of the request ID is the the optional id of the request
</div> </div>
@ -1005,6 +1003,19 @@ This allows matching on them later for multi-request conditions.
<hr /> <hr />
<div class="dd">
<code>stop-at-first-match</code> <i>bool</i>
</div>
<div class="dt">
StopAtFirstMatch stops the execution of the requests and template as soon as a match is found.
</div>
<hr />
@ -1130,7 +1141,7 @@ It will only match if the condition is not true.
<div class="dt"> <div class="dt">
Name of the matcher. Name should be lowercase and must not contain Name of the matcher. Name should be lowercase and must not contain
spaces or dashes (-). spaces or underscores (_).
@ -1373,7 +1384,7 @@ Appears in:
<div class="dt"> <div class="dt">
Name of the extractor. Name should be lowercase and must not contain Name of the extractor. Name should be lowercase and must not contain
spaces or dashes (-). spaces or underscores (_).
@ -1420,9 +1431,9 @@ Valid values:
</div> </div>
<div class="dt"> <div class="dt">
Regex contains the regular expression patterns to exract from a part. Regex contains the regular expression patterns to extract from a part.
Go regex engine does not supports lookaheads or lookbehinds, so as a result Go regex engine does not support lookaheads or lookbehinds, so as a result
they are also not supported in nuclei. they are also not supported in nuclei.
@ -1478,29 +1489,23 @@ group: 1
</div> </div>
<div class="dt"> <div class="dt">
kval contains the key-value pairs required in the response. description: |
kval contains the key-value pairs present in the HTTP response header.
Each protocol exposes a lot of different data in response. The kval kval extractor can be used to extract HTTP response header and cookie key-value pairs.
extractor can be used to extract those key-value pairs. A list of kval extractor inputs are case insensitive, and does not support dash (-) in input which can replaced with underscores (_)
supported parts is available in docs for request types. For example, Content-Type should be replaced with content_type
Examples:
```yaml
# Extract Server Header From HTTP Response
kval:
- Server
```
```yaml
# Extracting value of PHPSESSID Cookie
kval:
- PHPSESSID
```
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"}
</div> </div>
@ -1554,11 +1559,6 @@ xpath:
- /html/body/div/p[2]/a - /html/body/div/p[2]/a
``` ```
```yaml
xpath:
- .batters | .batter | .[] | .id
```
</div> </div>
@ -1718,7 +1718,7 @@ Valid values:
</div> </div>
<div class="dt"> <div class="dt">
ID is the ID of the request ID is the the optional id of the request
</div> </div>
@ -1798,17 +1798,17 @@ Usually it's enough to just leave it as INET.
Valid values: Valid values:
- <code>INET</code> - <code>inet</code>
- <code>CSNET</code> - <code>csnet</code>
- <code>CHAOS</code> - <code>chaos</code>
- <code>HESIOD</code> - <code>hesiod</code>
- <code>NONE</code> - <code>none</code>
- <code>ANY</code> - <code>any</code>
</div> </div>
<hr /> <hr />
@ -1988,7 +1988,7 @@ denylist:
</div> </div>
<div class="dt"> <div class="dt">
ID is the ID of the request ID is the the optional id of the request
</div> </div>
@ -2068,7 +2068,7 @@ matchers:
</div> </div>
<div class="dt"> <div class="dt">
ID is the ID of the request ID is the the optional id of the request
</div> </div>
@ -2374,7 +2374,7 @@ Appears in:
</div> </div>
<div class="dt"> <div class="dt">
ID is the ID of the request ID is the the optional id of the request
</div> </div>