Compare commits

..
Author SHA1 Message Date
Ice3man 38f25f5263 feat: fixed analyzer timeout issue + missing case fix 2024-12-02 17:10:36 +05:30
dependabot[bot] 0fc4a02a05 chore(deps): bump github.com/projectdiscovery/hmap from 0.0.68 to 0.0.69 (#5874)
Bumps [github.com/projectdiscovery/hmap](https://github.com/projectdiscovery/hmap) from 0.0.68 to 0.0.69.
- [Release notes](https://github.com/projectdiscovery/hmap/releases)
- [Commits](https://github.com/projectdiscovery/hmap/compare/v0.0.68...v0.0.69)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/hmap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 14:50:57 +05:30
Dogan Can Bakir b649829bc3 update version (#5877) 2024-12-02 14:50:41 +05:30
dependabot[bot] 9a3053e9be Merge pull request #5873 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/wappalyzergo-0.2.5 2024-12-02 09:12:24 +00:00
dependabot[bot] 889972f3de Merge pull request #5872 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/rawhttp-0.1.76 2024-12-02 09:11:10 +00:00
dependabot[bot] f7d30f6389 chore(deps): bump github.com/projectdiscovery/rawhttp
Bumps [github.com/projectdiscovery/rawhttp](https://github.com/projectdiscovery/rawhttp) from 0.1.74 to 0.1.76.
- [Release notes](https://github.com/projectdiscovery/rawhttp/releases)
- [Commits](https://github.com/projectdiscovery/rawhttp/compare/v0.1.74...v0.1.76)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/rawhttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-12-02 09:05:08 +00:00
dependabot[bot] 36aae9cc55 chore(deps): bump github.com/projectdiscovery/wappalyzergo
Bumps [github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo) from 0.2.4 to 0.2.5.
- [Release notes](https://github.com/projectdiscovery/wappalyzergo/releases)
- [Commits](https://github.com/projectdiscovery/wappalyzergo/compare/v0.2.4...v0.2.5)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/wappalyzergo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-12-02 09:05:06 +00:00
dependabot[bot] a12bd9fbf8 chore(deps): bump github.com/projectdiscovery/utils from 0.2.21 to 0.3.0 (#5875)
Bumps [github.com/projectdiscovery/utils](https://github.com/projectdiscovery/utils) from 0.2.21 to 0.3.0.
- [Release notes](https://github.com/projectdiscovery/utils/releases)
- [Changelog](https://github.com/projectdiscovery/utils/blob/main/CHANGELOG.md)
- [Commits](https://github.com/projectdiscovery/utils/compare/v0.2.21...v0.3.0)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/utils
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 14:33:56 +05:30
dependabot[bot] 4bb9374207 chore(deps): bump github.com/projectdiscovery/ratelimit (#5871)
Bumps [github.com/projectdiscovery/ratelimit](https://github.com/projectdiscovery/ratelimit) from 0.0.61 to 0.0.64.
- [Release notes](https://github.com/projectdiscovery/ratelimit/releases)
- [Commits](https://github.com/projectdiscovery/ratelimit/compare/v0.0.61...v0.0.64)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/ratelimit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 14:33:46 +05:30
Tarun Koyalwar 16735f5243 fix template signing singnature issue (#5869)
* fix incorrect .gitignore

* template signer utility tool

* use yaml marhsal & unmarshal for normalization

* normalize before verification
2024-12-02 14:31:46 +05:30
Richard Brown 557b4fba38 removed trailing comma from the jsonl exporter (#5861)
* removed trailing comma from the jsonl exporter

* adding the O_TRUNC flag when opening the file to explicitly indicate that the file should be truncated if it exists.
2024-12-01 18:45:22 +05:30
Dogan Can Bakir 1f985459b8 add max-os-threads flag (#5622)
* add `max-os-threads` flag

* minor

* use global pkg
2024-11-27 20:06:26 +05:30
Dwi Siswanto 3a07fa9c22 feat: add -enable-global-matchers flag (#5857)
* feat: add `-enable-global-matchers` flag

Signed-off-by: Dwi Siswanto <[email protected]>

* refactor(templates): use embedded `types.Options` in `Template`

Signed-off-by: Dwi Siswanto <[email protected]>

* feat(lib): add `EnableGlobalMatchersTemplates` SDK opt

Signed-off-by: Dwi Siswanto <[email protected]>

---------

Signed-off-by: Dwi Siswanto <[email protected]>
2024-11-27 14:37:59 +05:30
dependabot[bot] b2d4efef1e Merge pull request #5853 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/gologger-1.1.33 2024-11-25 17:23:56 +00:00
dependabot[bot] 36262a4152 Merge pull request #5852 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/fastdialer-0.2.10 2024-11-25 15:24:01 +00:00
dependabot[bot] 7fb7b7ad92 Merge pull request #5851 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/retryabledns-1.0.86 2024-11-25 15:23:30 +00:00
dependabot[bot] a0ec8a0546 chore(deps): bump github.com/projectdiscovery/retryabledns
Bumps [github.com/projectdiscovery/retryabledns](https://github.com/projectdiscovery/retryabledns) from 1.0.85 to 1.0.86.
- [Release notes](https://github.com/projectdiscovery/retryabledns/releases)
- [Commits](https://github.com/projectdiscovery/retryabledns/compare/v1.0.85...v1.0.86)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/retryabledns
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-25 12:35:57 +00:00
dependabot[bot] a229666d41 Merge pull request #5850 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/retryablehttp-go-1.0.88 2024-11-25 12:34:40 +00:00
dependabot[bot] e0ea25d856 chore(deps): bump github.com/projectdiscovery/gologger
Bumps [github.com/projectdiscovery/gologger](https://github.com/projectdiscovery/gologger) from 1.1.31 to 1.1.33.
- [Release notes](https://github.com/projectdiscovery/gologger/releases)
- [Commits](https://github.com/projectdiscovery/gologger/compare/v1.1.31...v1.1.33)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/gologger
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-25 12:11:13 +00:00
dependabot[bot] 13dfe8802a chore(deps): bump github.com/projectdiscovery/retryablehttp-go
Bumps [github.com/projectdiscovery/retryablehttp-go](https://github.com/projectdiscovery/retryablehttp-go) from 1.0.86 to 1.0.88.
- [Release notes](https://github.com/projectdiscovery/retryablehttp-go/releases)
- [Commits](https://github.com/projectdiscovery/retryablehttp-go/compare/v1.0.86...v1.0.88)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/retryablehttp-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-25 12:11:12 +00:00
dependabot[bot] 97b8c510a1 chore(deps): bump github.com/projectdiscovery/fastdialer
Bumps [github.com/projectdiscovery/fastdialer](https://github.com/projectdiscovery/fastdialer) from 0.2.9 to 0.2.10.
- [Release notes](https://github.com/projectdiscovery/fastdialer/releases)
- [Commits](https://github.com/projectdiscovery/fastdialer/compare/v0.2.9...v0.2.10)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/fastdialer
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-25 12:11:07 +00:00
dependabot[bot] fa6a7e8486 Merge pull request #5849 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/wappalyzergo-0.2.4 2024-11-25 12:09:58 +00:00
dependabot[bot] fbe2981e8d chore(deps): bump github.com/projectdiscovery/wappalyzergo
Bumps [github.com/projectdiscovery/wappalyzergo](https://github.com/projectdiscovery/wappalyzergo) from 0.2.2 to 0.2.4.
- [Release notes](https://github.com/projectdiscovery/wappalyzergo/releases)
- [Commits](https://github.com/projectdiscovery/wappalyzergo/compare/v0.2.2...v0.2.4)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/wappalyzergo
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-25 05:58:15 +00:00
Dogan Can Bakir 436c386272 respect defaults when listing templates (#5846)
* respect defaults when listing templates

* filter out headless, code and dast templates
2024-11-23 06:21:55 +05:30
Dwi Siswanto 28abf56e75 ci(generate-docs): push w/o pull (#5843)
Signed-off-by: Dwi Siswanto <[email protected]>
2024-11-21 18:48:25 +05:30
sandeep a09fcc196b auto gen docs update 2024-11-21 18:16:12 +05:30
alban-stourbe-wmxandTarun Koyalwar 2b4b058886 handle env variables in dynamic secret file (#5835)
* handle env variables in dynamic secret file

* inject more variables from -v and -env-vars

* use expand with env

* fix missing replacer

---------

Co-authored-by: Tarun Koyalwar <[email protected]>
2024-11-21 16:34:13 +05:30
Dogan Can Bakirandsandeep 63687c2ce0 disable self-contained and file protocol templates as default (#5825)
* disable self-contained and file protocol templates as default

* make excluding default

* add config funcs

* fix wrn display

* fix integration tests

* enable self-contained templates when code templates are enabled

---------

Co-authored-by: sandeep <[email protected]>
2024-11-19 22:00:28 +05:30
dependabot[bot] abfd43268a chore(deps): bump github.com/projectdiscovery/hmap from 0.0.65 to 0.0.67 (#5832)
Bumps [github.com/projectdiscovery/hmap](https://github.com/projectdiscovery/hmap) from 0.0.65 to 0.0.67.
- [Release notes](https://github.com/projectdiscovery/hmap/releases)
- [Commits](https://github.com/projectdiscovery/hmap/compare/v0.0.65...v0.0.67)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/hmap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-19 11:52:34 +05:30
Ice3man b046f7686f feat: Added time based delay analyzer to fuzzing implementation (#5781)
* feat: added fuzzing output enhancements

* changes as requested

* misc

* feat: added dfp flag to display fuzz points + misc additions

* feat: added support for fuzzing nested path segments

* feat: added parts to fuzzing requests

* feat: added tracking for parameter occurence frequency in fuzzing

* added cli flag for fuzz frequency

* fixed broken tests

* fixed path based sqli integration test

* feat: added configurable fuzzing aggression level for payloads

* fixed failing test

* feat: added analyzers implementation for fuzzing

* feat: misc changes to analyzer

* feat: misc additions of units + tests fix

* misc changes to implementation
2024-11-19 11:51:32 +05:30
Dwi SiswantoandIce3man 13af7ccd49 fix: data race at protocolstate, contextargs & some outdated test cases (#5820)
* test(flow): update outdated test cases

Signed-off-by: Dwi Siswanto <[email protected]>

* test(multiproto): update outdated test cases

Signed-off-by: Dwi Siswanto <[email protected]>

* feat: fixed failing tests

* fixed data race

* fixed memgaurdian race conditiong

* test(customtemplates): use test repo

Signed-off-by: Dwi Siswanto <[email protected]>

* feat(customtemplates): add more `{Clone,Pull}Options`

Signed-off-by: Dwi Siswanto <[email protected]>

* feat(customtemplates): validate `{Clone,Pull}Options`

Signed-off-by: Dwi Siswanto <[email protected]>

* bugfix: fixed failing integration tests for flow and multi

* chore: either 1 or 2 results in interactsh

---------

Signed-off-by: Dwi Siswanto <[email protected]>
Co-authored-by: Ice3man <[email protected]>
2024-11-19 11:08:25 +05:30
dependabot[bot] 40c83ddb18 Merge pull request #5831 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/retryabledns-1.0.85 2024-11-18 15:11:51 +00:00
dependabot[bot] e07c61689e chore(deps): bump github.com/projectdiscovery/retryabledns
Bumps [github.com/projectdiscovery/retryabledns](https://github.com/projectdiscovery/retryabledns) from 1.0.83 to 1.0.85.
- [Release notes](https://github.com/projectdiscovery/retryabledns/releases)
- [Commits](https://github.com/projectdiscovery/retryabledns/compare/v1.0.83...v1.0.85)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/retryabledns
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-18 12:43:47 +00:00
dependabot[bot] 91a18c79fc Merge pull request #5830 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/goflags-0.1.65 2024-11-18 12:41:24 +00:00
dependabot[bot] c76421d3d8 Merge pull request #5829 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/dsl-0.3.3 2024-11-18 12:41:06 +00:00
dependabot[bot] 26311c1668 Merge pull request #5828 from projectdiscovery/dependabot/go_modules/dev/github.com/projectdiscovery/rawhttp-0.1.74 2024-11-18 12:40:39 +00:00
dependabot[bot] e7d628c414 chore(deps): bump github.com/projectdiscovery/goflags
Bumps [github.com/projectdiscovery/goflags](https://github.com/projectdiscovery/goflags) from 0.1.64 to 0.1.65.
- [Release notes](https://github.com/projectdiscovery/goflags/releases)
- [Commits](https://github.com/projectdiscovery/goflags/compare/v0.1.64...v0.1.65)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/goflags
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-18 05:48:36 +00:00
dependabot[bot] 54e81c96f1 chore(deps): bump github.com/projectdiscovery/dsl from 0.3.0 to 0.3.3
Bumps [github.com/projectdiscovery/dsl](https://github.com/projectdiscovery/dsl) from 0.3.0 to 0.3.3.
- [Release notes](https://github.com/projectdiscovery/dsl/releases)
- [Commits](https://github.com/projectdiscovery/dsl/compare/v0.3.0...v0.3.3)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/dsl
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-18 05:48:28 +00:00
dependabot[bot] afc24616a4 chore(deps): bump github.com/projectdiscovery/rawhttp
Bumps [github.com/projectdiscovery/rawhttp](https://github.com/projectdiscovery/rawhttp) from 0.1.73 to 0.1.74.
- [Release notes](https://github.com/projectdiscovery/rawhttp/releases)
- [Commits](https://github.com/projectdiscovery/rawhttp/compare/v0.1.73...v0.1.74)

---
updated-dependencies:
- dependency-name: github.com/projectdiscovery/rawhttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2024-11-18 05:48:21 +00:00
Keith Chason ba6a050d48 Batch JSONL output and add trailing commas (#5705) 2024-11-15 15:45:44 +05:30
72 changed files with 1420 additions and 379 deletions

No files matched your search

-1
View File
@@ -24,5 +24,4 @@ jobs:
SYNTAX-REFERENCE.md
nuclei-jsonschema.json
message: 'docs: update syntax & JSON schema 🤖'
- run: git pull origin $GITHUB_REF --rebase
- run: git push origin $GITHUB_REF
+19 -19
View File
@@ -2,8 +2,8 @@
**/*-cache
**/*-config
**/.cache
*.DS_Store
*.exe
**/*.DS_Store
**/*.exe
.devcontainer
.gitignore
.idea
@@ -11,23 +11,23 @@
# Binaries
/bin/*
**/bindgen
**/debug-*
**/docgen
**/functional-test
**/fuzzplayground
**/integration-test
**/jsdocgen
**/main
**/memogen
**/nuclei
**/nuclei-stats*
**/nuclei_dev
**/nuclei_main
**/scan-charts
**/scrapefunc
**/scrapefuncs
**/tsgen
/bindgen
/debug-*
/docgen
/functional-test
/fuzzplayground
/integration-test
/jsdocgen
/main
/memogen
/nuclei
/nuclei-stats*
/nuclei_dev
/nuclei_main
/scan-charts
/scrapefunc
/scrapefuncs
/tsgen
# Templates
/*.yaml
+4
View File
@@ -42,6 +42,10 @@ scan-charts: GOBUILD_OUTPUT = ./bin/scan-charts
scan-charts: GOBUILD_PACKAGES = cmd/scan-charts/main.go
scan-charts: go-build
template-signer: GOBUILD_OUTPUT = ./bin/template-signer
template-signer: GOBUILD_PACKAGES = cmd/tools/signer/main.go
template-signer: go-build
docgen: GOBUILD_OUTPUT = ./bin/docgen
docgen: GOBUILD_PACKAGES = cmd/docgen/docgen.go
docgen: bin = dstdocgen
+66
View File
@@ -1373,6 +1373,19 @@ Fuzzing describes schema to fuzz http requests
<div class="dd">
<code>analyzer</code> <i><a href="#analyzersanalyzertemplate">analyzers.AnalyzerTemplate</a></i>
</div>
<div class="dt">
Analyzer is an analyzer to use for matching the response.
</div>
<hr />
<div class="dd">
<code>self-contained</code> <i>bool</i>
</div>
@@ -2025,6 +2038,59 @@ Appears in:
## analyzers.AnalyzerTemplate
AnalyzerTemplate is the template for the analyzer
Appears in:
- <code><a href="#httprequest">http.Request</a>.analyzer</code>
<hr />
<div class="dd">
<code>name</code> <i>string</i>
</div>
<div class="dt">
Name is the name of the analyzer to use
Valid values:
- <code>time_delay</code>
</div>
<hr />
<div class="dd">
<code>parameters</code> <i>map[string]interface{}</i>
</div>
<div class="dt">
Parameters is the parameters for the analyzer
Parameters are different for each analyzer. For example, you can customize
time_delay analyzer with sleep_duration, time_slope_error_range, etc. Refer
to the docs for each analyzer to get an idea about parameters.
</div>
<hr />
## SignatureTypeHolder
SignatureTypeHolder is used to hold internal type of the signature
+1 -1
View File
@@ -99,7 +99,7 @@ type codePreCondition struct{}
// Execute executes a test case and returns an error if occurred
func (h *codePreCondition) Execute(filePath string) error {
results, err := testutils.RunNucleiArgsWithEnvAndGetResults(debug, getEnvValues(), "-t", filePath, "-u", "input", "-code", "-var", "foo=bar")
results, err := testutils.RunNucleiArgsWithEnvAndGetResults(debug, getEnvValues(), "-t", filePath, "-u", "input", "-code", "-esc")
if err != nil {
return err
}
+3 -3
View File
@@ -15,7 +15,7 @@ type fileWithOrMatcher struct{}
// Execute executes a test case and returns an error if occurred
func (h *fileWithOrMatcher) Execute(filePath string) error {
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug, "-file")
if err != nil {
return err
}
@@ -27,7 +27,7 @@ type fileWithAndMatcher struct{}
// Execute executes a test case and returns an error if occurred
func (h *fileWithAndMatcher) Execute(filePath string) error {
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug, "-file")
if err != nil {
return err
}
@@ -39,7 +39,7 @@ type fileWithExtractor struct{}
// Execute executes a test case and returns an error if occurred
func (h *fileWithExtractor) Execute(filePath string) error {
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug, "-file")
if err != nil {
return err
}
+1 -1
View File
@@ -22,7 +22,7 @@ var flowTestcases = []TestCaseInfo{
type conditionalFlow struct{}
func (t *conditionalFlow) Execute(filePath string) error {
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "blog.projectdiscovery.io", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "cloud.projectdiscovery.io", debug)
if err != nil {
return err
}
+4 -4
View File
@@ -155,7 +155,7 @@ func (h *httpInteractshRequest) Execute(filePath string) error {
return err
}
return expectResultsCount(results, 1)
return expectResultsCount(results, 1, 2)
}
type httpDefaultMatcherCondition struct{}
@@ -952,7 +952,7 @@ func (h *httpRequestSelfContained) Execute(filePath string) error {
}()
defer server.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-var foo=bar")
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
if err != nil {
return err
}
@@ -988,7 +988,7 @@ func (h *httpRequestSelfContainedWithParams) Execute(filePath string) error {
}()
defer server.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-var foo=bar")
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
if err != nil {
return err
}
@@ -1031,7 +1031,7 @@ func (h *httpRequestSelfContainedFileInput) Execute(filePath string) error {
}
defer FileLoc.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-V", "test="+FileLoc.Name())
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-V", "test="+FileLoc.Name(), "-esc")
if err != nil {
return err
}
+1 -1
View File
@@ -14,7 +14,7 @@ type multiProtoDynamicExtractor struct{}
// Execute executes a test case and returns an error if occurred
func (h *multiProtoDynamicExtractor) Execute(templatePath string) error {
results, err := testutils.RunNucleiTemplateAndGetResults(templatePath, "blog.projectdiscovery.io", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(templatePath, "docs.projectdiscovery.io", debug)
if err != nil {
return err
}
+1 -1
View File
@@ -119,7 +119,7 @@ func (h *networkRequestSelContained) Execute(filePath string) error {
_, _ = conn.Write([]byte("Authentication successful"))
})
defer ts.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-var foo=bar")
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
if err != nil {
return err
}
+8
View File
@@ -263,6 +263,9 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVar(&options.SignTemplates, "sign", false, "signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable"),
flagSet.BoolVar(&options.EnableCodeTemplates, "code", false, "enable loading code protocol-based templates"),
flagSet.BoolVarP(&options.DisableUnsignedTemplates, "disable-unsigned-templates", "dut", false, "disable running unsigned templates or templates with mismatched signature"),
flagSet.BoolVarP(&options.EnableSelfContainedTemplates, "enable-self-contained", "esc", false, "enable loading self-contained templates"),
flagSet.BoolVarP(&options.EnableGlobalMatchersTemplates, "enable-global-matchers", "egm", false, "enable loading global matchers templates"),
flagSet.BoolVar(&options.EnableFileTemplates, "file", false, "enable loading file templates"),
)
flagSet.CreateGroup("filters", "Filtering",
@@ -492,6 +495,11 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
options.DAST = true
}
// All cloud-based templates depend on both code and self-contained templates.
if options.EnableCodeTemplates {
options.EnableSelfContainedTemplates = true
}
// api key hierarchy: cli flag > env var > .pdcp/credential file
if pdcpauth == "true" {
runner.AuthWithPDCP()
+1
View File
@@ -69,6 +69,7 @@ func init() {
// need to set headless to true for headless templates
defaultOpts.Headless = true
defaultOpts.EnableCodeTemplates = true
defaultOpts.EnableSelfContainedTemplates = true
if err := protocolstate.Init(defaultOpts); err != nil {
gologger.Fatal().Msgf("Could not initialize protocol state: %s\n", err)
}
+114
View File
@@ -0,0 +1,114 @@
package main
import (
"crypto/sha256"
"encoding/hex"
"flag"
"os"
"path/filepath"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/gologger/levels"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
"github.com/projectdiscovery/nuclei/v3/pkg/templates/signer"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
fileutil "github.com/projectdiscovery/utils/file"
folderutil "github.com/projectdiscovery/utils/folder"
)
var (
appConfigDir = folderutil.AppConfigDirOrDefault(".config", "nuclei")
defaultCertFile = filepath.Join(appConfigDir, "keys", "nuclei-user.crt")
defaultPrivKey = filepath.Join(appConfigDir, "keys", "nuclei-user-private-key.pem")
)
var (
template string
cert string
privKey string
)
func main() {
flag.StringVar(&template, "template", "", "template to sign (file only)")
flag.StringVar(&cert, "cert", defaultCertFile, "certificate file")
flag.StringVar(&privKey, "priv-key", defaultPrivKey, "private key file")
flag.Parse()
config.DefaultConfig.LogAllEvents = true
gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
if template == "" {
gologger.Fatal().Msg("template is required")
}
if !fileutil.FileExists(template) {
gologger.Fatal().Msgf("template file %s does not exist or not a file", template)
}
// get signer
tmplSigner, err := signer.NewTemplateSignerFromFiles(cert, privKey)
if err != nil {
gologger.Fatal().Msgf("failed to create signer: %s", err)
}
gologger.Info().Msgf("Template Signer: %v\n", tmplSigner.Identifier())
// read file
bin, err := os.ReadFile(template)
if err != nil {
gologger.Fatal().Msgf("failed to read template file %s: %s", template, err)
}
// extract signature and content
sig, content := signer.ExtractSignatureAndContent(bin)
hash := sha256.Sum256(content)
gologger.Info().Msgf("Signature Details:")
gologger.Info().Msgf("----------------")
gologger.Info().Msgf("Signature: %s", sig)
gologger.Info().Msgf("Content Hash (SHA256): %s\n", hex.EncodeToString(hash[:]))
execOpts := defaultExecutorOpts(template)
tmpl, err := templates.Parse(template, nil, execOpts)
if err != nil {
gologger.Fatal().Msgf("failed to parse template: %s", err)
}
gologger.Info().Msgf("Template Verified: %v\n", tmpl.Verified)
if !tmpl.Verified {
gologger.Info().Msgf("------------------------")
gologger.Info().Msg("Template is not verified, signing template")
if err := templates.SignTemplate(tmplSigner, template); err != nil {
gologger.Fatal().Msgf("Failed to sign template: %s", err)
}
// verify again by reading file what the new signature and hash is
bin2, err := os.ReadFile(template)
if err != nil {
gologger.Fatal().Msgf("failed to read signed template file %s: %s", template, err)
}
sig2, content2 := signer.ExtractSignatureAndContent(bin2)
hash2 := sha256.Sum256(content2)
gologger.Info().Msgf("Updated Signature Details:")
gologger.Info().Msgf("------------------------")
gologger.Info().Msgf("Signature: %s", sig2)
gologger.Info().Msgf("Content Hash (SHA256): %s\n", hex.EncodeToString(hash2[:]))
}
gologger.Info().Msgf("✓ Template signed & verified successfully")
}
func defaultExecutorOpts(templatePath string) protocols.ExecutorOptions {
// use parsed options when initializing signer instead of default options
options := types.DefaultOptions()
templates.UseOptionsForSigner(options)
catalog := disk.NewCatalog(filepath.Dir(templatePath))
executerOpts := protocols.ExecutorOptions{
Catalog: catalog,
Options: options,
TemplatePath: templatePath,
Parser: templates.NewParser(),
}
return executerOpts
}
+19 -19
View File
@@ -20,12 +20,12 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/errors v0.9.1
github.com/projectdiscovery/clistats v0.1.1
github.com/projectdiscovery/fastdialer v0.2.9
github.com/projectdiscovery/hmap v0.0.65
github.com/projectdiscovery/fastdialer v0.2.10
github.com/projectdiscovery/hmap v0.0.69
github.com/projectdiscovery/interactsh v1.2.0
github.com/projectdiscovery/rawhttp v0.1.73
github.com/projectdiscovery/retryabledns v1.0.83
github.com/projectdiscovery/retryablehttp-go v1.0.86
github.com/projectdiscovery/rawhttp v0.1.76
github.com/projectdiscovery/retryabledns v1.0.86
github.com/projectdiscovery/retryablehttp-go v1.0.88
github.com/projectdiscovery/yamldoc-go v1.0.4
github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.5.0
@@ -38,9 +38,9 @@ require (
github.com/weppos/publicsuffix-go v0.30.2
github.com/xanzy/go-gitlab v0.107.0
go.uber.org/multierr v1.11.0
golang.org/x/net v0.30.0
golang.org/x/net v0.31.0
golang.org/x/oauth2 v0.22.0
golang.org/x/text v0.19.0
golang.org/x/text v0.20.0
gopkg.in/yaml.v2 v2.4.0
)
@@ -81,33 +81,33 @@ require (
github.com/microsoft/go-mssqldb v1.6.0
github.com/ory/dockertest/v3 v3.10.0
github.com/praetorian-inc/fingerprintx v1.1.9
github.com/projectdiscovery/dsl v0.3.0
github.com/projectdiscovery/dsl v0.3.3
github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
github.com/projectdiscovery/goflags v0.1.64
github.com/projectdiscovery/gologger v1.1.31
github.com/projectdiscovery/goflags v0.1.65
github.com/projectdiscovery/gologger v1.1.33
github.com/projectdiscovery/gostruct v0.0.2
github.com/projectdiscovery/gozero v0.0.3
github.com/projectdiscovery/httpx v1.6.9
github.com/projectdiscovery/mapcidr v1.1.34
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
github.com/projectdiscovery/ratelimit v0.0.61
github.com/projectdiscovery/ratelimit v0.0.64
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917
github.com/projectdiscovery/sarif v0.0.1
github.com/projectdiscovery/tlsx v1.1.8
github.com/projectdiscovery/uncover v1.0.9
github.com/projectdiscovery/useragent v0.0.78
github.com/projectdiscovery/utils v0.2.17
github.com/projectdiscovery/wappalyzergo v0.2.2
github.com/projectdiscovery/utils v0.3.0
github.com/projectdiscovery/wappalyzergo v0.2.5
github.com/redis/go-redis/v9 v9.1.0
github.com/seh-msft/burpxml v1.0.1
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
github.com/stretchr/testify v1.9.0
github.com/stretchr/testify v1.10.0
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9
github.com/yassinebenaid/godump v0.10.0
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706
go.mongodb.org/mongo-driver v1.17.0
golang.org/x/term v0.25.0
golang.org/x/term v0.26.0
gopkg.in/yaml.v3 v3.0.1
moul.io/http2curl v1.0.0
)
@@ -152,6 +152,7 @@ require (
github.com/docker/docker v24.0.9+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/fgprof v0.9.5 // indirect
github.com/free5gc/util v1.0.5-0.20230511064842-2e120956883b // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gaissmai/bart v0.9.5 // indirect
@@ -214,7 +215,6 @@ require (
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb // indirect
github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect
github.com/refraction-networking/utls v1.6.7 // indirect
github.com/samber/lo v1.44.0 // indirect
github.com/sashabaranov/go-openai v1.15.3 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
@@ -247,7 +247,7 @@ require (
github.com/zeebo/blake3 v0.2.3 // indirect
go.uber.org/goleak v1.3.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sync v0.9.0 // indirect
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
mellium.im/sasl v0.3.1 // indirect
)
@@ -314,10 +314,10 @@ require (
go.etcd.io/bbolt v1.3.10 // indirect
go.uber.org/zap v1.25.0 // indirect
goftp.io/server/v2 v2.0.1 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
google.golang.org/protobuf v1.34.2 // indirect
+47 -38
View File
@@ -237,12 +237,18 @@ github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
@@ -325,6 +331,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@@ -577,6 +585,7 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
@@ -671,6 +680,7 @@ github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa h1:KQKuQDgA3DZX6C396lt3WDYB9Um1gLITLbvficVbqXk=
@@ -804,6 +814,7 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
@@ -845,26 +856,26 @@ github.com/projectdiscovery/cdncheck v1.1.0 h1:qDITidmJsejzpk3rMkauCh6sjI2GH9hW/
github.com/projectdiscovery/cdncheck v1.1.0/go.mod h1:sZ8U4MjHSsyaTVjBbYWHT1cwUVvUYwDX1W+WvWRicIc=
github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB72JIg66c8wE=
github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0=
github.com/projectdiscovery/dsl v0.3.0 h1:NzU6WcJ8GFQ676IVefrxC5nk/bvb7FCuhmp8tbNC9dQ=
github.com/projectdiscovery/dsl v0.3.0/go.mod h1:GMVxLtQuQUc/RmSn3jQxGCI4yit3iyf2AoZxUoXbsb0=
github.com/projectdiscovery/fastdialer v0.2.9 h1:vDCqxVMCyUu3oVEizEK1K8K+CCcLkVDW3X2HfiWaVFA=
github.com/projectdiscovery/fastdialer v0.2.9/go.mod h1:mYv5QaNBDDSHlZO9DI0niRMw+G5hUzwIhs8QixSElUI=
github.com/projectdiscovery/dsl v0.3.3 h1:4Ij5S86cHlb6xFrS7+5zAiJPeBt5h970XBTHqeTkpyU=
github.com/projectdiscovery/dsl v0.3.3/go.mod h1:DAjSeaogLM9f0Ves2zDc/vbJrfcv+kEmS51p0dLLaPI=
github.com/projectdiscovery/fastdialer v0.2.10 h1:5iciZXMPdynbk/9iuqkJT1gqMXwzgEpFSWdoj/5CHCo=
github.com/projectdiscovery/fastdialer v0.2.10/go.mod h1:21rwXMecVsPVdSvON8Up761/GgxC4OSc9Rvx5LNH5fY=
github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA=
github.com/projectdiscovery/fasttemplate v0.0.2/go.mod h1:XYWWVMxnItd+r0GbjA1GCsUopMw1/XusuQxdyAIHMCw=
github.com/projectdiscovery/freeport v0.0.7 h1:Q6uXo/j8SaV/GlAHkEYQi8WQoPXyJWxyspx+aFmz9Qk=
github.com/projectdiscovery/freeport v0.0.7/go.mod h1:cOhWKvNBe9xM6dFJ3RrrLvJ5vXx2NQ36SecuwjenV2k=
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb h1:rutG906Drtbpz4DwU5mhGIeOhRcktDH4cGQitGUMAsg=
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb/go.mod h1:FLjF1DmZ+POoGEiIQdWuYVwS++C/GwpX8YaCsTSm1RY=
github.com/projectdiscovery/goflags v0.1.64 h1:FDfwdt9N97Hi8OuhbkDlKtVttpc/CRMIWQVa08VsHsI=
github.com/projectdiscovery/goflags v0.1.64/go.mod h1:3FyHIVQtnycNOc1LE3O1jj/XR5XuMdF9QfHd0ujhnX4=
github.com/projectdiscovery/gologger v1.1.31 h1:FlZi1RsDoRtOkj9+a1PhcOmwD3NdRpDyjp/0/fmpQ/s=
github.com/projectdiscovery/gologger v1.1.31/go.mod h1:zVbkxOmWuh1GEyr6dviEPNwH/GMWdnJrMUSOJbRmDqI=
github.com/projectdiscovery/goflags v0.1.65 h1:rjoj+5lP/FDzgeM0WILUTX9AOOnw0J0LXtl8P1SVeGE=
github.com/projectdiscovery/goflags v0.1.65/go.mod h1:cg6+yrLlaekP1hnefBc/UXbH1YGWa0fuzEW9iS1aG4g=
github.com/projectdiscovery/gologger v1.1.33 h1:wQxaQ8p/0Rx89lowBp0PnY2QSWiqf9QW1vGYAllsVJ4=
github.com/projectdiscovery/gologger v1.1.33/go.mod h1:P/WwqKstshQATJxN39V0KJ9ZuiGLOizmSqHIYrrz1T4=
github.com/projectdiscovery/gostruct v0.0.2 h1:s8gP8ApugGM4go1pA+sVlPDXaWqNP5BBDDSv7VEdG1M=
github.com/projectdiscovery/gostruct v0.0.2/go.mod h1:H86peL4HKwMXcQQtEa6lmC8FuD9XFt6gkNR0B/Mu5PE=
github.com/projectdiscovery/gozero v0.0.3 h1:tsYkrSvWw4WdIUJyisd4MB1vRiw1X57TuVVk3p8Z3G8=
github.com/projectdiscovery/gozero v0.0.3/go.mod h1:MpJ37Dsh94gy2EKqaemdeh+CzduGVB2SDfhr6Upsjew=
github.com/projectdiscovery/hmap v0.0.65 h1:jR0GfHOJE5pUmHPVqHg8O2uRoAB4MQn8V6pcE6oVoZg=
github.com/projectdiscovery/hmap v0.0.65/go.mod h1:H3Z/YMYX7T0xF/BR2sAxgXTcyPGS8sxdqmh2yoP7/VE=
github.com/projectdiscovery/hmap v0.0.69 h1:e30pCr6JShf/UyJmKQpx++Yceiijw4GWj3lFHGZ1yko=
github.com/projectdiscovery/hmap v0.0.69/go.mod h1:LgZHcgcxOvA3X8tuFtfu4dofJjAHAfpMno27Jx0J34w=
github.com/projectdiscovery/httpx v1.6.9 h1:ihyFclesLjvQpiJpRIlAYeebapyIbOI/arDAvvy1ES8=
github.com/projectdiscovery/httpx v1.6.9/go.mod h1:zQtX5CtcDYXzIRWne1ztCVtqG0sXCnx84tFwfMHoB8Q=
github.com/projectdiscovery/interactsh v1.2.0 h1:Al6jHiR+Usl9egYJDLJaWNHOcH8Rugk8gWMasc8Cmw8=
@@ -879,16 +890,16 @@ github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 h1:L/e8z8yw
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5/go.mod h1:pGW2ncnTxTxHtP9wzcIJAB+3/NMp6IiuQWd2NK7K+oc=
github.com/projectdiscovery/networkpolicy v0.0.9 h1:IrlDoYZagNNO8y+7iZeHT8k5izE+nek7TdtvEBwCxqk=
github.com/projectdiscovery/networkpolicy v0.0.9/go.mod h1:XFJ2Lnv8BE/ziQCFjBHMsH1w6VmkPiQtk+NlBpdMU7M=
github.com/projectdiscovery/ratelimit v0.0.61 h1:n9PD4Z4Y6cLeT2rn9IiOAA0I/kIZE/D7z7z5X/WQds8=
github.com/projectdiscovery/ratelimit v0.0.61/go.mod h1:u7DxBBcUzFg4Cb2s5yabmtCMJs+ojulNpNrSLtftoKg=
github.com/projectdiscovery/rawhttp v0.1.73 h1:uzOgj1XrDx2Qbr8qjP5bKdnOkxwyt5kbYcOquTSktMo=
github.com/projectdiscovery/rawhttp v0.1.73/go.mod h1:zfQZCjQzpd8kvAqyV4Rj0oArifLSxmQwSyQ4w4rm56M=
github.com/projectdiscovery/ratelimit v0.0.64 h1:fDjCM+U9HqJU6+NBvJn0kY89PxD20iWvRFX1mLblRB8=
github.com/projectdiscovery/ratelimit v0.0.64/go.mod h1:XVuisddIjhmdd9ukw+w90AkSJd3pEKBTG9fBvSjwVxs=
github.com/projectdiscovery/rawhttp v0.1.76 h1:O2IoYSyG7unH5oW8r8j3539koCNkimyzcHFmCbx5BDU=
github.com/projectdiscovery/rawhttp v0.1.76/go.mod h1:ZxvbdkRV2PBoCbJxHh9B0P0nC5gVG3p1Z5uiua3iC5I=
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gBVSorSzvmm0bFa7gDV4QNSOWPL/fgZ4kTXBxk=
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg=
github.com/projectdiscovery/retryabledns v1.0.83 h1:qevo2GBDr/BSSb5W9PxudXhu477uOz1mH1Kk0maGfVY=
github.com/projectdiscovery/retryabledns v1.0.83/go.mod h1:t9DWqUdr3wdc1iIuAozefhDpPfIqDnu0q9BpJO4Mq5M=
github.com/projectdiscovery/retryablehttp-go v1.0.86 h1:r/rqVrT/fSMe6/syIq1FGd8do/vt+Kgca9pFegyHG88=
github.com/projectdiscovery/retryablehttp-go v1.0.86/go.mod h1:upk8ItKt9hayUp6Z7E60tH314BAnIUQ5y4KS4x9R90g=
github.com/projectdiscovery/retryabledns v1.0.86 h1:8YMJGJ94lFBKKN3t7NOzJfbGsZoh9qNpi49xdfJcZVc=
github.com/projectdiscovery/retryabledns v1.0.86/go.mod h1:5PhXvlLkEFmlYOt9i4wiKA1eONLrNiZ6DQE88Ph9rgU=
github.com/projectdiscovery/retryablehttp-go v1.0.88 h1:uR6T+i8Sy1isfG1KClhhsXnOqkOR6E8MAvuyOFq3T10=
github.com/projectdiscovery/retryablehttp-go v1.0.88/go.mod h1:ktjiIKyej+plUeK9vksqRf3wGicqY3E1rW84V/O7p0M=
github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us=
github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ=
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=
@@ -899,10 +910,10 @@ github.com/projectdiscovery/uncover v1.0.9 h1:s5RbkD/V4r8QcPkys4gTTqMuRSgXq0Jpre
github.com/projectdiscovery/uncover v1.0.9/go.mod h1:2PUF3SpB5QNIJ8epaB2xbRzkPaxEAWRDm3Ir2ijt81U=
github.com/projectdiscovery/useragent v0.0.78 h1:YpgiY3qXpzygFA88SWVseAyWeV9ZKrIpDkfOY+mQ/UY=
github.com/projectdiscovery/useragent v0.0.78/go.mod h1:SQgk2DZu1qCvYqBRYWs2sjenXqLEDnRw65wJJoolwZ4=
github.com/projectdiscovery/utils v0.2.17 h1:zRlZN/21TXURWO7FenQGRBzkT9ziz+/nPuZ7wd84IPM=
github.com/projectdiscovery/utils v0.2.17/go.mod h1:reZl7z57TfuBKfLUaPFcri0tqbqwjujyFDqd+yxq5gk=
github.com/projectdiscovery/wappalyzergo v0.2.2 h1:AQT6+oo++HOcseTFSTa2en08vWv5miE/NgnJlqL1lCQ=
github.com/projectdiscovery/wappalyzergo v0.2.2/go.mod h1:k3aujwFsLcB24ppzwNE0lYpV3tednKGJVTbk4JgrhmI=
github.com/projectdiscovery/utils v0.3.0 h1:JNRMUPMx2gSzdk3bOQPtXSucoz+qC1JVkibIn7+kPTk=
github.com/projectdiscovery/utils v0.3.0/go.mod h1:k2XlmfaYO4k6T4vAyUa3Kn/0BxPTIlNiBFpM6nVCbz0=
github.com/projectdiscovery/wappalyzergo v0.2.5 h1:DhPEgeD+9i6yg+aGlbkT4iOAspQfB5ZzrmpEhwoiMlA=
github.com/projectdiscovery/wappalyzergo v0.2.5/go.mod h1:fXiqsyLHaX/ovBNUe/nX0318bWON6SHftLvgq1xaOq0=
github.com/projectdiscovery/yamldoc-go v1.0.4 h1:eZoESapnMw6WAHiVgRwNqvbJEfNHEH148uthhFbG5jE=
github.com/projectdiscovery/yamldoc-go v1.0.4/go.mod h1:8PIPRcUD55UbtQdcfFR1hpIGRWG0P7alClXNGt1TBik=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -959,8 +970,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
github.com/samber/lo v1.44.0 h1:5il56KxRE+GHsm1IR+sZ/6J42NODigFiqCWpSc2dybA=
github.com/samber/lo v1.44.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sashabaranov/go-openai v1.15.3 h1:rzoNK9n+Cak+PM6OQ9puxDmFllxfnVea9StlmhglXqA=
github.com/sashabaranov/go-openai v1.15.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
@@ -1023,8 +1032,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9 h1:GXIyLuIJ5Qk46lI8WJ83qHBZKUI3zhmMmuoY9HICUIQ=
@@ -1214,8 +1223,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1308,8 +1317,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1334,8 +1343,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1410,8 +1419,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
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=
@@ -1424,8 +1433,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1442,8 +1451,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+2 -2
View File
@@ -14,7 +14,7 @@ dns:
matchers:
- type: word
words:
- "ghost.io"
- ".vercel-dns.com"
internal: true
http:
@@ -25,4 +25,4 @@ http:
matchers:
- type: word
words:
- "ghost.io"
- "html>"
@@ -23,4 +23,4 @@ code:
- type: dsl
dsl:
- true
# digest: 4a0a0047304502200307590191cb7c766b6c21e5777d345bdddf7adf9d6da8f7d336d585d9ac4a8b022100fd30fb0c7722778eb3d861d60e721d805925b8d8df2b979ef2104c35ec57d5cb:4a3eb6b4988d95847d4203be25ed1d46
# digest: 490a00463044022048c083c338c0195f5012122d40c1009d2e2030c583e56558e0d6249a41e6f3f4022070656adf748f4874018d7a01fce116db10a3acd1f9b03e12a83906fb625b5c50:4a3eb6b4988d95847d4203be25ed1d46
@@ -20,4 +20,4 @@ code:
- type: word
words:
- "hello from input baz"
# digest: 4a0a0047304502203fe1d7d52bc2a41886d576a90c82c3be42078baaa4b46e1f3d8519665d6f88b202210081feb82c41150c5b218e226fc4f299ded19f42ba01ef34ba60b0634b4ea6ee12:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4b0a00483046022100cbbdb7214f669d111b671d271110872dc8af2ab41cf5c312b6e4f64126f55337022100a60547952a0c2bea58388f2d2effe8ad73cd6b6fc92e73eb3c8f88beab6105ec:4a3eb6b4988d95847d4203be25ed1d46
@@ -18,4 +18,4 @@ code:
- type: word
words:
- "hello from input"
# digest: 4b0a00483046022100afb5ebff14a40e7f9b679ffc4d93ce7849e33eb398ebb47f2e757cd24831f9dd02210089ffa21b2763e99ebce95dfc5b91e1e62da4ccdc9d2ad5c48584fa350ba335af:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4a0a00473045022032b81e8bb7475abf27639b0ced71355497166d664698021f26498e7031d62a23022100e99ccde578bfc0b658f16427ae9a3d18922849d3ba3e022032ea0d2a8e77fadb:4a3eb6b4988d95847d4203be25ed1d46
@@ -26,4 +26,4 @@ code:
part: interactsh_protocol
words:
- "http"
# digest: 4b0a00483046022100939f83e74d43932a5bd792b1fd2c100eec2df60f2b2a8dd56b5c8ef5faa92b17022100f93031b0de373af7d78e623968ea5a2d67c4561ef70e3e6da15aef7e5c853115:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4a0a0047304502201a5dd0eddfab4f02588a5a8ac1947a5fa41fed80b59d698ad5cc00456296efb6022100fe6e608e38c060964800f5f863a7cdc93f686f2d0f4b52854f73948b808b4511:4a3eb6b4988d95847d4203be25ed1d46
@@ -21,4 +21,4 @@ code:
- type: word
words:
- "hello from input"
# digest: 4a0a00473045022100b8e676ce0c57b60c233a0203539dec20457bbb5f1790d351a5d45405b6668b2602204b1f2fa18e7db099f05329009597ceb2d9b7337562c1a676e8d50ea2f1c6fcbe:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4b0a00483046022100ced1702728cc68f906c4c7d2c4d05ed071bfabee1e36eec7ebecbeca795a170c022100d20fd41796f130a8f9c4972fee85386d67d61eb5fc1119b1afe2a851eb2f3e65:4a3eb6b4988d95847d4203be25ed1d46
@@ -13,7 +13,7 @@ dns:
- type: dsl
name: blogid
dsl:
- trim_suffix(cname,'.ghost.io')
- trim_suffix(cname,'.vercel-dns.com')
internal: true
http:
@@ -24,6 +24,6 @@ http:
matchers:
- type: dsl
dsl:
- contains(body,'ProjectDiscovery.io') # check for http string
- blogid == 'projectdiscovery' # check for cname (extracted information from dns response)
- contains(body,'introduction') # check for http string
- blogid == 'cname' # check for cname (extracted information from dns response)
condition: and
@@ -7,7 +7,7 @@ info:
variables:
cname_filtered: '{{trim_suffix(dns_cname,".ghost.io")}}'
cname_filtered: '{{trim_suffix(dns_cname,".vercel-dns.com")}}'
dns:
- name: "{{FQDN}}" # DNS Request
@@ -24,7 +24,7 @@ http:
matchers:
- type: dsl
dsl:
- contains(http_body,'ProjectDiscovery.io') # check for http string
- cname_filtered == 'projectdiscovery' # check for cname (extracted information from dns response)
- ssl_subject_cn == 'blog.projectdiscovery.io'
- contains(http_body,'introduction') # check for http string
- cname_filtered == 'cname' # check for cname (extracted information from dns response)
- ssl_subject_cn == 'docs.projectdiscovery.io'
condition: and
@@ -20,7 +20,7 @@ http:
matchers:
- type: dsl
dsl:
- contains(http_body,'ProjectDiscovery.io') # check for http string
- trim_suffix(dns_cname,'.ghost.io') == 'projectdiscovery' # check for cname (extracted information from dns response)
- ssl_subject_cn == 'blog.projectdiscovery.io'
- contains(http_body,'introduction') # check for http string
- trim_suffix(dns_cname,'.vercel-dns.com') == 'cname' # check for cname (extracted information from dns response)
- ssl_subject_cn == 'docs.projectdiscovery.io'
condition: and
@@ -19,4 +19,4 @@ code:
regex:
- 'hello from (.*)'
group: 1
# digest: 490a00463044022050da011362cf08c2cb81e812c7f86d7282afe0562d4bf00d390f1300d19bc910022029e9d305da69e941ac18797645aecb217abde6557f891e141301b48e89a3c0cd:4a3eb6b4988d95847d4203be25ed1d46
# digest: 490a0046304402206b3648e8d393ac4df82c7d59b1a6ee3731c66c249dbd4d9bf31f0b7f176b37ec02203184d36373e516757c7d708b5799bc16edb1cebc0a64f3442d13ded4b33c42fb:4a3eb6b4988d95847d4203be25ed1d46
@@ -18,4 +18,4 @@ code:
- type: word
words:
- "hello from first"
# digest: 4b0a00483046022100b3b8759c0df028455eb59b1433ac240e5d4604b011bb0c63680bd3cc159ac6f0022100f44aa11b640d11ad0e2902897f4eb51666ab3cd83c31dfd2590f6e43391e39b0:4a3eb6b4988d95847d4203be25ed1d46
# digest: 490a0046304402204cbb1bdf8370e49bb930b17460fb35e15f285a3b48b165736ac0e7ba2f9bc0fb022067c134790c4a2cf646b195aa4488e2c222266436e6bda47931908a28807bdb81:4a3eb6b4988d95847d4203be25ed1d46
+22
View File
@@ -3,6 +3,7 @@ package runner
import (
"context"
"fmt"
"strings"
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
@@ -10,9 +11,12 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/writer"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/utils/env"
errorutil "github.com/projectdiscovery/utils/errors"
)
@@ -75,7 +79,25 @@ func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret
vars := map[string]interface{}{}
mainCtx := context.Background()
ctx := scan.NewScanContext(mainCtx, contextargs.NewWithInput(mainCtx, d.Input))
cliVars := map[string]interface{}{}
if opts.ExecOpts.Options != nil {
// gets variables passed from cli -v and -env-vars
cliVars = generators.BuildPayloadFromOptions(opts.ExecOpts.Options)
}
for _, v := range d.Variables {
// Check if the template has any env variables and expand them
if strings.HasPrefix(v.Value, "$") {
env.ExpandWithEnv(&v.Value)
}
if strings.Contains(v.Value, "{{") {
// if variables had value like {{username}}, then replace it with the value from cliVars
// variables:
// - key: username
// value: {{username}}
v.Value = replacer.Replace(v.Value, cliVars)
}
vars[v.Key] = v.Value
ctx.Input.Add(v.Key, v.Value)
}
+10 -3
View File
@@ -304,10 +304,17 @@ func createReportingOptions(options *types.Options) (*reporting.Options, error)
OmitRaw: options.OmitRawRequests,
}
}
// Combine options.
if options.JSONLExport != "" {
reportingOptions.JSONLExporter = &jsonl.Options{
File: options.JSONLExport,
OmitRaw: options.OmitRawRequests,
// Combine the CLI options with the config file options with the CLI options taking precedence
if reportingOptions.JSONLExporter != nil {
reportingOptions.JSONLExporter.File = options.JSONLExport
reportingOptions.JSONLExporter.OmitRaw = options.OmitRawRequests
} else {
reportingOptions.JSONLExporter = &jsonl.Options{
File: options.JSONLExport,
OmitRaw: options.OmitRawRequests,
}
}
}
+2 -3
View File
@@ -536,7 +536,6 @@ func (r *Runner) RunEnumeration() error {
// if input type is not list (implicitly enable fuzzing)
r.options.DAST = true
}
store, err := loader.New(loaderConfig)
if err != nil {
return errors.Wrap(err, "Could not create loader.")
@@ -731,6 +730,8 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
stats.ForceDisplayWarning(templates.ExcludedCodeTmplStats)
stats.ForceDisplayWarning(templates.ExludedDastTmplStats)
stats.ForceDisplayWarning(templates.TemplatesExcludedStats)
stats.ForceDisplayWarning(templates.ExcludedFileStats)
stats.ForceDisplayWarning(templates.ExcludedSelfContainedStats)
}
if tmplCount == 0 && workflowCount == 0 {
@@ -745,8 +746,6 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
stats.DisplayAsWarning(httpProtocol.SetThreadToCountZero)
stats.ForceDisplayWarning(templates.SkippedUnsignedStats)
stats.ForceDisplayWarning(templates.SkippedRequestSignatureStats)
stats.ForceDisplayWarning(templates.SkippedSelfContainedStats)
stats.ForceDisplayWarning(templates.SkippedFileStats)
cfg := config.DefaultConfig
+25
View File
@@ -380,6 +380,31 @@ func WithSandboxOptions(allowLocalFileAccess bool, restrictLocalNetworkAccess bo
func EnableCodeTemplates() NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.opts.EnableCodeTemplates = true
e.opts.EnableSelfContainedTemplates = true
return nil
}
}
// EnableSelfContainedTemplates allows loading/executing self-contained templates
func EnableSelfContainedTemplates() NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.opts.EnableSelfContainedTemplates = true
return nil
}
}
// EnableGlobalMatchersTemplates allows loading/executing global-matchers templates
func EnableGlobalMatchersTemplates() NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.opts.EnableGlobalMatchersTemplates = true
return nil
}
}
// EnableFileTemplates allows loading/executing file protocol templates
func EnableFileTemplates() NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.opts.EnableFileTemplates = true
return nil
}
}
+2 -1
View File
@@ -3,11 +3,12 @@ package nuclei
import (
"context"
"fmt"
"github.com/projectdiscovery/nuclei/v3/pkg/input"
"strings"
"sync"
"time"
"github.com/projectdiscovery/nuclei/v3/pkg/input"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
+1
View File
@@ -144,6 +144,7 @@ func TestWithVarsNuclei(t *testing.T) {
}()
ne, err := nuclei.NewNucleiEngineCtx(
context.TODO(),
nuclei.EnableSelfContainedTemplates(),
nuclei.WithTemplatesOrWorkflows(nuclei.TemplateSources{Templates: []string{"http/token-spray/api-1forge.yaml"}}),
nuclei.WithVars([]string{"token=foobar"}),
nuclei.WithVerbosity(nuclei.VerbosityOptions{Debug: true}),
+21
View File
@@ -3,6 +3,22 @@
"$id": "https://templates.-template",
"$ref": "#/$defs/templates.Template",
"$defs": {
"analyzers.AnalyzerTemplate": {
"properties": {
"name": {
"type": "string"
},
"parameters": {
"$ref": "#/$defs/map[string]interface {}"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"name",
"parameters"
]
},
"code.Request": {
"properties": {
"matchers": {
@@ -785,6 +801,11 @@
"title": "fuzzin rules for http fuzzing",
"description": "Fuzzing describes rule schema to fuzz http requests"
},
"analyzer": {
"$ref": "#/$defs/analyzers.AnalyzerTemplate",
"title": "analyzer for http request",
"description": "Analyzer for HTTP Request"
},
"self-contained": {
"type": "boolean"
},
+1 -1
View File
@@ -31,7 +31,7 @@ const (
CLIConfigFileName = "config.yaml"
ReportingConfigFilename = "reporting-config.yaml"
// Version is the current version of nuclei
Version = `v3.3.6`
Version = `v3.3.7`
// Directory Names of custom templates
CustomS3TemplatesDirName = "s3"
CustomGitHubTemplatesDirName = "github"
+25 -63
View File
@@ -5,12 +5,10 @@ import (
"io"
"net/url"
"os"
"regexp"
"sort"
"strings"
"sync"
"github.com/Knetic/govaluate"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
@@ -19,7 +17,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader/filter"
"github.com/projectdiscovery/nuclei/v3/pkg/keys"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
templateTypes "github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
@@ -28,11 +25,9 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/workflows"
"github.com/projectdiscovery/retryablehttp-go"
errorutil "github.com/projectdiscovery/utils/errors"
fileutil "github.com/projectdiscovery/utils/file"
sliceutil "github.com/projectdiscovery/utils/slice"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
"github.com/samber/lo"
)
const (
@@ -303,6 +298,27 @@ func (store *Store) LoadTemplatesOnlyMetadata() error {
for templatePath := range validPaths {
template, _, _ := templatesCache.Has(templatePath)
if len(template.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
continue
}
if len(template.RequestsCode) > 0 && !store.config.ExecutorOptions.Options.EnableCodeTemplates {
continue
}
if template.IsFuzzing() && !store.config.ExecutorOptions.Options.DAST {
continue
}
if template.SelfContained && !store.config.ExecutorOptions.Options.EnableSelfContainedTemplates {
continue
}
if template.HasFileProtocol() && !store.config.ExecutorOptions.Options.EnableFileTemplates {
continue
}
if template != nil {
template.Path = templatePath
store.templates = append(store.templates, template)
@@ -495,18 +511,13 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
return
}
if parsed.SelfContained &&
store.config.ExecutorOptions.Options.Vars.IsEmpty() && !store.config.ExecutorOptions.Options.EnvironmentVariables &&
templateContainsUnresolvedVariables(templatePath) {
stats.Increment(templates.SkippedSelfContainedStats)
if parsed.SelfContained && !store.config.ExecutorOptions.Options.EnableSelfContainedTemplates {
stats.Increment(templates.ExcludedSelfContainedStats)
return
}
if parsed.HasFileProtocol() &&
lo.NoneBy(store.config.ExecutorOptions.Options.Targets, func(target string) bool {
return fileutil.FileOrFolderExists(target)
}) {
stats.Increment(templates.SkippedFileStats)
if parsed.HasFileProtocol() && !store.config.ExecutorOptions.Options.EnableFileTemplates {
stats.Increment(templates.ExcludedFileStats)
return
}
@@ -574,55 +585,6 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
return loadedTemplates.Slice
}
var (
numericalExpressionRegex = regexp.MustCompile(`^[0-9+\-/\W]+$`)
unresolvedVariablesRegex = regexp.MustCompile(`(?:%7[B|b]|\{){2}([^}]+)(?:%7[D|d]|\}){2}["'\)\}]*`)
)
// copy of the original function from pkg/protocols/common/expressions/variables.go:ContainsUnresolvedVariables
func templateContainsUnresolvedVariables(templatePath string) bool {
data, err := os.ReadFile(templatePath)
if err != nil {
return false
}
matches := unresolvedVariablesRegex.FindAllStringSubmatch(string(data), -1)
if len(matches) == 0 {
return false
}
var unresolvedVariables []string
for _, match := range matches {
if len(match) < 2 {
continue
}
// Skip if the match is an expression
if numericalExpressionRegex.MatchString(match[1]) {
continue
}
// or if it contains only literals (can be solved from expression engine)
if hasLiteralsOnly(match[1]) {
continue
}
unresolvedVariables = append(unresolvedVariables, match[1])
}
return len(unresolvedVariables) > 0
}
func hasLiteralsOnly(data string) bool {
expr, err := govaluate.NewEvaluableExpressionWithFunctions(data, dsl.HelperFunctions)
if err != nil {
return false
}
if expr != nil {
_, err = expr.Evaluate(nil)
return err == nil
}
return true
}
// IsHTTPBasedProtocolUsed returns true if http/headless protocol is being used for
// any templates.
func IsHTTPBasedProtocolUsed(store *Store) bool {
+31 -5
View File
@@ -137,33 +137,59 @@ getRepo:
// download the git repo to a given path
func (ctr *customTemplateGitHubRepo) cloneRepo(clonePath, githubToken string) error {
r, err := git.PlainClone(clonePath, false, &git.CloneOptions{
URL: ctr.gitCloneURL,
Auth: getAuth(ctr.owner, githubToken),
})
cloneOpts := &git.CloneOptions{
URL: ctr.gitCloneURL,
Auth: getAuth(ctr.owner, githubToken),
SingleBranch: true,
Depth: 1,
}
err := cloneOpts.Validate()
if err != nil {
return err
}
r, err := git.PlainClone(clonePath, false, cloneOpts)
if err != nil {
return errors.Errorf("%s/%s: %s", ctr.owner, ctr.reponame, err.Error())
}
// Add the user as well in the config. By default, user is not set
config, _ := r.Storer.Config()
config.User.Name = ctr.owner
return r.SetConfig(config)
}
// performs the git pull on given repo
func (ctr *customTemplateGitHubRepo) pullChanges(repoPath, githubToken string) error {
pullOpts := &git.PullOptions{
RemoteName: "origin",
Auth: getAuth(ctr.owner, githubToken),
SingleBranch: true,
Depth: 1,
}
err := pullOpts.Validate()
if err != nil {
return err
}
r, err := git.PlainOpen(repoPath)
if err != nil {
return err
}
w, err := r.Worktree()
if err != nil {
return err
}
err = w.Pull(&git.PullOptions{RemoteName: "origin", Auth: getAuth(ctr.owner, githubToken)})
err = w.Pull(pullOpts)
if err != nil {
return errors.Errorf("%s/%s: %s", ctr.owner, ctr.reponame, err.Error())
}
return nil
}
+2 -4
View File
@@ -22,14 +22,12 @@ func TestDownloadCustomTemplatesFromGitHub(t *testing.T) {
config.DefaultConfig.SetTemplatesDir(templatesDirectory)
options := testutils.DefaultOptions
options.GitHubTemplateRepo = []string{"projectdiscovery/nuclei-templates", "ehsandeep/nuclei-templates"}
options.GitHubToken = os.Getenv("GITHUB_TOKEN")
options.GitHubTemplateRepo = []string{"projectdiscovery/nuclei-templates-test"}
ctm, err := NewCustomTemplatesManager(options)
require.Nil(t, err, "could not create custom templates manager")
ctm.Download(context.Background())
require.DirExists(t, filepath.Join(templatesDirectory, "github", "projectdiscovery", "nuclei-templates"), "cloned directory does not exists")
require.DirExists(t, filepath.Join(templatesDirectory, "github", "ehsandeep", "nuclei-templates"), "cloned directory does not exists")
require.DirExists(t, filepath.Join(templatesDirectory, "github", "projectdiscovery", "nuclei-templates-test"), "cloned directory does not exists")
}
+103
View File
@@ -0,0 +1,103 @@
package analyzers
import (
"math/rand"
"strconv"
"strings"
"time"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
"github.com/projectdiscovery/retryablehttp-go"
)
// Analyzer is an interface for all the analyzers
// that can be used for the fuzzer
type Analyzer interface {
// Name returns the name of the analyzer
Name() string
// ApplyTransformation applies the transformation to the initial payload.
ApplyInitialTransformation(data string, params map[string]interface{}) string
// Analyze is the main function for the analyzer
Analyze(options *Options) (bool, string, error)
}
// AnalyzerTemplate is the template for the analyzer
type AnalyzerTemplate struct {
// description: |
// Name is the name of the analyzer to use
// values:
// - time_delay
Name string `json:"name" yaml:"name"`
// description: |
// Parameters is the parameters for the analyzer
//
// Parameters are different for each analyzer. For example, you can customize
// time_delay analyzer with sleep_duration, time_slope_error_range, etc. Refer
// to the docs for each analyzer to get an idea about parameters.
Parameters map[string]interface{} `json:"parameters" yaml:"parameters"`
}
var (
analyzers map[string]Analyzer
)
// RegisterAnalyzer registers a new analyzer
func RegisterAnalyzer(name string, analyzer Analyzer) {
analyzers[name] = analyzer
}
// GetAnalyzer returns the analyzer for a given name
func GetAnalyzer(name string) Analyzer {
return analyzers[name]
}
func init() {
analyzers = make(map[string]Analyzer)
}
// Options contains the options for the analyzer
type Options struct {
FuzzGenerated fuzz.GeneratedRequest
HttpClient *retryablehttp.Client
ResponseTimeDelay time.Duration
AnalyzerParameters map[string]interface{}
}
var (
random = rand.New(rand.NewSource(time.Now().UnixNano()))
)
// ApplyPayloadTransformations applies the payload transformations to the payload
// It supports the below payloads -
// - [RANDNUM] => random number between 1000 and 9999
// - [RANDSTR] => random string of 4 characters
func ApplyPayloadTransformations(value string) string {
randomInt := GetRandomInteger()
randomStr := randStringBytesMask(4)
value = strings.ReplaceAll(value, "[RANDNUM]", strconv.Itoa(randomInt))
value = strings.ReplaceAll(value, "[RANDSTR]", randomStr)
return value
}
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
)
func randStringBytesMask(n int) string {
b := make([]byte, n)
for i := 0; i < n; {
if idx := int(random.Int63() & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i++
}
}
return string(b)
}
// GetRandomInteger returns a random integer between 1000 and 9999
func GetRandomInteger() int {
return random.Intn(9000) + 1000
}
+168
View File
@@ -0,0 +1,168 @@
package time
import (
"fmt"
"io"
"net/http/httptrace"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers"
"github.com/projectdiscovery/retryablehttp-go"
)
// Analyzer is a time delay analyzer for the fuzzer
type Analyzer struct{}
const (
DefaultSleepDuration = int(5)
DefaultRequestsLimit = int(4)
DefaultTimeCorrelationErrorRange = float64(0.15)
DefaultTimeSlopeErrorRange = float64(0.30)
defaultSleepTimeDuration = 5 * time.Second
)
var _ analyzers.Analyzer = &Analyzer{}
func init() {
analyzers.RegisterAnalyzer("time_delay", &Analyzer{})
}
// Name is the name of the analyzer
func (a *Analyzer) Name() string {
return "time_delay"
}
// ApplyInitialTransformation applies the transformation to the initial payload.
//
// It supports the below payloads -
// - [SLEEPTIME] => sleep_duration
// - [INFERENCE] => Inference payload for time delay analyzer
//
// It also applies the payload transformations to the payload
// which includes [RANDNUM] and [RANDSTR]
func (a *Analyzer) ApplyInitialTransformation(data string, params map[string]interface{}) string {
duration := DefaultSleepDuration
if len(params) > 0 {
if v, ok := params["sleep_duration"]; ok {
duration, ok = v.(int)
if !ok {
duration = DefaultSleepDuration
gologger.Warning().Msgf("Invalid sleep_duration parameter type, using default value: %d", duration)
}
}
}
data = strings.ReplaceAll(data, "[SLEEPTIME]", strconv.Itoa(duration))
data = analyzers.ApplyPayloadTransformations(data)
// Also support [INFERENCE] for the time delay analyzer
if strings.Contains(data, "[INFERENCE]") {
randInt := analyzers.GetRandomInteger()
data = strings.ReplaceAll(data, "[INFERENCE]", fmt.Sprintf("%d=%d", randInt, randInt))
}
return data
}
func (a *Analyzer) parseAnalyzerParameters(params map[string]interface{}) (int, int, float64, float64, error) {
requestsLimit := DefaultRequestsLimit
sleepDuration := DefaultSleepDuration
timeCorrelationErrorRange := DefaultTimeCorrelationErrorRange
timeSlopeErrorRange := DefaultTimeSlopeErrorRange
if len(params) == 0 {
return requestsLimit, sleepDuration, timeCorrelationErrorRange, timeSlopeErrorRange, nil
}
var ok bool
for k, v := range params {
switch k {
case "sleep_duration":
sleepDuration, ok = v.(int)
case "requests_limit":
requestsLimit, ok = v.(int)
case "time_correlation_error_range":
timeCorrelationErrorRange, ok = v.(float64)
case "time_slope_error_range":
timeSlopeErrorRange, ok = v.(float64)
}
if !ok {
return 0, 0, 0, 0, errors.Errorf("invalid parameter type for %s", k)
}
}
return requestsLimit, sleepDuration, timeCorrelationErrorRange, timeSlopeErrorRange, nil
}
// Analyze is the main function for the analyzer
func (a *Analyzer) Analyze(options *analyzers.Options) (bool, string, error) {
if options.ResponseTimeDelay < defaultSleepTimeDuration {
return false, "", nil
}
// Parse parameters for this analyzer if any or use default values
requestsLimit, sleepDuration, timeCorrelationErrorRange, timeSlopeErrorRange, err :=
a.parseAnalyzerParameters(options.AnalyzerParameters)
if err != nil {
return false, "", err
}
reqSender := func(delay int) (float64, error) {
gr := options.FuzzGenerated
replaced := strings.ReplaceAll(gr.OriginalPayload, "[SLEEPTIME]", strconv.Itoa(delay))
replaced = a.ApplyInitialTransformation(replaced, options.AnalyzerParameters)
if err := gr.Component.SetValue(gr.Key, replaced); err != nil {
return 0, errors.Wrap(err, "could not set value in component")
}
rebuilt, err := gr.Component.Rebuild()
if err != nil {
return 0, errors.Wrap(err, "could not rebuild request")
}
gologger.Verbose().Msgf("[%s] Sending request with %d delay for: %s", a.Name(), delay, rebuilt.URL.String())
timeTaken, err := doHTTPRequestWithTimeTracing(rebuilt, options.HttpClient)
if err != nil {
return 0, errors.Wrap(err, "could not do request with time tracing")
}
return timeTaken, nil
}
matched, matchReason, err := checkTimingDependency(
requestsLimit,
sleepDuration,
timeCorrelationErrorRange,
timeSlopeErrorRange,
reqSender,
)
if err != nil {
return false, "", err
}
if matched {
return true, matchReason, nil
}
return false, "", nil
}
// doHTTPRequestWithTimeTracing does a http request with time tracing
func doHTTPRequestWithTimeTracing(req *retryablehttp.Request, httpclient *retryablehttp.Client) (float64, error) {
var ttfb time.Duration
var start time.Time
trace := &httptrace.ClientTrace{
GotFirstResponseByte: func() { ttfb = time.Since(start) },
}
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
start = time.Now()
resp, err := httpclient.Do(req)
if err != nil {
return 0, errors.Wrap(err, "could not do request")
}
_, err = io.ReadAll(resp.Body)
if err != nil {
return 0, errors.Wrap(err, "could not read response body")
}
return ttfb.Seconds(), nil
}
+171
View File
@@ -0,0 +1,171 @@
// Package time implements a time delay analyzer using linear
// regression heuristics inspired from ZAP to discover time
// based issues.
//
// The approach is the one used in ZAP for timing based checks.
// Advantages of this approach are many compared to the old approach of
// heuristics of sleep time.
//
// As we are building a statistical model, we can predict if the delay
// is random or not very quickly. Also, the payloads are alternated to send
// a very high sleep and a very low sleep. This way the comparison is
// faster to eliminate negative cases. Only legitimate cases are sent for
// more verification.
//
// For more details on the algorithm, follow the links below:
// - https://groups.google.com/g/zaproxy-develop/c/KGSkNHlLtqk
// - https://github.com/zaproxy/zap-extensions/pull/5053
//
// This file has been implemented from its original version. It was originally licensed under the Apache License 2.0 (see LICENSE file for details).
// The original algorithm is implemented in ZAP Active Scanner.
package time
import (
"errors"
"fmt"
"math"
)
type timeDelayRequestSender func(delay int) (float64, error)
// checkTimingDependency checks the timing dependency for a given request
//
// It alternates and sends first a high request, then a low request. Each time
// it checks if the delay of the application can be predictably controlled.
func checkTimingDependency(
requestsLimit int,
highSleepTimeSeconds int,
correlationErrorRange float64,
slopeErrorRange float64,
requestSender timeDelayRequestSender,
) (bool, string, error) {
if requestsLimit < 2 {
return false, "", errors.New("requests limit should be at least 2")
}
regression := newSimpleLinearRegression()
requestsLeft := requestsLimit
for {
if requestsLeft <= 0 {
break
}
isCorrelationPossible, err := sendRequestAndTestConfidence(regression, highSleepTimeSeconds, requestSender)
if err != nil {
return false, "", err
}
if !isCorrelationPossible {
return false, "", nil
}
isCorrelationPossible, err = sendRequestAndTestConfidence(regression, 1, requestSender)
if err != nil {
return false, "", err
}
if !isCorrelationPossible {
return false, "", nil
}
requestsLeft = requestsLeft - 2
}
result := regression.IsWithinConfidence(correlationErrorRange, 1.0, slopeErrorRange)
if result {
resultReason := fmt.Sprintf(
"[time_delay] made %d requests successfully, with a regression slope of %.2f and correlation %.2f",
requestsLimit,
regression.slope,
regression.correlation,
)
return result, resultReason, nil
}
return result, "", nil
}
// sendRequestAndTestConfidence sends a request and tests the confidence of delay
func sendRequestAndTestConfidence(
regression *simpleLinearRegression,
delay int,
requestSender timeDelayRequestSender,
) (bool, error) {
delayReceived, err := requestSender(delay)
if err != nil {
return false, err
}
if delayReceived < float64(delay) {
return false, nil
}
regression.AddPoint(float64(delay), delayReceived)
if !regression.IsWithinConfidence(0.3, 1.0, 0.5) {
return false, nil
}
return true, nil
}
// simpleLinearRegression is a simple linear regression model that can be updated at runtime.
// It is based on the same algorithm in ZAP for doing timing checks.
type simpleLinearRegression struct {
count float64
independentSum float64
dependentSum float64
// Variances
independentVarianceN float64
dependentVarianceN float64
sampleCovarianceN float64
slope float64
intercept float64
correlation float64
}
func newSimpleLinearRegression() *simpleLinearRegression {
return &simpleLinearRegression{
slope: 1,
correlation: 1,
}
}
func (o *simpleLinearRegression) AddPoint(x, y float64) {
independentResidualAdjustment := x - o.independentSum/o.count
dependentResidualAdjustment := y - o.dependentSum/o.count
o.count += 1
o.independentSum += x
o.dependentSum += y
if math.IsNaN(independentResidualAdjustment) {
return
}
independentResidual := x - o.independentSum/o.count
dependentResidual := y - o.dependentSum/o.count
o.independentVarianceN += independentResidual * independentResidualAdjustment
o.dependentVarianceN += dependentResidual * dependentResidualAdjustment
o.sampleCovarianceN += independentResidual * dependentResidualAdjustment
o.slope = o.sampleCovarianceN / o.independentVarianceN
o.correlation = o.slope * math.Sqrt(o.independentVarianceN/o.dependentVarianceN)
o.correlation *= o.correlation
// NOTE: zap had the reverse formula, changed it to the correct one
// for intercept. Verify if this is correct.
o.intercept = o.dependentSum/o.count - o.slope*(o.independentSum/o.count)
if math.IsNaN(o.correlation) {
o.correlation = 1
}
}
func (o *simpleLinearRegression) Predict(x float64) float64 {
return o.slope*x + o.intercept
}
func (o *simpleLinearRegression) IsWithinConfidence(correlationErrorRange float64, expectedSlope float64, slopeErrorRange float64,
) bool {
return o.correlation > 1.0-correlationErrorRange
//math.Abs(expectedSlope-o.slope) < slopeErrorRange
}
+143
View File
@@ -0,0 +1,143 @@
// Tests ported from ZAP Java version of the algorithm
package time
import (
"math"
"math/rand"
"testing"
"time"
"github.com/stretchr/testify/require"
)
const (
correlationErrorRange = float64(0.1)
slopeErrorRange = float64(0.2)
)
var rng = rand.New(rand.NewSource(time.Now().UnixNano()))
func Test_should_generate_alternating_sequences(t *testing.T) {
var generatedDelays []float64
reqSender := func(delay int) (float64, error) {
generatedDelays = append(generatedDelays, float64(delay))
return float64(delay), nil
}
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
require.NoError(t, err)
require.True(t, matched)
require.EqualValues(t, []float64{15, 1, 15, 1}, generatedDelays)
}
func Test_should_giveup_non_injectable(t *testing.T) {
var timesCalled int
reqSender := func(delay int) (float64, error) {
timesCalled++
return 0.5, nil
}
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
require.NoError(t, err)
require.False(t, matched)
require.Equal(t, 1, timesCalled)
}
func Test_should_giveup_slow_non_injectable(t *testing.T) {
var timesCalled int
reqSender := func(delay int) (float64, error) {
timesCalled++
return 10 + rng.Float64()*0.5, nil
}
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
require.NoError(t, err)
require.False(t, matched)
require.LessOrEqual(t, timesCalled, 3)
}
func Test_should_giveup_slow_non_injectable_realworld(t *testing.T) {
var timesCalled int
var iteration = 0
counts := []float64{21, 11, 21, 11}
reqSender := func(delay int) (float64, error) {
timesCalled++
iteration++
return counts[iteration-1], nil
}
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
require.NoError(t, err)
require.False(t, matched)
require.LessOrEqual(t, timesCalled, 4)
}
func Test_should_detect_dependence_with_small_error(t *testing.T) {
reqSender := func(delay int) (float64, error) {
return float64(delay) + rng.Float64()*0.5, nil
}
matched, reason, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
require.NoError(t, err)
require.True(t, matched)
require.NotEmpty(t, reason)
}
func Test_LinearRegression_Numerical_stability(t *testing.T) {
variables := [][]float64{
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {1, 1}, {2, 2}, {2, 2}, {2, 2},
}
slope := float64(1)
correlation := float64(1)
regression := newSimpleLinearRegression()
for _, v := range variables {
regression.AddPoint(v[0], v[1])
}
require.True(t, almostEqual(regression.slope, slope))
require.True(t, almostEqual(regression.correlation, correlation))
}
func Test_LinearRegression_exact_verify(t *testing.T) {
variables := [][]float64{
{1, 1}, {2, 3},
}
slope := float64(2)
correlation := float64(1)
regression := newSimpleLinearRegression()
for _, v := range variables {
regression.AddPoint(v[0], v[1])
}
require.True(t, almostEqual(regression.slope, slope))
require.True(t, almostEqual(regression.correlation, correlation))
}
func Test_LinearRegression_known_verify(t *testing.T) {
variables := [][]float64{
{1, 1.348520581}, {2, 2.524046187}, {3, 3.276944688}, {4, 4.735374498}, {5, 5.150291657},
}
slope := float64(0.981487046)
correlation := float64(0.979228906)
regression := newSimpleLinearRegression()
for _, v := range variables {
regression.AddPoint(v[0], v[1])
}
require.True(t, almostEqual(regression.slope, slope))
require.True(t, almostEqual(regression.correlation, correlation))
}
func Test_LinearRegression_nonlinear_verify(t *testing.T) {
variables := [][]float64{
{1, 2}, {2, 4}, {3, 8}, {4, 16}, {5, 32},
}
regression := newSimpleLinearRegression()
for _, v := range variables {
regression.AddPoint(v[0], v[1])
}
require.Less(t, regression.correlation, 0.9)
}
const float64EqualityThreshold = 1e-8
func almostEqual(a, b float64) bool {
return math.Abs(a-b) <= float64EqualityThreshold
}
+1 -1
View File
@@ -7,7 +7,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
"github.com/projectdiscovery/retryablehttp-go"
"github.com/projectdiscovery/utils/maps"
mapsutil "github.com/projectdiscovery/utils/maps"
urlutil "github.com/projectdiscovery/utils/url"
)
+18 -2
View File
@@ -50,6 +50,11 @@ type ExecuteRuleInput struct {
BaseRequest *retryablehttp.Request
// DisplayFuzzPoints is a flag to display fuzz points
DisplayFuzzPoints bool
// ApplyPayloadInitialTransformation is an optional function
// to transform the payload initially based on analyzer rules
ApplyPayloadInitialTransformation func(string, map[string]interface{}) string
AnalyzerParams map[string]interface{}
}
// GeneratedRequest is a single generated request for rule
@@ -64,6 +69,15 @@ type GeneratedRequest struct {
Component component.Component
// Parameter being fuzzed
Parameter string
// Key is the key for the request
Key string
// Value is the value for the request
Value string
// OriginalValue is the original value for the request
OriginalValue string
// OriginalPayload is the original payload for the request
OriginalPayload string
}
// Execute executes a fuzzing rule accepting a callback on which
@@ -216,7 +230,9 @@ func (rule *Rule) executeRuleValues(input *ExecuteRuleInput, ruleComponent compo
// if we are only fuzzing values
if len(rule.Fuzz.Value) > 0 {
for _, value := range rule.Fuzz.Value {
if err := rule.executePartRule(input, ValueOrKeyValue{Value: value}, ruleComponent); err != nil {
originalPayload := value
if err := rule.executePartRule(input, ValueOrKeyValue{Value: value, OriginalPayload: originalPayload}, ruleComponent); err != nil {
if component.IsErrSetValue(err) {
// this are errors due to format restrictions
// ex: fuzzing string value in a json int field
@@ -257,7 +273,7 @@ func (rule *Rule) executeRuleValues(input *ExecuteRuleInput, ruleComponent compo
if err != nil {
return err
}
if gotErr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", ""); gotErr != nil {
if gotErr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", "", "", "", "", ""); gotErr != nil {
return gotErr
}
}
+23 -13
View File
@@ -42,14 +42,14 @@ func (rule *Rule) executePartComponent(input *ExecuteRuleInput, payload ValueOrK
return rule.executePartComponentOnKV(input, payload, ruleComponent.Clone())
} else {
// for value only fuzzing
return rule.executePartComponentOnValues(input, payload.Value, ruleComponent.Clone())
return rule.executePartComponentOnValues(input, payload.Value, payload.OriginalPayload, ruleComponent.Clone())
}
}
// executePartComponentOnValues executes this rule on a given component and payload
// this supports both single and multiple [ruleType] modes
// i.e if component has multiple values, they can be replaced once or all depending on mode
func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadStr string, ruleComponent component.Component) error {
func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadStr, originalPayload string, ruleComponent component.Component) error {
finalErr := ruleComponent.Iterate(func(key string, value interface{}) error {
valueStr := types.ToString(value)
if !rule.matchKeyOrValue(key, valueStr) {
@@ -57,8 +57,13 @@ func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadS
return nil
}
var evaluated string
var evaluated, originalEvaluated string
evaluated, input.InteractURLs = rule.executeEvaluate(input, key, valueStr, payloadStr, input.InteractURLs)
if input.ApplyPayloadInitialTransformation != nil {
evaluated = input.ApplyPayloadInitialTransformation(evaluated, input.AnalyzerParams)
originalEvaluated, _ = rule.executeEvaluate(input, key, valueStr, originalPayload, input.InteractURLs)
}
if err := ruleComponent.SetValue(key, evaluated); err != nil {
// gologger.Warning().Msgf("could not set value due to format restriction original(%s, %s[%T]) , new(%s,%s[%T])", key, valueStr, value, key, evaluated, evaluated)
return nil
@@ -70,7 +75,7 @@ func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadS
return err
}
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, valueStr); qerr != nil {
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, valueStr, originalEvaluated, valueStr, key, evaluated); qerr != nil {
return qerr
}
// fmt.Printf("executed with value: %s\n", evaluated)
@@ -92,7 +97,7 @@ func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadS
if err != nil {
return err
}
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", ""); qerr != nil {
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", "", "", "", "", ""); qerr != nil {
err = qerr
return err
}
@@ -127,7 +132,7 @@ func (rule *Rule) executePartComponentOnKV(input *ExecuteRuleInput, payload Valu
return err
}
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, value); qerr != nil {
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, value, "", "", "", ""); qerr != nil {
return err
}
@@ -146,12 +151,13 @@ func (rule *Rule) executePartComponentOnKV(input *ExecuteRuleInput, payload Valu
}
// execWithInput executes a rule with input via callback
func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.Request, interactURLs []string, component component.Component, parameter, parameterValue string) error {
func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.Request, interactURLs []string, component component.Component, parameter, parameterValue, originalPayload, originalValue, key, value string) error {
// If the parameter is a number, replace it with the parameter value
// or if the parameter is empty and the parameter value is not empty
// replace it with the parameter value
actualParameter := parameter
if _, err := strconv.Atoi(parameter); err == nil || (parameter == "" && parameterValue != "") {
parameter = parameterValue
actualParameter = parameterValue
}
// If the parameter is frequent, skip it if the option is enabled
if rule.options.FuzzParamsFrequency != nil {
@@ -164,11 +170,15 @@ func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.
}
}
request := GeneratedRequest{
Request: httpReq,
InteractURLs: interactURLs,
DynamicValues: input.Values,
Component: component,
Parameter: parameter,
Request: httpReq,
InteractURLs: interactURLs,
DynamicValues: input.Values,
Component: component,
Parameter: actualParameter,
Key: key,
Value: value,
OriginalValue: originalValue,
OriginalPayload: originalPayload,
}
if !input.Callback(request) {
return types.ErrNoMoreRequests
+2
View File
@@ -19,6 +19,8 @@ var (
type ValueOrKeyValue struct {
Key string
Value string
OriginalPayload string
}
func (v *ValueOrKeyValue) IsKV() bool {
+1
View File
@@ -201,6 +201,7 @@ type ResultEvent struct {
FuzzingMethod string `json:"fuzzing_method,omitempty"`
FuzzingParameter string `json:"fuzzing_parameter,omitempty"`
FuzzingPosition string `json:"fuzzing_position,omitempty"`
AnalyzerDetails string `json:"analyzer_details,omitempty"`
FileToIndexPosition map[string]int `json:"-"`
TemplateVerifier string `json:"-"`
@@ -142,6 +142,9 @@ func (metaInput *MetaInput) Unmarshal(data string) error {
}
func (metaInput *MetaInput) Clone() *MetaInput {
metaInput.mu.Lock()
defer metaInput.mu.Unlock()
input := NewMetaInput()
input.Input = metaInput.Input
input.CustomIP = metaInput.CustomIP
@@ -9,6 +9,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/network/networkclientpool"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/whois/rdapclientpool"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
_ "github.com/projectdiscovery/utils/global"
)
// Init initializes the client pools for the protocols
@@ -19,7 +19,7 @@ var (
)
func StartActiveMemGuardian(ctx context.Context) {
if memguardian.DefaultMemGuardian == nil {
if memguardian.DefaultMemGuardian == nil || memTimer != nil {
return
}
+3
View File
@@ -14,6 +14,7 @@ import (
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
@@ -55,6 +56,8 @@ type generatedRequest struct {
// requestURLPattern tracks unmodified request url pattern without values ( it is used for constant vuln_hash)
// ex: {{BaseURL}}/api/exp?param={{randstr}}
requestURLPattern string
fuzzGeneratedRequest fuzz.GeneratedRequest
}
// setReqURLPattern sets the url request pattern for the generated request
+29
View File
@@ -3,13 +3,18 @@ package http
import (
"bytes"
"fmt"
"math"
"strings"
"time"
"github.com/invopop/jsonschema"
json "github.com/json-iterator/go"
"github.com/pkg/errors"
_ "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers/time"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers"
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
@@ -126,6 +131,9 @@ type Request struct {
// Fuzzing describes schema to fuzz http requests
Fuzzing []*fuzz.Rule `yaml:"fuzzing,omitempty" json:"fuzzing,omitempty" jsonschema:"title=fuzzin rules for http fuzzing,description=Fuzzing describes rule schema to fuzz http requests"`
// description: |
// Analyzer is an analyzer to use for matching the response.
Analyzer *analyzers.AnalyzerTemplate `yaml:"analyzer,omitempty" json:"analyzer,omitempty" jsonschema:"title=analyzer for http request,description=Analyzer for HTTP Request"`
CompiledOperators *operators.Operators `yaml:"-" json:"-"`
@@ -303,6 +311,21 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
},
RedirectFlow: httpclientpool.DontFollowRedirect,
}
var customTimeout int
if request.Analyzer != nil && request.Analyzer.Name == "time_delay" {
var timeoutVal int
if timeout, ok := request.Analyzer.Parameters["sleep_duration"]; ok {
timeoutVal, _ = timeout.(int)
} else {
timeoutVal = 5
}
// Add 3x buffer to the timeout
customTimeout = int(math.Ceil(float64(timeoutVal) * 3))
}
if customTimeout > 0 {
connectionConfiguration.Connection.CustomMaxTimeout = time.Duration(customTimeout) * time.Second
}
if request.Redirects || options.Options.FollowRedirects {
connectionConfiguration.RedirectFlow = httpclientpool.FollowAllRedirect
@@ -369,6 +392,12 @@ func (request *Request) Compile(options *protocols.ExecutorOptions) error {
}
}
if request.Analyzer != nil {
if analyzer := analyzers.GetAnalyzer(request.Analyzer.Name); analyzer == nil {
return errors.Errorf("analyzer %s not found", request.Analyzer.Name)
}
}
// Resolve payload paths from vars if they exists
for name, payload := range request.options.Options.Vars.AsMap() {
payloadStr, ok := payload.(string)
@@ -60,6 +60,9 @@ func Init(options *types.Options) error {
type ConnectionConfiguration struct {
// DisableKeepAlive of the connection
DisableKeepAlive bool
// CustomMaxTimeout is the custom timeout for the connection
// This overrides all other timeouts and is used for accurate time based fuzzing.
CustomMaxTimeout time.Duration
cookiejar *cookiejar.Jar
mu sync.RWMutex
}
@@ -108,6 +111,7 @@ func (c *Configuration) Clone() *Configuration {
if c.Connection != nil {
cloneConnection := &ConnectionConfiguration{
DisableKeepAlive: c.Connection.DisableKeepAlive,
CustomMaxTimeout: c.Connection.CustomMaxTimeout,
}
if c.Connection.HasCookieJar() {
cookiejar := *c.Connection.GetCookieJar()
@@ -135,6 +139,10 @@ func (c *Configuration) Hash() string {
builder.WriteString(strconv.FormatBool(c.DisableCookie))
builder.WriteString("c")
builder.WriteString(strconv.FormatBool(c.Connection != nil))
if c.Connection != nil && c.Connection.CustomMaxTimeout > 0 {
builder.WriteString("k")
builder.WriteString(c.Connection.CustomMaxTimeout.String())
}
builder.WriteString("r")
builder.WriteString(strconv.FormatInt(int64(c.ResponseHeaderTimeout.Seconds()), 10))
hash := builder.String()
@@ -247,6 +255,9 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
if configuration.ResponseHeaderTimeout != 0 {
responseHeaderTimeout = configuration.ResponseHeaderTimeout
}
if configuration.Connection != nil && configuration.Connection.CustomMaxTimeout > 0 {
responseHeaderTimeout = configuration.Connection.CustomMaxTimeout
}
transport := &http.Transport{
ForceAttemptHTTP2: options.ForceAttemptHTTP2,
@@ -313,6 +324,9 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl
}
if !configuration.NoTimeout {
httpclient.Timeout = options.GetTimeouts().HttpTimeout
if configuration.Connection != nil && configuration.Connection.CustomMaxTimeout > 0 {
httpclient.Timeout = configuration.Connection.CustomMaxTimeout
}
}
client := retryablehttp.NewWithHTTPClient(httpclient, retryableHttpOptions)
if jar != nil {
+5
View File
@@ -170,6 +170,10 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
if value, ok := wrapped.InternalEvent["global-matchers"]; ok {
isGlobalMatchers = value.(bool)
}
var analyzerDetails string
if value, ok := wrapped.InternalEvent["analyzer_details"]; ok {
analyzerDetails = value.(string)
}
data := &output.ResultEvent{
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
@@ -193,6 +197,7 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
CURLCommand: types.ToString(wrapped.InternalEvent["curl-command"]),
TemplateEncoded: request.options.EncodeTemplate(),
Error: types.ToString(wrapped.InternalEvent["error"]),
AnalyzerDetails: analyzerDetails,
}
return data
}
+19
View File
@@ -19,6 +19,7 @@ import (
"github.com/projectdiscovery/fastdialer/fastdialer"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers"
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
@@ -927,8 +928,26 @@ func (request *Request) executeRequest(input *contextargs.Context, generatedRequ
matchedURL = responseURL
}
}
finalEvent := make(output.InternalEvent)
if request.Analyzer != nil {
analyzer := analyzers.GetAnalyzer(request.Analyzer.Name)
analysisMatched, analysisDetails, err := analyzer.Analyze(&analyzers.Options{
FuzzGenerated: generatedRequest.fuzzGeneratedRequest,
HttpClient: request.httpClient,
ResponseTimeDelay: duration,
AnalyzerParameters: request.Analyzer.Parameters,
})
if err != nil {
gologger.Warning().Msgf("Could not analyze response: %v\n", err)
}
if analysisMatched {
finalEvent["analyzer_details"] = analysisDetails
finalEvent["analyzer"] = true
}
}
outputEvent := request.responseToDSLMap(respChain.Response(), input.MetaInput.Input, matchedURL, convUtil.String(dumpedRequest), respChain.FullResponse().String(), respChain.Body().String(), respChain.Headers().String(), duration, generatedRequest.meta)
// add response fields to template context and merge templatectx variables to output event
request.options.AddTemplateVars(input.MetaInput, request.Type(), request.ID, outputEvent)
+16 -7
View File
@@ -6,6 +6,7 @@ package http
// -> request.executeGeneratedFuzzingRequest [execute final generated fuzzing request and get result]
import (
"context"
"fmt"
"net/http"
"strings"
@@ -13,6 +14,7 @@ import (
"github.com/pkg/errors"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers"
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/matchers"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
@@ -121,7 +123,7 @@ func (request *Request) executeAllFuzzingRules(input *contextargs.Context, value
default:
}
err := rule.Execute(&fuzz.ExecuteRuleInput{
input := &fuzz.ExecuteRuleInput{
Input: input,
DisplayFuzzPoints: request.options.Options.DisplayFuzzPoints,
Callback: func(gr fuzz.GeneratedRequest) bool {
@@ -135,8 +137,14 @@ func (request *Request) executeAllFuzzingRules(input *contextargs.Context, value
return request.executeGeneratedFuzzingRequest(gr, input, callback)
},
Values: values,
BaseRequest: baseRequest.Clone(input.Context()),
})
BaseRequest: baseRequest.Clone(context.TODO()),
}
if request.Analyzer != nil {
analyzer := analyzers.GetAnalyzer(request.Analyzer.Name)
input.ApplyPayloadInitialTransformation = analyzer.ApplyInitialTransformation
input.AnalyzerParams = request.Analyzer.Parameters
}
err := rule.Execute(input)
if err == nil {
applicable = true
continue
@@ -166,10 +174,11 @@ func (request *Request) executeGeneratedFuzzingRequest(gr fuzz.GeneratedRequest,
}
request.options.RateLimitTake()
req := &generatedRequest{
request: gr.Request,
dynamicValues: gr.DynamicValues,
interactshURLs: gr.InteractURLs,
original: request,
request: gr.Request,
dynamicValues: gr.DynamicValues,
interactshURLs: gr.InteractURLs,
original: request,
fuzzGeneratedRequest: gr,
}
var gotMatches bool
requestErr := request.executeRequest(input, req, gr.DynamicValues, hasInteractMatchers, func(event *output.InternalWrappedEvent) {
+58 -22
View File
@@ -10,16 +10,21 @@ import (
)
type Exporter struct {
options *Options
mutex *sync.Mutex
rows []output.ResultEvent
options *Options
mutex *sync.Mutex
rows []output.ResultEvent
outputFile *os.File
}
// Options contains the configuration options for JSONL exporter client
type Options struct {
// File is the file to export found JSONL result to
File string `yaml:"file"`
OmitRaw bool `yaml:"omit-raw"`
File string `yaml:"file"`
// OmitRaw whether to exclude the raw request and response from the output
OmitRaw bool `yaml:"omit-raw"`
// BatchSize the number of records to keep in memory before writing them out to the JSONL file or 0 to disable
// batching (default)
BatchSize int `yaml:"batch-size"`
}
// New creates a new JSONL exporter integration client based on options.
@@ -32,8 +37,7 @@ func New(options *Options) (*Exporter, error) {
return exporter, nil
}
// Export appends the passed result event to the list of objects to be exported to
// the resulting JSONL file
// Export appends the passed result event to the list of objects to be exported to the resulting JSONL file
func (exporter *Exporter) Export(event *output.ResultEvent) error {
exporter.mutex.Lock()
defer exporter.mutex.Unlock()
@@ -46,40 +50,72 @@ func (exporter *Exporter) Export(event *output.ResultEvent) error {
// Add the event to the rows
exporter.rows = append(exporter.rows, *event)
// If the batch size is greater than 0 and the number of rows has reached the batch, flush it to the database
if exporter.options.BatchSize > 0 && len(exporter.rows) >= exporter.options.BatchSize {
err := exporter.WriteRows()
if err != nil {
// The error is already logged, return it to bubble up to the caller
return err
}
}
return nil
}
// Close writes the in-memory data to the JSONL file specified by options.JSONLExport
// and closes the exporter after operation
func (exporter *Exporter) Close() error {
exporter.mutex.Lock()
defer exporter.mutex.Unlock()
// Open the JSONL file for writing and create it if it doesn't exist
f, err := os.OpenFile(exporter.options.File, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return errors.Wrap(err, "failed to create JSONL file")
// WriteRows writes all rows from the rows list to JSONL file and removes them from the list
func (exporter *Exporter) WriteRows() error {
// Open the file for writing if it's not already.
// This will recreate the file if it exists, but keep the file handle so that batched writes within the same
// execution are appended to the same file.
var err error
if exporter.outputFile == nil {
// Open the JSONL file for writing and create it if it doesn't exist
exporter.outputFile, err = os.OpenFile(exporter.options.File, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return errors.Wrap(err, "failed to create JSONL file")
}
}
// Loop through the rows and convert each to a JSON byte array and write to file
for _, row := range exporter.rows {
// Loop through the rows and write them, removing them as they're entered
for len(exporter.rows) > 0 {
row := exporter.rows[0]
// Convert the row to JSON byte array and append a trailing newline. This is treated as a single line in JSONL
obj, err := json.Marshal(row)
if err != nil {
return errors.Wrap(err, "failed to generate row for JSONL report")
}
// Add a trailing newline to the JSON byte array to confirm with the JSONL format
obj = append(obj, '\n')
// Attempt to append the JSON line to file specified in options.JSONLExport
if _, err = f.Write(obj); err != nil {
if _, err = exporter.outputFile.Write(obj); err != nil {
return errors.Wrap(err, "failed to append JSONL line")
}
// Remove the item from the list
exporter.rows = exporter.rows[1:]
}
return nil
}
// Close writes the in-memory data to the JSONL file specified by options.JSONLExport and closes the exporter after
// operation
func (exporter *Exporter) Close() error {
exporter.mutex.Lock()
defer exporter.mutex.Unlock()
// Write any remaining rows to the file
// Write all pending rows
err := exporter.WriteRows()
if err != nil {
// The error is already logged, return it to bubble up to the caller
return err
}
// Close the file
if err := f.Close(); err != nil {
if err := exporter.outputFile.Close(); err != nil {
return errors.Wrap(err, "failed to close JSONL file")
}
+8 -1
View File
@@ -83,7 +83,7 @@ func CreateReportDescription(event *output.ResultEvent, formatter ResultFormatte
}
}
if len(event.ExtractedResults) > 0 || len(event.Metadata) > 0 {
if len(event.ExtractedResults) > 0 || len(event.Metadata) > 0 || event.AnalyzerDetails != "" {
builder.WriteString("\n")
builder.WriteString(formatter.MakeBold("Extra Information"))
builder.WriteString("\n\n")
@@ -99,6 +99,13 @@ func CreateReportDescription(event *output.ResultEvent, formatter ResultFormatte
}
builder.WriteString("\n")
}
if event.AnalyzerDetails != "" {
builder.WriteString(formatter.MakeBold("Analyzer Details:"))
builder.WriteString("\n\n")
builder.WriteString(event.AnalyzerDetails)
builder.WriteString("\n")
}
if len(event.Metadata) > 0 {
builder.WriteString(formatter.MakeBold("Metadata:"))
builder.WriteString("\n\n")
+1 -1
View File
@@ -197,7 +197,7 @@ func New(options *Options, db string, doNotDedupe bool) (Client, error) {
return client, nil
}
// CreateConfigIfNotExists creates report-config if it doesn't exists
// CreateConfigIfNotExists creates report-config if it doesn't exist
func CreateConfigIfNotExists() error {
reportingConfig := config.DefaultConfig.GetReportingConfigFilePath()
+9 -1
View File
@@ -112,7 +112,8 @@ func Parse(filePath string, preprocessor Preprocessor, options protocols.Executo
// isGlobalMatchersEnabled checks if any of requests in the template
// have global matchers enabled. It iterates through all requests and
// returns true if at least one request has global matchers enabled;
// otherwise, it returns false.
// otherwise, it returns false. If global matchers templates are not
// enabled in the options, the method will immediately return false.
//
// Note: This method only checks the `RequestsHTTP`
// field of the template, which is specific to http-protocol-based
@@ -120,6 +121,10 @@ func Parse(filePath string, preprocessor Preprocessor, options protocols.Executo
//
// TODO: support all protocols.
func (template *Template) isGlobalMatchersEnabled() bool {
if !template.Options.Options.EnableGlobalMatchersTemplates {
return false
}
for _, request := range template.RequestsHTTP {
if request.GlobalMatchers {
return true
@@ -446,6 +451,9 @@ func parseTemplate(data []byte, options protocols.ExecutorOptions) (*Template, e
var verifier *signer.TemplateSigner
for _, verifier = range signer.DefaultTemplateVerifiers {
template.Verified, _ = verifier.Verify(data, template)
if config.DefaultConfig.LogAllEvents {
gologger.Verbose().Msgf("template %v verified by %s : %v", template.ID, verifier.Identifier(), template.Verified)
}
if template.Verified {
template.TemplateVerifier = verifier.Identifier()
break
+2 -2
View File
@@ -10,7 +10,7 @@ const (
ExcludedCodeTmplStats = "code-flag-missing-warnings"
ExludedDastTmplStats = "fuzz-flag-missing-warnings"
SkippedUnsignedStats = "skipped-unsigned-stats" // tracks loading of unsigned templates
ExcludedSelfContainedStats = "excluded-self-contained-stats"
ExcludedFileStats = "excluded-file-stats"
SkippedRequestSignatureStats = "skipped-request-signature-stats"
SkippedSelfContainedStats = "skipped-self-contained-stats"
SkippedFileStats = "skipped-file-stats"
)
+7 -2
View File
@@ -30,11 +30,12 @@ func ExtractSignatureAndContent(data []byte) (signature, content []byte) {
dataStr := string(data)
if idx := strings.LastIndex(dataStr, SignaturePattern); idx != -1 {
signature = []byte(strings.TrimSpace(dataStr[idx:]))
content = []byte(strings.TrimSpace(dataStr[:idx]))
content = bytes.TrimSpace(data[:idx])
} else {
content = data
}
return
content = bytes.TrimSpace(content)
return signature, content
}
// SignableTemplate is a template that can be signed
@@ -145,6 +146,10 @@ func (t *TemplateSigner) Verify(data []byte, tmpl SignableTemplate) (bool, error
return false, err
}
// normalize content by removing \r\n everywhere since this only done for verification
// it does not affect the actual template
content = bytes.ReplaceAll(content, []byte("\r\n"), []byte("\n"))
buff := bytes.NewBuffer(content)
// if file has any imports process them
for _, file := range tmpl.GetFileImports() {
+2 -2
View File
@@ -9,10 +9,10 @@ func init() {
stats.NewEntry(SkippedCodeTmplTamperedStats, "Found %d unsigned or tampered code template (carefully examine before using it & use -sign flag to sign them)")
stats.NewEntry(ExcludedHeadlessTmplStats, "Excluded %d headless template[s] (disabled as default), use -headless option to run headless templates.")
stats.NewEntry(ExcludedCodeTmplStats, "Excluded %d code template[s] (disabled as default), use -code option to run code templates.")
stats.NewEntry(ExcludedSelfContainedStats, "Excluded %d self-contained template[s] (disabled as default), use -esc option to run self-contained templates.")
stats.NewEntry(ExcludedFileStats, "Excluded %d file template[s] (disabled as default), use -file option to run file templates.")
stats.NewEntry(TemplatesExcludedStats, "Excluded %d template[s] with known weak matchers / tags excluded from default run using .nuclei-ignore")
stats.NewEntry(ExludedDastTmplStats, "Excluded %d dast template[s] (disabled as default), use -dast option to run dast templates.")
stats.NewEntry(SkippedUnsignedStats, "Skipping %d unsigned template[s]")
stats.NewEntry(SkippedRequestSignatureStats, "Skipping %d templates, HTTP Request signatures can only be used in Signed & Verified templates.")
stats.NewEntry(SkippedSelfContainedStats, "Skipping %d self-contained template[s], use -var or -env-vars flag to run them")
stats.NewEntry(SkippedFileStats, "Skipping %d file template[s], use file or directory as an input to run file templates")
}
+5 -5
View File
@@ -227,11 +227,6 @@ func (template *Template) HasCodeProtocol() bool {
return len(template.RequestsCode) > 0
}
// HasFileProtocol returns true if the template has a file protocol section
func (template *Template) HasFileProtocol() bool {
return len(template.RequestsFile) > 0
}
// validateAllRequestIDs check if that protocol already has given id if not
// then is is manually set to proto_index
func (template *Template) validateAllRequestIDs() {
@@ -560,3 +555,8 @@ func (template *Template) UnmarshalJSON(data []byte) error {
}
return nil
}
// HasFileProtocol returns true if the template has a file protocol section
func (template *Template) HasFileProtocol() bool {
return len(template.RequestsFile) > 0
}
+105 -74
View File
@@ -20,6 +20,7 @@ var (
HTTPMethodTypeHolderDoc encoder.Doc
FUZZRuleDoc encoder.Doc
SliceOrMapSliceDoc encoder.Doc
ANALYZERSAnalyzerTemplateDoc encoder.Doc
SignatureTypeHolderDoc encoder.Doc
MATCHERSMatcherDoc encoder.Doc
MatcherTypeHolderDoc encoder.Doc
@@ -459,7 +460,7 @@ func init() {
Value: "HTTP response headers in name:value format",
},
}
HTTPRequestDoc.Fields = make([]encoder.Doc, 37)
HTTPRequestDoc.Fields = make([]encoder.Doc, 38)
HTTPRequestDoc.Fields[0].Name = "path"
HTTPRequestDoc.Fields[0].Type = "[]string"
HTTPRequestDoc.Fields[0].Note = ""
@@ -565,114 +566,119 @@ func init() {
HTTPRequestDoc.Fields[15].Note = ""
HTTPRequestDoc.Fields[15].Description = "Fuzzing describes schema to fuzz http requests"
HTTPRequestDoc.Fields[15].Comments[encoder.LineComment] = " Fuzzing describes schema to fuzz http requests"
HTTPRequestDoc.Fields[16].Name = "self-contained"
HTTPRequestDoc.Fields[16].Type = "bool"
HTTPRequestDoc.Fields[16].Name = "analyzer"
HTTPRequestDoc.Fields[16].Type = "analyzers.AnalyzerTemplate"
HTTPRequestDoc.Fields[16].Note = ""
HTTPRequestDoc.Fields[16].Description = "SelfContained specifies if the request is self-contained."
HTTPRequestDoc.Fields[16].Comments[encoder.LineComment] = "SelfContained specifies if the request is self-contained."
HTTPRequestDoc.Fields[17].Name = "signature"
HTTPRequestDoc.Fields[17].Type = "SignatureTypeHolder"
HTTPRequestDoc.Fields[16].Description = "Analyzer is an analyzer to use for matching the response."
HTTPRequestDoc.Fields[16].Comments[encoder.LineComment] = "Analyzer is an analyzer to use for matching the response."
HTTPRequestDoc.Fields[17].Name = "self-contained"
HTTPRequestDoc.Fields[17].Type = "bool"
HTTPRequestDoc.Fields[17].Note = ""
HTTPRequestDoc.Fields[17].Description = "Signature is the request signature method"
HTTPRequestDoc.Fields[17].Comments[encoder.LineComment] = "Signature is the request signature method"
HTTPRequestDoc.Fields[17].Values = []string{
HTTPRequestDoc.Fields[17].Description = "SelfContained specifies if the request is self-contained."
HTTPRequestDoc.Fields[17].Comments[encoder.LineComment] = "SelfContained specifies if the request is self-contained."
HTTPRequestDoc.Fields[18].Name = "signature"
HTTPRequestDoc.Fields[18].Type = "SignatureTypeHolder"
HTTPRequestDoc.Fields[18].Note = ""
HTTPRequestDoc.Fields[18].Description = "Signature is the request signature method"
HTTPRequestDoc.Fields[18].Comments[encoder.LineComment] = "Signature is the request signature method"
HTTPRequestDoc.Fields[18].Values = []string{
"AWS",
}
HTTPRequestDoc.Fields[18].Name = "skip-secret-file"
HTTPRequestDoc.Fields[18].Type = "bool"
HTTPRequestDoc.Fields[18].Note = ""
HTTPRequestDoc.Fields[18].Description = "SkipSecretFile skips the authentication or authorization configured in the secret file."
HTTPRequestDoc.Fields[18].Comments[encoder.LineComment] = "SkipSecretFile skips the authentication or authorization configured in the secret file."
HTTPRequestDoc.Fields[19].Name = "cookie-reuse"
HTTPRequestDoc.Fields[19].Name = "skip-secret-file"
HTTPRequestDoc.Fields[19].Type = "bool"
HTTPRequestDoc.Fields[19].Note = ""
HTTPRequestDoc.Fields[19].Description = "CookieReuse is an optional setting that enables cookie reuse for\nall requests defined in raw section."
HTTPRequestDoc.Fields[19].Comments[encoder.LineComment] = "CookieReuse is an optional setting that enables cookie reuse for"
HTTPRequestDoc.Fields[20].Name = "disable-cookie"
HTTPRequestDoc.Fields[19].Description = "SkipSecretFile skips the authentication or authorization configured in the secret file."
HTTPRequestDoc.Fields[19].Comments[encoder.LineComment] = "SkipSecretFile skips the authentication or authorization configured in the secret file."
HTTPRequestDoc.Fields[20].Name = "cookie-reuse"
HTTPRequestDoc.Fields[20].Type = "bool"
HTTPRequestDoc.Fields[20].Note = ""
HTTPRequestDoc.Fields[20].Description = "DisableCookie is an optional setting that disables cookie reuse"
HTTPRequestDoc.Fields[20].Comments[encoder.LineComment] = "DisableCookie is an optional setting that disables cookie reuse"
HTTPRequestDoc.Fields[21].Name = "read-all"
HTTPRequestDoc.Fields[20].Description = "CookieReuse is an optional setting that enables cookie reuse for\nall requests defined in raw section."
HTTPRequestDoc.Fields[20].Comments[encoder.LineComment] = "CookieReuse is an optional setting that enables cookie reuse for"
HTTPRequestDoc.Fields[21].Name = "disable-cookie"
HTTPRequestDoc.Fields[21].Type = "bool"
HTTPRequestDoc.Fields[21].Note = ""
HTTPRequestDoc.Fields[21].Description = "Enables force reading of the entire raw unsafe request body ignoring\nany specified content length headers."
HTTPRequestDoc.Fields[21].Comments[encoder.LineComment] = "Enables force reading of the entire raw unsafe request body ignoring"
HTTPRequestDoc.Fields[22].Name = "redirects"
HTTPRequestDoc.Fields[21].Description = "DisableCookie is an optional setting that disables cookie reuse"
HTTPRequestDoc.Fields[21].Comments[encoder.LineComment] = "DisableCookie is an optional setting that disables cookie reuse"
HTTPRequestDoc.Fields[22].Name = "read-all"
HTTPRequestDoc.Fields[22].Type = "bool"
HTTPRequestDoc.Fields[22].Note = ""
HTTPRequestDoc.Fields[22].Description = "Redirects specifies whether redirects should be followed by the HTTP Client.\n\nThis can be used in conjunction with `max-redirects` to control the HTTP request redirects."
HTTPRequestDoc.Fields[22].Comments[encoder.LineComment] = "Redirects specifies whether redirects should be followed by the HTTP Client."
HTTPRequestDoc.Fields[23].Name = "host-redirects"
HTTPRequestDoc.Fields[22].Description = "Enables force reading of the entire raw unsafe request body ignoring\nany specified content length headers."
HTTPRequestDoc.Fields[22].Comments[encoder.LineComment] = "Enables force reading of the entire raw unsafe request body ignoring"
HTTPRequestDoc.Fields[23].Name = "redirects"
HTTPRequestDoc.Fields[23].Type = "bool"
HTTPRequestDoc.Fields[23].Note = ""
HTTPRequestDoc.Fields[23].Description = "Redirects specifies whether only redirects to the same host should be followed by the HTTP Client.\n\nThis can be used in conjunction with `max-redirects` to control the HTTP request redirects."
HTTPRequestDoc.Fields[23].Comments[encoder.LineComment] = "Redirects specifies whether only redirects to the same host should be followed by the HTTP Client."
HTTPRequestDoc.Fields[24].Name = "pipeline"
HTTPRequestDoc.Fields[23].Description = "Redirects specifies whether redirects should be followed by the HTTP Client.\n\nThis can be used in conjunction with `max-redirects` to control the HTTP request redirects."
HTTPRequestDoc.Fields[23].Comments[encoder.LineComment] = "Redirects specifies whether redirects should be followed by the HTTP Client."
HTTPRequestDoc.Fields[24].Name = "host-redirects"
HTTPRequestDoc.Fields[24].Type = "bool"
HTTPRequestDoc.Fields[24].Note = ""
HTTPRequestDoc.Fields[24].Description = "Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining\n\nAll requests must be idempotent (GET/POST). This can be used for race conditions/billions requests."
HTTPRequestDoc.Fields[24].Comments[encoder.LineComment] = "Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining"
HTTPRequestDoc.Fields[25].Name = "unsafe"
HTTPRequestDoc.Fields[24].Description = "Redirects specifies whether only redirects to the same host should be followed by the HTTP Client.\n\nThis can be used in conjunction with `max-redirects` to control the HTTP request redirects."
HTTPRequestDoc.Fields[24].Comments[encoder.LineComment] = "Redirects specifies whether only redirects to the same host should be followed by the HTTP Client."
HTTPRequestDoc.Fields[25].Name = "pipeline"
HTTPRequestDoc.Fields[25].Type = "bool"
HTTPRequestDoc.Fields[25].Note = ""
HTTPRequestDoc.Fields[25].Description = "Unsafe specifies whether to use rawhttp engine for sending Non RFC-Compliant requests.\n\nThis uses the [rawhttp](https://github.com/projectdiscovery/rawhttp) engine to achieve complete\ncontrol over the request, with no normalization performed by the client."
HTTPRequestDoc.Fields[25].Comments[encoder.LineComment] = "Unsafe specifies whether to use rawhttp engine for sending Non RFC-Compliant requests."
HTTPRequestDoc.Fields[26].Name = "race"
HTTPRequestDoc.Fields[25].Description = "Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining\n\nAll requests must be idempotent (GET/POST). This can be used for race conditions/billions requests."
HTTPRequestDoc.Fields[25].Comments[encoder.LineComment] = "Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining"
HTTPRequestDoc.Fields[26].Name = "unsafe"
HTTPRequestDoc.Fields[26].Type = "bool"
HTTPRequestDoc.Fields[26].Note = ""
HTTPRequestDoc.Fields[26].Description = "Race determines if all the request have to be attempted at the same time (Race Condition)\n\nThe actual number of requests that will be sent is determined by the `race_count` field."
HTTPRequestDoc.Fields[26].Comments[encoder.LineComment] = "Race determines if all the request have to be attempted at the same time (Race Condition)"
HTTPRequestDoc.Fields[27].Name = "req-condition"
HTTPRequestDoc.Fields[26].Description = "Unsafe specifies whether to use rawhttp engine for sending Non RFC-Compliant requests.\n\nThis uses the [rawhttp](https://github.com/projectdiscovery/rawhttp) engine to achieve complete\ncontrol over the request, with no normalization performed by the client."
HTTPRequestDoc.Fields[26].Comments[encoder.LineComment] = "Unsafe specifies whether to use rawhttp engine for sending Non RFC-Compliant requests."
HTTPRequestDoc.Fields[27].Name = "race"
HTTPRequestDoc.Fields[27].Type = "bool"
HTTPRequestDoc.Fields[27].Note = ""
HTTPRequestDoc.Fields[27].Description = "ReqCondition automatically assigns numbers to requests and preserves their history.\n\nThis allows matching on them later for multi-request conditions."
HTTPRequestDoc.Fields[27].Comments[encoder.LineComment] = "ReqCondition automatically assigns numbers to requests and preserves their history."
HTTPRequestDoc.Fields[28].Name = "stop-at-first-match"
HTTPRequestDoc.Fields[27].Description = "Race determines if all the request have to be attempted at the same time (Race Condition)\n\nThe actual number of requests that will be sent is determined by the `race_count` field."
HTTPRequestDoc.Fields[27].Comments[encoder.LineComment] = "Race determines if all the request have to be attempted at the same time (Race Condition)"
HTTPRequestDoc.Fields[28].Name = "req-condition"
HTTPRequestDoc.Fields[28].Type = "bool"
HTTPRequestDoc.Fields[28].Note = ""
HTTPRequestDoc.Fields[28].Description = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
HTTPRequestDoc.Fields[28].Comments[encoder.LineComment] = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
HTTPRequestDoc.Fields[29].Name = "skip-variables-check"
HTTPRequestDoc.Fields[28].Description = "ReqCondition automatically assigns numbers to requests and preserves their history.\n\nThis allows matching on them later for multi-request conditions."
HTTPRequestDoc.Fields[28].Comments[encoder.LineComment] = "ReqCondition automatically assigns numbers to requests and preserves their history."
HTTPRequestDoc.Fields[29].Name = "stop-at-first-match"
HTTPRequestDoc.Fields[29].Type = "bool"
HTTPRequestDoc.Fields[29].Note = ""
HTTPRequestDoc.Fields[29].Description = "SkipVariablesCheck skips the check for unresolved variables in request"
HTTPRequestDoc.Fields[29].Comments[encoder.LineComment] = "SkipVariablesCheck skips the check for unresolved variables in request"
HTTPRequestDoc.Fields[30].Name = "iterate-all"
HTTPRequestDoc.Fields[29].Description = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
HTTPRequestDoc.Fields[29].Comments[encoder.LineComment] = "StopAtFirstMatch stops the execution of the requests and template as soon as a match is found."
HTTPRequestDoc.Fields[30].Name = "skip-variables-check"
HTTPRequestDoc.Fields[30].Type = "bool"
HTTPRequestDoc.Fields[30].Note = ""
HTTPRequestDoc.Fields[30].Description = "IterateAll iterates all the values extracted from internal extractors"
HTTPRequestDoc.Fields[30].Comments[encoder.LineComment] = "IterateAll iterates all the values extracted from internal extractors"
HTTPRequestDoc.Fields[31].Name = "digest-username"
HTTPRequestDoc.Fields[31].Type = "string"
HTTPRequestDoc.Fields[30].Description = "SkipVariablesCheck skips the check for unresolved variables in request"
HTTPRequestDoc.Fields[30].Comments[encoder.LineComment] = "SkipVariablesCheck skips the check for unresolved variables in request"
HTTPRequestDoc.Fields[31].Name = "iterate-all"
HTTPRequestDoc.Fields[31].Type = "bool"
HTTPRequestDoc.Fields[31].Note = ""
HTTPRequestDoc.Fields[31].Description = "DigestAuthUsername specifies the username for digest authentication"
HTTPRequestDoc.Fields[31].Comments[encoder.LineComment] = "DigestAuthUsername specifies the username for digest authentication"
HTTPRequestDoc.Fields[32].Name = "digest-password"
HTTPRequestDoc.Fields[31].Description = "IterateAll iterates all the values extracted from internal extractors"
HTTPRequestDoc.Fields[31].Comments[encoder.LineComment] = "IterateAll iterates all the values extracted from internal extractors"
HTTPRequestDoc.Fields[32].Name = "digest-username"
HTTPRequestDoc.Fields[32].Type = "string"
HTTPRequestDoc.Fields[32].Note = ""
HTTPRequestDoc.Fields[32].Description = "DigestAuthPassword specifies the password for digest authentication"
HTTPRequestDoc.Fields[32].Comments[encoder.LineComment] = "DigestAuthPassword specifies the password for digest authentication"
HTTPRequestDoc.Fields[33].Name = "disable-path-automerge"
HTTPRequestDoc.Fields[33].Type = "bool"
HTTPRequestDoc.Fields[32].Description = "DigestAuthUsername specifies the username for digest authentication"
HTTPRequestDoc.Fields[32].Comments[encoder.LineComment] = "DigestAuthUsername specifies the username for digest authentication"
HTTPRequestDoc.Fields[33].Name = "digest-password"
HTTPRequestDoc.Fields[33].Type = "string"
HTTPRequestDoc.Fields[33].Note = ""
HTTPRequestDoc.Fields[33].Description = "DisablePathAutomerge disables merging target url path with raw request path"
HTTPRequestDoc.Fields[33].Comments[encoder.LineComment] = "DisablePathAutomerge disables merging target url path with raw request path"
HTTPRequestDoc.Fields[34].Name = "pre-condition"
HTTPRequestDoc.Fields[34].Type = "[]matchers.Matcher"
HTTPRequestDoc.Fields[33].Description = "DigestAuthPassword specifies the password for digest authentication"
HTTPRequestDoc.Fields[33].Comments[encoder.LineComment] = "DigestAuthPassword specifies the password for digest authentication"
HTTPRequestDoc.Fields[34].Name = "disable-path-automerge"
HTTPRequestDoc.Fields[34].Type = "bool"
HTTPRequestDoc.Fields[34].Note = ""
HTTPRequestDoc.Fields[34].Description = "Fuzz PreCondition is matcher-like field to check if fuzzing should be performed on this request or not"
HTTPRequestDoc.Fields[34].Comments[encoder.LineComment] = "Fuzz PreCondition is matcher-like field to check if fuzzing should be performed on this request or not"
HTTPRequestDoc.Fields[35].Name = "pre-condition-operator"
HTTPRequestDoc.Fields[35].Type = "string"
HTTPRequestDoc.Fields[34].Description = "DisablePathAutomerge disables merging target url path with raw request path"
HTTPRequestDoc.Fields[34].Comments[encoder.LineComment] = "DisablePathAutomerge disables merging target url path with raw request path"
HTTPRequestDoc.Fields[35].Name = "pre-condition"
HTTPRequestDoc.Fields[35].Type = "[]matchers.Matcher"
HTTPRequestDoc.Fields[35].Note = ""
HTTPRequestDoc.Fields[35].Description = "FuzzPreConditionOperator is the operator between multiple PreConditions for fuzzing Default is OR"
HTTPRequestDoc.Fields[35].Comments[encoder.LineComment] = "FuzzPreConditionOperator is the operator between multiple PreConditions for fuzzing Default is OR"
HTTPRequestDoc.Fields[36].Name = "global-matchers"
HTTPRequestDoc.Fields[36].Type = "bool"
HTTPRequestDoc.Fields[35].Description = "Fuzz PreCondition is matcher-like field to check if fuzzing should be performed on this request or not"
HTTPRequestDoc.Fields[35].Comments[encoder.LineComment] = "Fuzz PreCondition is matcher-like field to check if fuzzing should be performed on this request or not"
HTTPRequestDoc.Fields[36].Name = "pre-condition-operator"
HTTPRequestDoc.Fields[36].Type = "string"
HTTPRequestDoc.Fields[36].Note = ""
HTTPRequestDoc.Fields[36].Description = "GlobalMatchers marks matchers as static and applies globally to all result events from other templates"
HTTPRequestDoc.Fields[36].Comments[encoder.LineComment] = "GlobalMatchers marks matchers as static and applies globally to all result events from other templates"
HTTPRequestDoc.Fields[36].Description = "FuzzPreConditionOperator is the operator between multiple PreConditions for fuzzing Default is OR"
HTTPRequestDoc.Fields[36].Comments[encoder.LineComment] = "FuzzPreConditionOperator is the operator between multiple PreConditions for fuzzing Default is OR"
HTTPRequestDoc.Fields[37].Name = "global-matchers"
HTTPRequestDoc.Fields[37].Type = "bool"
HTTPRequestDoc.Fields[37].Note = ""
HTTPRequestDoc.Fields[37].Description = "GlobalMatchers marks matchers as static and applies globally to all result events from other templates"
HTTPRequestDoc.Fields[37].Comments[encoder.LineComment] = "GlobalMatchers marks matchers as static and applies globally to all result events from other templates"
GENERATORSAttackTypeHolderDoc.Type = "generators.AttackTypeHolder"
GENERATORSAttackTypeHolderDoc.Comments[encoder.LineComment] = " AttackTypeHolder is used to hold internal type of the protocol"
@@ -847,6 +853,30 @@ func init() {
}
SliceOrMapSliceDoc.Fields = make([]encoder.Doc, 0)
ANALYZERSAnalyzerTemplateDoc.Type = "analyzers.AnalyzerTemplate"
ANALYZERSAnalyzerTemplateDoc.Comments[encoder.LineComment] = " AnalyzerTemplate is the template for the analyzer"
ANALYZERSAnalyzerTemplateDoc.Description = "AnalyzerTemplate is the template for the analyzer"
ANALYZERSAnalyzerTemplateDoc.AppearsIn = []encoder.Appearance{
{
TypeName: "http.Request",
FieldName: "analyzer",
},
}
ANALYZERSAnalyzerTemplateDoc.Fields = make([]encoder.Doc, 2)
ANALYZERSAnalyzerTemplateDoc.Fields[0].Name = "name"
ANALYZERSAnalyzerTemplateDoc.Fields[0].Type = "string"
ANALYZERSAnalyzerTemplateDoc.Fields[0].Note = ""
ANALYZERSAnalyzerTemplateDoc.Fields[0].Description = "Name is the name of the analyzer to use"
ANALYZERSAnalyzerTemplateDoc.Fields[0].Comments[encoder.LineComment] = "Name is the name of the analyzer to use"
ANALYZERSAnalyzerTemplateDoc.Fields[0].Values = []string{
"time_delay",
}
ANALYZERSAnalyzerTemplateDoc.Fields[1].Name = "parameters"
ANALYZERSAnalyzerTemplateDoc.Fields[1].Type = "map[string]interface{}"
ANALYZERSAnalyzerTemplateDoc.Fields[1].Note = ""
ANALYZERSAnalyzerTemplateDoc.Fields[1].Description = "Parameters is the parameters for the analyzer\n\nParameters are different for each analyzer. For example, you can customize\ntime_delay analyzer with sleep_duration, time_slope_error_range, etc. Refer\nto the docs for each analyzer to get an idea about parameters."
ANALYZERSAnalyzerTemplateDoc.Fields[1].Comments[encoder.LineComment] = "Parameters is the parameters for the analyzer"
SignatureTypeHolderDoc.Type = "SignatureTypeHolder"
SignatureTypeHolderDoc.Comments[encoder.LineComment] = " SignatureTypeHolder is used to hold internal type of the signature"
SignatureTypeHolderDoc.Description = "SignatureTypeHolder is used to hold internal type of the signature"
@@ -2127,6 +2157,7 @@ func GetTemplateDoc() *encoder.FileDoc {
&HTTPMethodTypeHolderDoc,
&FUZZRuleDoc,
&SliceOrMapSliceDoc,
&ANALYZERSAnalyzerTemplateDoc,
&SignatureTypeHolderDoc,
&MATCHERSMatcherDoc,
&MatcherTypeHolderDoc,
+20 -21
View File
@@ -137,7 +137,7 @@ func TestFlowWithConditionPositive(t *testing.T) {
err = Template.Executer.Compile()
require.Nil(t, err, "could not compile template")
input := contextargs.NewWithInput(context.Background(), "blog.projectdiscovery.io")
input := contextargs.NewWithInput(context.Background(), "cloud.projectdiscovery.io")
ctx := scan.NewScanContext(context.Background(), input)
// positive match . expect results also verify that both dns() and http() were executed
gotresults, err := Template.Executer.Execute(ctx)
@@ -150,8 +150,7 @@ func TestFlowWithNoMatchers(t *testing.T) {
// when using conditional flow with no matchers at all
// we implicitly assume that request was successful and internally changed the result to true (for scope of condition only)
// testcase-1 : no matchers but contains extractor
Template, err := templates.Parse("testcases/condition-flow-extractors.yaml", nil, executerOpts)
Template, err := templates.Parse("testcases/condition-flow-no-operators.yaml", nil, executerOpts)
require.Nil(t, err, "could not parse template")
require.True(t, Template.Flow != "", "not a flow template") // this is classifer if template is flow or not
@@ -159,27 +158,27 @@ func TestFlowWithNoMatchers(t *testing.T) {
err = Template.Executer.Compile()
require.Nil(t, err, "could not compile template")
input := contextargs.NewWithInput(context.Background(), "blog.projectdiscovery.io")
ctx := scan.NewScanContext(context.Background(), input)
// positive match . expect results also verify that both dns() and http() were executed
gotresults, err := Template.Executer.Execute(ctx)
require.Nil(t, err, "could not execute template")
require.True(t, gotresults)
// testcase-2 : no matchers and no extractors
Template, err = templates.Parse("testcases/condition-flow-no-operators.yaml", nil, executerOpts)
require.Nil(t, err, "could not parse template")
require.True(t, Template.Flow != "", "not a flow template") // this is classifer if template is flow or not
err = Template.Executer.Compile()
require.Nil(t, err, "could not compile template")
anotherInput := contextargs.NewWithInput(context.Background(), "blog.projectdiscovery.io")
anotherInput := contextargs.NewWithInput(context.Background(), "cloud.projectdiscovery.io")
anotherCtx := scan.NewScanContext(context.Background(), anotherInput)
// positive match . expect results also verify that both dns() and http() were executed
gotresults, err = Template.Executer.Execute(anotherCtx)
gotresults, err := Template.Executer.Execute(anotherCtx)
require.Nil(t, err, "could not execute template")
require.True(t, gotresults)
t.Run("Contains Extractor", func(t *testing.T) {
Template, err := templates.Parse("testcases/condition-flow-extractors.yaml", nil, executerOpts)
require.Nil(t, err, "could not parse template")
require.True(t, Template.Flow != "", "not a flow template") // this is classifer if template is flow or not
err = Template.Executer.Compile()
require.Nil(t, err, "could not compile template")
input := contextargs.NewWithInput(context.Background(), "scanme.sh")
ctx := scan.NewScanContext(context.Background(), input)
// positive match . expect results also verify that both dns() and http() were executed
gotresults, err := Template.Executer.Execute(ctx)
require.Nil(t, err, "could not execute template")
require.True(t, gotresults)
})
}
@@ -1,29 +1,28 @@
id: ghost-blog-detection
id: condition-flow-extractors
info:
name: Ghost blog detection
name: Condition Flow Extractors
author: pdteam
severity: info
flow: dns() && http()
dns:
- name: "{{FQDN}}"
type: CNAME
type: A
extractors:
- type: dsl
name: cname
name: a
internal: true
dsl:
- cname
- a
http:
- method: GET
path:
- "{{BaseURL}}?ref={{cname}}"
- "{{BaseURL}}/?ref={{a}}"
matchers:
- type: word
words:
- "ghost.io"
- "ok"
@@ -1,23 +1,21 @@
id: ghost-blog-detection
id: condition-flow-no-operators
info:
name: Ghost blog detection
name: Condition Flow No Operators
author: pdteam
severity: info
flow: dns() && http()
dns:
- name: "{{FQDN}}"
type: CNAME
http:
- method: GET
path:
- "{{BaseURL}}?ref={{dns_cname}}"
- "{{BaseURL}}/?ref={{dns_cname}}"
matchers:
- type: word
words:
- "ghost.io"
- "html>"
@@ -1,6 +1,6 @@
id: ghost-blog-detection
id: vercel-hosted-detection
info:
name: Ghost blog detection
name: Vercel-hosted detection
author: pdteam
severity: info
@@ -14,14 +14,14 @@ dns:
matchers:
- type: word
words:
- "ghost.io"
- "vercel-dns"
http:
- method: GET
path:
- "{{BaseURL}}"
- "{{dns_cname}}"
matchers:
- type: word
words:
- "ghost.io"
- "DEPLOYMENT_NOT_FOUND"
+2 -2
View File
@@ -56,7 +56,7 @@ func TestMultiProtoWithDynamicExtractor(t *testing.T) {
err = Template.Executer.Compile()
require.Nil(t, err, "could not compile template")
input := contextargs.NewWithInput(context.Background(), "blog.projectdiscovery.io")
input := contextargs.NewWithInput(context.Background(), "http://scanme.sh")
ctx := scan.NewScanContext(context.Background(), input)
gotresults, err := Template.Executer.Execute(ctx)
require.Nil(t, err, "could not execute template")
@@ -72,7 +72,7 @@ func TestMultiProtoWithProtoPrefix(t *testing.T) {
err = Template.Executer.Compile()
require.Nil(t, err, "could not compile template")
input := contextargs.NewWithInput(context.Background(), "blog.projectdiscovery.io")
input := contextargs.NewWithInput(context.Background(), "https://cloud.projectdiscovery.io/sign-in")
ctx := scan.NewScanContext(context.Background(), input)
gotresults, err := Template.Executer.Execute(ctx)
require.Nil(t, err, "could not execute template")
@@ -7,15 +7,7 @@ info:
dns:
- name: "{{FQDN}}" # DNS Request
type: cname
extractors:
- type: dsl
name: blogid
dsl:
- trim_suffix(cname,'.ghost.io')
internal: true
type: a
http:
- method: GET # http request
@@ -25,6 +17,6 @@ http:
matchers:
- type: dsl
dsl:
- contains(body,'ProjectDiscovery.io') # check for http string
- blogid == 'projectdiscovery' # check for cname (extracted information from dns response)
- body == "ok"
- dns_a == '128.199.158.128' # check for A record (extracted information from dns response)
condition: and
@@ -20,7 +20,7 @@ http:
matchers:
- type: dsl
dsl:
- contains(http_body,'ProjectDiscovery.io') # check for http string
- trim_suffix(dns_cname,'.ghost.io') == 'projectdiscovery' # check for cname (extracted information from dns response)
- ssl_subject_cn == 'blog.projectdiscovery.io'
- contains(http_body, 'ProjectDiscovery Cloud Platform') # check for http string
- dns_cname == 'cname.vercel-dns.com' # check for cname (extracted information from dns response)
- ssl_subject_cn == 'cloud.projectdiscovery.io'
condition: and
+6
View File
@@ -383,6 +383,12 @@ type Options struct {
EnableCodeTemplates bool
// DisableUnsignedTemplates disables processing of unsigned templates
DisableUnsignedTemplates bool
// EnableSelfContainedTemplates enables processing of self-contained templates
EnableSelfContainedTemplates bool
// EnableGlobalMatchersTemplates enables processing of global-matchers templates
EnableGlobalMatchersTemplates bool
// EnableFileTemplates enables file templates
EnableFileTemplates bool
// Disables cloud upload
EnableCloudUpload bool
// ScanID is the scan ID to use for cloud upload