Compare commits

..
227 changed files with 2965 additions and 6181 deletions

No files matched your search

-72
View File
@@ -1,72 +0,0 @@
name: Bug Report
description: Create a report to help us to improve the Nuclei.
title: "[BUG] ..."
labels: ["Type: Bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
For support requests, FAQs or "How to" questions, please use the [GitHub Discussions](https://github.com/projectdiscovery/nuclei/discussions) section instead or join our [Discord server](https://discord.gg/projectdiscovery) to discuss the idea on the **#nuclei** channel.
:warning: **Issues missing important information may be closed without further investigation.**
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues.
required: true
- type: textarea
attributes:
label: Current Behavior
description: A concise description of what you're experiencing.
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Steps To Reproduce
description: |
Steps to reproduce the behavior, for example, commands to run Nuclei.
:warning: **Please redact any literal target hosts/URLs or other sensitive information.**
placeholder: |
1. Run `nuclei -t ...`
validations:
required: true
- type: textarea
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: textarea
attributes:
label: Environment
description: |
Examples:
- **OS**: Ubuntu 20.04
- **Nuclei** (`nuclei -version`): v3.3.1
- **Go** (`go version`): go1.22.0 _(only if you've installed it via the `go install` command)_
value: |
- OS:
- Nuclei:
- Go:
render: markdown
validations:
required: true
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Templates? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
@@ -1,37 +0,0 @@
name: Feature Request
description: Request feature to implement in the Nuclei.
title: "[FEATURE] ..."
labels: ["Type: Enhancement"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request!
Please make sure to provide a detailed description with all the relevant information that might be required to start working on this feature. In case you are not sure about your request or whether the particular feature is already supported or not, please [start a discussion](https://github.com/projectdiscovery/nuclei/discussions/categories/ideas) instead.
Join our [Discord server](https://discord.gg/projectdiscovery) to discuss the idea on the **#nuclei** channel.
- type: textarea
attributes:
label: Describe your feature request
description: A clear and concise description of feature to implement.
validations:
required: true
- type: textarea
attributes:
label: Describe the use case of the feature
description: A clear and concise description of the feature request's motivation and the use-cases in which it could be useful.
validations:
required: true
- type: textarea
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
attributes:
label: Additional context
description: Add any other context about the feature request here.
validations:
required: false
+21
View File
@@ -0,0 +1,21 @@
---
name: Feature request
about: Request feature to implement in this project
title: ""
labels: 'Type: Enhancement'
assignees: ''
---
<!--
1. Please make sure to provide a detailed description with all the relevant information that might be required to start working on this feature.
2. In case you are not sure about your request or whether the particular feature is already supported or not, please start a discussion instead.
3. GitHub Discussion: https://github.com/projectdiscovery/nuclei/discussions/categories/ideas
4. Join our discord server at https://discord.gg/projectdiscovery to discuss the idea on the #nuclei channel.
-->
### Please describe your feature request:
<!-- A clear and concise description of feature to implement -->
### Describe the use case of this feature:
<!-- A clear and concise description of the feature request's motivation and the use-cases in which it could be useful. -->
+36
View File
@@ -0,0 +1,36 @@
---
name: Issue report
about: Create a report to help us to improve the project
labels: 'Type: Bug'
---
<!--
1. Please search to see if an issue already exists for the bug you encountered.
2. For support requests, FAQs or "How to" questions, please use the GitHub Discussions section instead - https://github.com/projectdiscovery/nuclei/discussions or
3. Join our discord server at https://discord.gg/projectdiscovery and post the question on the #nuclei channel.
-->
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
### Nuclei version:
<!-- You can find current version of nuclei with "nuclei -version" -->
<!-- We only accept issues that are reproducible on the latest version of nuclei. -->
<!-- You can find the latest version of project at https://github.com/projectdiscovery/nuclei/releases/ -->
### Current Behavior:
<!-- A concise description of what you're experiencing. -->
### Expected Behavior:
<!-- A concise description of what you expected to happen. -->
### Steps To Reproduce:
<!--
Example: steps to reproduce the behavior:
1. Run 'nuclei -t ... -u ..'
2. See error...
-->
### Anything else:
<!-- Links? References? Screenshots? Anything that will give us more context about the issue that you are encountering! -->
-8
View File
@@ -1,8 +0,0 @@
addReviewers: true
reviewers:
- dogancanbakir
numberOfReviewers: 1
# A list of keywords to be skipped the process that add reviewers if pull requests include it
# skipKeywords:
# - wip
+16 -14
View File
@@ -12,23 +12,28 @@ jobs:
name: Test Builds
strategy:
matrix:
go-version: [1.21.x]
os: [ubuntu-latest, windows-latest, macOS-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Go
uses: projectdiscovery/actions/setup/go@v1
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
# required for running python code in py-snippet.yaml integration test
- name: Set up Python
- name: Set up Python # required for running python code in py-snippet.yaml integration test
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Verify Go modules
run: make verify
- name: Check out code
uses: actions/checkout@v3
- name: Go Mod hygiene
run: |
go clean -modcache
go mod tidy
- name: Build
run: go build .
@@ -37,7 +42,6 @@ jobs:
- name: Test
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
run: go test ./...
- name: Integration Tests
@@ -45,7 +49,6 @@ jobs:
env:
GH_ACTION: true
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
run: |
chmod +x run.sh
bash run.sh ${{ matrix.os }}
@@ -60,10 +63,9 @@ jobs:
run: go run .
working-directory: examples/simple/
# Temporarily disabled very flaky in github actions
# - name: Example SDK Advanced
# run: go run .
# working-directory: examples/advanced/
- name: Example SDK Advanced
run: go run .
working-directory: examples/advanced/
- name: Example SDK with speed control
run: go run .
+6 -4
View File
@@ -15,11 +15,13 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Go
uses: projectdiscovery/actions/setup/go@v1
uses: actions/setup-go@v4
with:
go-version: 1.21.x
- name: Check out code
uses: actions/checkout@v3
- name: Functional Tests
env:
+10 -5
View File
@@ -12,11 +12,16 @@ jobs:
name: Lint Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: projectdiscovery/actions/setup/go@v1
uses: actions/setup-go@v4
with:
go-version: 1.21.x
- name: Checkout code
uses: actions/checkout@v3
- name: Run golangci-lint
uses: projectdiscovery/actions/golangci-lint@v1
uses: golangci/[email protected]
with:
version: latest
args: --timeout 5m
+11 -6
View File
@@ -11,19 +11,24 @@ jobs:
name: Test Performance
strategy:
matrix:
go-version: [1.21.x]
os: [ubuntu-latest, macOS-latest]
runs-on: ${{ matrix.os }}
if: github.repository == 'projectdiscovery/nuclei'
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Go
uses: projectdiscovery/actions/setup/go@v1
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Verify Go modules
run: make verify
- name: Check out code
uses: actions/checkout@v3
- name: Go Mod hygine
run: |
go clean -modcache
go mod tidy
# Max GH exection time 6H => timeout after that
- name: Running performance with big list
+6 -5
View File
@@ -11,15 +11,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: "Set up Go"
uses: projectdiscovery/actions/setup/go@v1
- name: "Set up Git"
uses: projectdiscovery/actions/setup/git@v1
uses: actions/setup-go@v4
with:
go-version: 1.21.x
- name: Generate YAML Syntax Documentation
id: generate-docs
@@ -36,6 +35,8 @@ jobs:
- name: Commit files
if: steps.generate-docs.outputs.CHANGES > 0
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git add SYNTAX-REFERENCE.md nuclei-jsonschema.json
git commit -m "Auto Generate Syntax Docs + JSONSchema [$(date)] :robot:" -a
+9 -6
View File
@@ -9,17 +9,20 @@ on:
jobs:
release:
runs-on: ubuntu-latest-16-cores
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: projectdiscovery/actions/setup/go@v1
- uses: projectdiscovery/actions/goreleaser@v1
- uses: actions/setup-go@v4
with:
release: true
go-version: 1.21.x
- uses: goreleaser/goreleaser-action@v4
with:
args: "release --rm-dist"
version: latest
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
SLACK_WEBHOOK: "${{ secrets.RELEASE_SLACK_WEBHOOK }}"
+9 -4
View File
@@ -12,12 +12,17 @@ jobs:
runs-on: ubuntu-latest-16-cores
steps:
- name: "Check out code"
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Go
uses: projectdiscovery/actions/setup/go@v1
uses: actions/setup-go@v4
with:
go-version: 1.21.x
- name: Release snapshot
uses: projectdiscovery/actions/goreleaser@v1
- name: release test
uses: goreleaser/goreleaser-action@v4
with:
args: "release --clean --snapshot"
version: latest
+4 -3
View File
@@ -10,9 +10,10 @@ jobs:
build:
runs-on: ubuntu-latest-16-cores
steps:
- uses: actions/checkout@v4
- uses: projectdiscovery/actions/setup/go@v1
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: 1.21.x
- name: Template Validation
run: |
+37 -36
View File
@@ -1,42 +1,43 @@
# Misc
**/*-cache
**/*-config
**/.cache
*.DS_Store
*.exe
.devcontainer
.gitignore
.idea
.vscode
# Binaries
**/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
# Generated docs
/dsl.md
# Junk
.devcontainer
vendor
dist
integration_tests/nuclei
integration_tests/.cache
integration_tests/integration-test
cmd/nuclei/main
cmd/nuclei/nuclei
cmd/integration-test/nuclei
cmd/functional-test/nuclei_dev
cmd/functional-test/nuclei_main
cmd/functional-test/functional-test
cmd/docgen/docgen
pkg/protocols/common/helpers/deserialization/testdata/Deserialize.class
pkg/protocols/common/helpers/deserialization/testdata/ValueObject.class
pkg/protocols/common/helpers/deserialization/testdata/ValueObject2.ser
vendor
*.exe
.gitignore
pkg/js/devtools/bindgen/cmd/bindgen/bindgen
pkg/js/devtools/jsdocgen/jsdocgen
pkg/js/devtools/tsgen/tsgen
pkg/js/devtools/tsgen/cmd/tsgen/tsgen
*.DS_Store
pkg/protocols/headless/engine/.cache
/nuclei
/bindgen
/jsdocgen
/tsgen
/scrapefuncs
/integration_tests/.cache/
/*.yaml
**/*-config
**/*-cache
/fuzzplayground
integration_tests/fuzzplayground
/dsl.md
/nuclei-stats
/nuclei-stats-*
/scan-charts
+39 -104
View File
@@ -1,127 +1,62 @@
# Go parameters
GOCMD := go
GOBUILD := $(GOCMD) build
GOBUILD_OUTPUT :=
GOBUILD_PACKAGES :=
GOBUILD_ADDITIONAL_ARGS :=
GOMOD := $(GOCMD) mod
GOTEST := $(GOCMD) test
GOCMD=go
GOBUILD=$(GOCMD) build
GOMOD=$(GOCMD) mod
GOTEST=$(GOCMD) test
GOFLAGS := -v
# This should be disabled if the binary uses pprof
LDFLAGS := -s -w
ifneq ($(shell go env GOOS),darwin)
LDFLAGS = -extldflags "-static"
LDFLAGS := -extldflags "-static"
endif
.PHONY: all build build-stats clean devtools-all devtools-bindgen devtools-scrapefuncs
.PHONY: devtools-tsgen docs dsl-docs functional fuzzplayground go-build integration
.PHONY: jsupdate-all jsupdate-bindgen jsupdate-tsgen memogen scan-charts test tidy ts verify
.PHONY: all build build-stats scan-charts docs test integration functional tidy devtools jsupdate ts fuzzplayground memogen dsl-docs
all: build
clean:
rm -f '${GOBUILD_OUTPUT}' 2>/dev/null
go-build: clean
go-build:
$(GOBUILD) $(GOFLAGS) -ldflags '${LDFLAGS}' $(GOBUILD_ADDITIONAL_ARGS) \
-o '${GOBUILD_OUTPUT}' $(GOBUILD_PACKAGES)
build: GOBUILD_OUTPUT = nuclei
build: GOBUILD_PACKAGES = cmd/nuclei/main.go
build: go-build
build-stats: GOBUILD_OUTPUT = nuclei-stats
build-stats: GOBUILD_PACKAGES = cmd/nuclei/main.go
build-stats: GOBUILD_ADDITIONAL_ARGS = -tags=stats
build-stats: go-build
scan-charts: GOBUILD_OUTPUT = scan-charts
scan-charts: GOBUILD_PACKAGES = cmd/scan-charts/main.go
scan-charts: go-build
docs: GOBUILD_OUTPUT = cmd/docgen/docgen
docs: GOBUILD_PACKAGES = cmd/docgen/docgen.go
docs: bin = dstdocgen
build:
rm -f nuclei 2>/dev/null
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "nuclei" cmd/nuclei/main.go
build-stats:
rm -f nuclei-stats 2>/dev/null
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -tags=stats -o "nuclei-stats" cmd/nuclei/main.go
scan-charts:
rm -f scan-charts 2>/dev/null
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "scan-charts" cmd/scan-charts/main.go
docs:
@if ! which $(bin) >/dev/null; then \
read -p "${bin} not found. Do you want to install it? (y/n) " answer; \
if [ "$$answer" = "y" ]; then \
echo "Installing ${bin}..."; \
go get -v github.com/projectdiscovery/yamldoc-go/cmd/docgen/$(bin); \
go install -v github.com/projectdiscovery/yamldoc-go/cmd/docgen/$(bin); \
else \
echo "Please install ${bin} manually."; \
exit 1; \
fi \
if ! which dstdocgen > /dev/null; then
echo -e "Command not found! Install? (y/n) \c"
go get -v github.com/projectdiscovery/yamldoc-go/cmd/docgen/dstdocgen
fi
# TODO: Handle the panic, so that we just need to run `go install $(bin)@latest` (line 51-52)
$(GOCMD) generate pkg/templates/templates.go
$(GOBUILD) -o "${GOBUILD_OUTPUT}" $(GOBUILD_PACKAGES)
./$(GOBUILD_OUTPUT) docs.md nuclei-jsonschema.json
git reset --hard # line 59
$(GOBUILD) -o "cmd/docgen/docgen" cmd/docgen/docgen.go
./cmd/docgen/docgen docs.md nuclei-jsonschema.json
test:
$(GOTEST) $(GOFLAGS) ./...
integration:
cd integration_tests; bash run.sh
functional:
cd cmd/functional-test; bash run.sh
tidy:
$(GOMOD) tidy
verify: tidy
$(GOMOD) verify
devtools-bindgen: GOBUILD_OUTPUT = bindgen
devtools-bindgen: GOBUILD_PACKAGES = pkg/js/devtools/bindgen/cmd/bindgen/main.go
devtools-bindgen: go-build
devtools-tsgen: GOBUILD_OUTPUT = tsgen
devtools-tsgen: GOBUILD_PACKAGES = pkg/js/devtools/tsgen/cmd/tsgen/main.go
devtools-tsgen: go-build
devtools-scrapefuncs: GOBUILD_OUTPUT = scrapefuncs
devtools-scrapefuncs: GOBUILD_PACKAGES = pkg/js/devtools/scrapefuncs/main.go
devtools-scrapefuncs: go-build
devtools-all: devtools-bindgen devtools-tsgen devtools-scrapefuncs
jsupdate-bindgen: GOBUILD_OUTPUT = bindgen
jsupdate-bindgen: GOBUILD_PACKAGES = pkg/js/devtools/bindgen/cmd/bindgen/main.go
jsupdate-bindgen: go-build
jsupdate-bindgen:
./$(GOBUILD_OUTPUT) -dir pkg/js/libs -out pkg/js/generated
jsupdate-tsgen: GOBUILD_OUTPUT = tsgen
jsupdate-tsgen: GOBUILD_PACKAGES = pkg/js/devtools/tsgen/cmd/tsgen/main.go
jsupdate-tsgen: go-build
jsupdate-tsgen:
./$(GOBUILD_OUTPUT) -dir pkg/js/libs -out pkg/js/generated/ts
jsupdate-all: jsupdate-bindgen jsupdate-tsgen
ts: jsupdate-tsgen
fuzzplayground: GOBUILD_OUTPUT = fuzzplayground
fuzzplayground: GOBUILD_PACKAGES = cmd/tools/fuzzplayground/main.go
fuzzplayground: LDFLAGS = -s -w
fuzzplayground: go-build
memogen: GOBUILD_OUTPUT = memogen
memogen: GOBUILD_PACKAGES = cmd/memogen/memogen.go
memogen: go-build
devtools:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "bindgen" pkg/js/devtools/bindgen/cmd/bindgen/main.go
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "tsgen" pkg/js/devtools/tsgen/cmd/tsgen/main.go
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "scrapefuncs" pkg/js/devtools/scrapefuncs/main.go
jsupdate:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "bindgen" pkg/js/devtools/bindgen/cmd/bindgen/main.go
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "tsgen" pkg/js/devtools/tsgen/cmd/tsgen/main.go
./bindgen -dir pkg/js/libs -out pkg/js/generated
./tsgen -dir pkg/js/libs -out pkg/js/generated/ts
ts:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "tsgen" pkg/js/devtools/tsgen/cmd/tsgen/main.go
./tsgen -dir pkg/js/libs -out pkg/js/generated/ts
fuzzplayground:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "fuzzplayground" cmd/tools/fuzzplayground/main.go
memogen:
./$(GOBUILD_OUTPUT) -src pkg/js/libs -tpl cmd/memogen/function.tpl
dsl-docs: GOBUILD_OUTPUT = scrapefuncs
dsl-docs: GOBUILD_PACKAGES = pkg/js/devtools/scrapefuncs/main.go
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "memogen" cmd/memogen/memogen.go
./memogen -src pkg/js/libs -tpl cmd/memogen/function.tpl
dsl-docs:
./$(GOBUILD_OUTPUT) -out dsl.md
rm -f dsl.md scrapefuncs 2>/dev/null
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "scrapefuncs" pkg/js/devtools/scrapefuncs/main.go
./scrapefuncs -out dsl.md
+12 -26
View File
@@ -30,10 +30,7 @@
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">Korean</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">Spanish</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">日本語</a>
</p>
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a>
</p>
---
@@ -140,7 +137,6 @@ TEMPLATES:
-nss, -no-strict-syntax disable strict syntax check on templates
-td, -template-display displays the templates content
-tl list all available templates
-tgl list all available tags
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
-code enable loading code protocol-based templates
-dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
@@ -179,12 +175,9 @@ OUTPUT:
-se, -sarif-export string file to export results in SARIF format
-je, -json-export string file to export results in JSON format
-jle, -jsonl-export string file to export results in JSONL(ine) format
-rd, -redact string[] redact given list of keys from query parameter, request header and body
CONFIGURATIONS:
-config string path to the nuclei configuration file
-tp, -profile string template profile config file to run
-tpl, -profile-list list community template profiles
-fr, -follow-redirects enable following redirects for http templates
-fhr, -follow-host-redirects follow redirects on the same host
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
@@ -204,17 +197,17 @@ CONFIGURATIONS:
-sml, -show-match-line show match lines for file templates, works with extractors only
-ztls use ztls library with autofallback to standard one for tls13 [Deprecated] autofallback to ztls is enabled by default
-sni string tls sni hostname to use (default: input domain name)
-dt, -dialer-timeout value timeout for network requests.
-dka, -dialer-keep-alive value keep-alive duration for network requests.
-lfa, -allow-local-file-access allows file (payload) access anywhere on the system
-lna, -restrict-local-network-access blocks connections to the local / private network
-i, -interface string network interface to use for network scan
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
-sip, -source-ip string source ip address to use for network scan
-rsr, -response-size-read int max response size to read in bytes
-rsr, -response-size-read int max response size to read in bytes (default 10485760)
-rss, -response-size-save int max response size to read in bytes (default 1048576)
-reset reset removes all nuclei configuration and data files (including nuclei-templates)
-tlsi, -tls-impersonate enable experimental client hello (ja3) tls randomization
-hae, -http-api-endpoint string experimental http api endpoint
INTERACTSH:
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
@@ -226,33 +219,28 @@ INTERACTSH:
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
FUZZING:
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
-dast enable / run dast (fuzz) nuclei templates
-dfp, -display-fuzz-points display fuzz points in the output for debugging
-fuzz-param-frequency int frequency of uninteresting parameters for fuzzing before skipping (default 10)
-fa, -fuzz-aggression string fuzzing aggression level controls payload count for fuzz (low, medium, high) (default "low")
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
-dast only run DAST templates
UNCOVER:
-uc, -uncover enable uncover engine
-uq, -uncover-query string[] uncover search query
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow,google) (default shodan)
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow) (default shodan)
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
-ul, -uncover-limit int uncover results to return (default 100)
-ur, -uncover-ratelimit int override ratelimit of engines with unknown ratelimit (default 60 req/min) (default 60)
RATE-LIMIT:
-rl, -rate-limit int maximum number of requests to send per second (default 150)
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
-rlm, -rate-limit-minute int maximum number of requests to send per minute
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
-jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
-pc, -payload-concurrency int max payload concurrency for each template (default 25)
-prc, -probe-concurrency int http probe concurrency with httpx (default 50)
OPTIMIZATIONS:
-timeout int time to wait in seconds before timeout (default 10)
@@ -310,11 +298,9 @@ STATISTICS:
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
CLOUD:
-auth configure projectdiscovery cloud (pdcp) api key (default true)
-tid, -team-id string upload scan results to given team id (optional) (default "none")
-cup, -cloud-upload upload scan results to pdcp dashboard
-sid, -scan-id string upload scan results to existing scan id (optional)
-sname, -scan-name string scan name to set (optional)
-auth configure projectdiscovery cloud (pdcp) api key
-cup, -cloud-upload upload scan results to pdcp dashboard
-sid, -scan-id string upload scan results to given scan id
AUTHENTICATION:
-sf, -secret-file string[] path to config file containing secrets for nuclei authenticated scan
+1 -2
View File
@@ -32,8 +32,7 @@
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">Korean</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">Spanish</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a>
</p>
---
-369
View File
@@ -1,369 +0,0 @@
<h1 align="center">
<br>
<a href="https://nuclei.projectdiscovery.io"><img src="static/nuclei-logo.png" width="200px" alt="Nuclei"></a>
</h1>
<h4 align="center">Escáner de vulnerabilidades rápido y personalizable basado en un sencillo DSL basado en YAML.</h4>
<p align="center">
<img src="https://img.shields.io/github/go-mod/go-version/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/downloads/projectdiscovery/nuclei/total">
<a href="https://github.com/projectdiscovery/nuclei/graphs/contributors"><img src="https://img.shields.io/github/contributors-anon/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/releases/"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/github/issues-raw/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/discussions"><img src="https://img.shields.io/github/discussions/projectdiscovery/nuclei">
<a href="https://discord.gg/projectdiscovery"><img src="https://img.shields.io/discord/695645237418131507.svg?logo=discord"></a>
<a href="https://twitter.com/pdnuclei"><img src="https://img.shields.io/twitter/follow/pdnuclei.svg?logo=twitter"></a>
</p>
<p align="center">
<a href="#how-it-works">Cómo funciona</a> •
<a href="#install-nuclei">Instalación</a> •
<a href="https://docs.projectdiscovery.io/tools/nuclei/">Documentación</a> •
<a href="#credits">Créditos</a> •
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">Preguntas Frecuentes</a> •
<a href="https://discord.gg/projectdiscovery">Únete a Discord</a>
</p>
<p align="center">
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">Korean</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">Spanish</a>
</p>
---
Nuclei se utiliza para enviar peticiones a múltiples objetivos basándose en una plantilla, lo que resulta en cero falsos positivos y proporciona un escaneo rápido en un gran número de hosts. Nuclei ofrece escaneos para una variedad de protocolos, incluyendo TCP, DNS, HTTP, SSL, File, Whois, Websocket, Headless, Code, etc. Con plantillas potentes y flexibles, Nuclei puede utilizarse para modelar todo tipo de comprobaciones de seguridad.
Tenemos un [repositorio dedicado](https://github.com/projectdiscovery/nuclei-templates) que alberga varios tipos de plantillas de vulnerabilidades, contribuidas por **más de 300** investigadores y ingenieros de seguridad.
## Cómo funciona
<h3 align="center">
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
</h3>
| :exclamation: **Descargo de responsabilidad** |
|---------------------------------|
| **Este proyecto está en desarrollo activo**. Es de esperar que se produzcan cambios importantes con las nuevas versiones. Consulte el registro de cambios de la versión antes de actualizar. |
| Este proyecto fue principalmente desarrollado para ser utilizado como una herramienta CLI independiente. **Ejecutar nuclei como un servicio puede suponer riesgos de seguridad.** Se recomienda utilizarlo con precaución y tomar medidas de seguridad adicionales. |
# Instalación de Nuclei
Nuclei requiere **go1.21** para instalarse correctamente. Ejecute el siguiente comando para instalar la última versión -
```sh
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
```
<details>
<summary>Brew</summary>
```sh
brew install nuclei
```
</details>
<details>
<summary>Docker</summary>
```sh
docker pull projectdiscovery/nuclei:latest
```
</details>
**Más métodos de instalación [pueden encontrarse aquí](https://docs.projectdiscovery.io/tools/nuclei/install).**
<table>
<tr>
<td>
### Plantillas de Nuclei
Nuclei cuenta con soporte incorporado para la descarga/actualización automática de plantillas desde la versión [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2) en adelante. El proyecto [**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) proporciona una lista de plantillas listas para usar, aportadas por la comunidad, y que se actualizan constantemente.
También puedes utilizar la bandera `update-templates` para actualizar las plantillas de Nuclei en cualquier momento; puedes escribir tus propias pruebas para tu flujo de trabajo y necesidades individuales siguiendo la [guía de plantillas](https://docs.projectdiscovery.io/templates/) de Nuclei.
La sintaxis de referencia YAML DSL está disponible [aquí](SYNTAX-REFERENCE.md).
</td>
</tr>
</table>
### Uso
```sh
nuclei -h
```
Esto mostrará ayuda sobre la herramienta. Aquí están todas las opciones que soporta.
```console
Nuclei es un escáner de vulnerabilidades rápido y basado en plantillas
que se centra en su amplia configurabilidad, extensibilidad y facilidad de uso.
Usage:
./nuclei [flags]
Flags:
TARGET:
-u, -target string[] URLs/hosts a escanear
-l, -list string ruta al archivo que contiene la lista de URLs/hosts a escanear (uno por línea)
-eh, -exclude-hosts string[] hosts a excluir para escanear de la lista de entrada (ip, cidr, hostname)
-resume string reanudar el escaneo usando resume.cfg (la clusterización quedará inhabilitada)
-sa, -scan-all-ips escanear todas las IP asociadas al registro dns
-iv, -ip-version string[] versión IP a escanear del nombre de host (4,6) - (por defecto 4)
TARGET-FORMAT:
-im, -input-mode string modo del archivo de entrada (list, burp, jsonl, yaml, openapi, swagger) (por defecto "list")
-ro, -required-only utilizar solo campos requeridos en el formato de entrada al generar peticiones
-sfv, -skip-format-validation saltar la validación de formato (como variables faltantes) al procesar el archivo de entrada
TEMPLATES:
-nt, -new-templates ejecutar sólo las nuevas plantillas añadidas en la última versión de nuclei-templates
-ntv, -new-templates-version string[] ejecutar las nuevas plantillas añadidas en la versión especificada
-as, -automatic-scan escaneo web automático utilizando la detección de tecnología de wappalyzer para mapeo de etiquetas
-t, -templates string[] lista de plantillas o directorio de plantillas a ejecutar (separadas por comas, file)
-turl, -template-url string[] url de plantilla o lista que contiene urls de plantillas a ejecutar (separadas por comas, file)
-w, -workflows string[] lista de flujos de trabajo o directorio de flujos de trabajo a ejecutar (separadas por comas, file)
-wurl, -workflow-url string[] url de flujo de trabajo o lista que contiene urls de flujo de trabajo para ejecutar (separadas por comas, file)
-validate valida las plantillas pasadas a nuclei
-nss, -no-strict-syntax deshabilita la comprobación de sintaxis estricta en las plantillas
-td, -template-display muestra el contenido de las plantillas
-tl lista todas las plantillas disponibles
-tgl lista todas las etiquetas disponibles
-sign firma las plantillas con la clave privada definida en la variable de entorno NUCLEI_SIGNATURE_PRIVATE_KEY
-code habilita la carga de plantillas basadas en protocolos de código
-dut, -disable-unsigned-templates deshabilita la ejecución de plantillas no firmadas o plantillas con firma no coincidente
FILTERING:
-a, -author string[] plantillas a ejecutar basadas en autores (separadas por comas, file)
-tags string[] plantillas a ejecutar basadas en etiquetas (separadas por comas, file)
-etags, -exclude-tags string[] plantillas a excluir basadas en etiquetas (separadas por comas, file)
-itags, -include-tags string[] etiquetas a ejecutar incluso si están excluidas ya sea por defecto o por configuración
-id, -template-id string[] plantillas a ejecutar basadas en IDs de plantilla (comma-separated, file, allow-wildcard)
-eid, -exclude-id string[] plantillas a excluir basadas en IDs de plantilla (separadas por comas, file)
-it, -include-templates string[] ruta al archivo de plantilla o directorio a ejecutar incluso si están excluidas ya sea por defecto o por configuración
-et, -exclude-templates string[] ruta al archivo de plantilla o directorio a excluir (separadas por comas, file)
-em, -exclude-matchers string[] matchers de plantilla a excluir en el resultado
-s, -severity value[] plantillas a ejecutar basadas en criticidad. Valores posibles: info, bajo, medio, alto, crítico, desconocido
-es, -exclude-severity value[] plantillas a excluir basadas en criticidad. Valores posibles: info, bajo, medio, alto, crítico, desconocido
-pt, -type value[] plantillas a ejecutar basadas en tipo de protocolo. Valores posibles: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
-ept, -exclude-type value[] plantillas a excluir basadas en tipo de protocolo. Valores posibles: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
-tc, -template-condition string[] plantillas a ejecutar basadas en condición de expresión
OUTPUT:
-o, -output string archivo de salida donde guardar las incidencias/vulnerabilidades detectadas
-sresp, -store-resp almacenar todas las peticiones/respuestas enviadas por nuclei en el directorio de salida
-srd, -store-resp-dir string almacenar todas las peticiones/respuestas enviadas por nuclei en un directorio personalizado (por defecto "output")
-silent mostrar resultados únicamente
-nc, -no-color deshabilitar la coloración del contenido de salida (códigos de escape ANSI)
-j, -jsonl escribir la salida en formato JSONL(ines)
-irr, -include-rr -omit-raw incluir pares peticiones/respuesta en las salidas JSON, JSONL y Markdown (sólo para hallazgos) [OBSOLETO usar -omit-raw] (por defecto true)
-or, -omit-raw omitir los pares peticiones/respuesta en las salidas JSON, JSONL y Markdown (sólo para hallazgos)
-ot, -omit-template omitir plantilla codificada en la salida JSON, JSONL
-nm, -no-meta deshabilitar la impresión de metadatos de resultados en la salida cli
-ts, -timestamp habilitar la impresión de la marca de tiempo en la salida cli
-rdb, -report-db string base de datos de informes de nuclei (utilizarla siempre para persistir los datos de los informes)
-ms, -matcher-status mostrar el estado de fallo de coincidencia
-me, -markdown-export string directorio para exportar resultados en formato markdown
-se, -sarif-export string archivo para exportar resultados en formato SARIF
-je, -json-export string archivo para exportar resultados en formato JSON
-jle, -jsonl-export string archivo para exportar resultados en formato JSONL(ines)
CONFIGURATIONS:
-config string ruta al archivo de configuración de nuclei
-fr, -follow-redirects habilitar el seguimiento de redirecciones para plantillas http
-fhr, -follow-host-redirects seguir redirecciones en el mismo host
-mr, -max-redirects int número máximo de redirecciones a seguir para plantillas http (por defecto 10)
-dr, -disable-redirects deshabilitar redirecciones para plantillas http
-rc, -report-config string archivo de configuración del módulo de informes de nuclei
-H, -header string[] encabezado/cookie personalizado a incluir en todas las peticiones http en formato header:value (cli, file)
-V, -var value variables personalizadas en formato key=value
-r, -resolvers string archivo que contiene lista de resolutores para nuclei
-sr, -system-resolvers utilizar resolución de DNS del sistema como fallback de error
-dc, -disable-clustering deshabilitar la clusterización de peticiones
-passive habilitar el modo de procesamiento pasivo de respuestas HTTP
-fh2, -force-http2 forzar la conexión http2 en las peticiones
-ev, -env-vars habilitar el uso de variables de entorno en la plantilla
-cc, -client-cert string archivo de certificado de cliente (codificado en PEM) utilizado para autenticarse contra los hosts escaneados
-ck, -client-key string archivo de clave de cliente (codificado en PEM) utilizado para autenticarse contra los hosts escaneados
-ca, -client-ca string archivo de autoridad de certificación de cliente (codificado en PEM) utilizado para autenticarse contra los hosts escaneados
-sml, -show-match-line mostrar líneas de coincidencia para plantillas de archivo, funciona solo con extractores
-ztls utilizar la biblioteca ztls con autofallback a estándar para tls13 [Obsoleto] autofallback a ztls está habilitado por defecto
-sni string nombre de host tls sni a usar (por defecto: nombre de dominio de entrada)
-dt, -dialer-timeout value tiempo de espera para peticiones de red
-dka, -dialer-keep-alive value duración de keep-alive para peticiones de red
-lfa, -allow-local-file-access permite el acceso a archivos (carga útil) en cualquier lugar del sistema
-lna, -restrict-local-network-access bloquea conexiones a la red local / privada
-i, -interface string interfaz de red a usar para el escaneo de red
-at, -attack-type string tipo de combinaciones de carga útil a realizar (batteringram, pitchfork, clusterbomb)
-sip, -source-ip string dirección ip de origen a usar para el escaneo de red
-rsr, -response-size-read int tamaño máximo de respuesta a leer en bytes (por defecto 10485760)
-rss, -response-size-save int tamaño máximo de respuesta a guardar en bytes (por defecto 1048576)
-reset reset elimina todos los archivos de configuración y datos de nuclei (incluidas las nuclei-templates)
-tlsi, -tls-impersonate habilitar client hello (ja3) tls randomization experimental
INTERACTSH:
-iserver, -interactsh-server string url del servidor interactsh para instancia autoalojada (por defecto: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
-itoken, -interactsh-token string token de autenticación del servidor interactsh autoalojado
-interactions-cache-size int número de peticiones a mantener en la caché de interacciones (por defecto 5000)
-interactions-eviction int número de segundos a esperar antes de eliminar las solicitudes de la caché (por defecto 60)
-interactions-poll-duration int número de segundos a esperar antes de cada solicitud de polling de interacciones (por defecto 5)
-interactions-cooldown-period int tiempo adicional para el polling de interacciones antes de salir (por defecto 5)
-ni, -no-interactsh desactivar el servidor interactsh para pruebas OAST, excluir plantillas basadas en OAST
FUZZING:
-ft, -fuzzing-type string sobrescribe el tipo de fuzzing establecido en la plantilla (replace, prefix, postfix, infix)
-fm, -fuzzing-mode string sobrescribe el modo de fuzzing establecido en la plantilla (multiple, single)
-fuzz habilita la carga de plantillas de fuzzing (Obsoleto: usar -dast en su lugar)
-dast solo ejecuta plantillas DAST
UNCOVER:
-uc, -uncover habilita el motor uncover
-uq, -uncover-query string[] consulta de búsqueda uncover
-ue, -uncover-engine string[] motor de búsqueda uncover (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow) (por defecto shodan)
-uf, -uncover-field string campos uncover a devolver (ip,port,host) (por defecto "ip:port")
-ul, -uncover-limit int resultados uncover a devolver (por defecto 100)
-ur, -uncover-ratelimit int sobrescribe el límite de velocidad de los motores con el límite de velocidad del motor uncover (por defecto 60 req/min) (por defecto 60)
RATE-LIMIT:
-rl, -rate-limit int número máximo de peticiones a enviar por segundo (por defecto 150)
-rlm, -rate-limit-minute int número máximo de peticiones a enviar por minuto
-bs, -bulk-size int número máximo de hosts a ser analizados en paralelo por plantilla (por defecto 25)
-c, -concurrency int número máximo de plantillas a ejecutar en paralelo (por defecto 25)
-hbs, -headless-bulk-size int número máximo de hosts headless a ser analizados en paralelo por plantilla (por defecto 10)
-headc, -headless-concurrency int número máximo de plantillas headless a ejecutar en paralelo (por defecto 10)
-jsc, -js-concurrency int número máximo de entornos de ejecución de JavaScript a ejecutar en paralelo (por defecto 120)
-pc, -payload-concurrency int concurrencia máxima de carga útil para cada plantilla (por defecto 25)
OPTIMIZATIONS:
-timeout int tiempo de espera en segundos (por defecto 10)
-retries int número de veces que se reintenta una petición fallida (por defecto 1)
-ldp, -leave-default-ports dejar puertos HTTP/HTTPS predeterminados (por ejemplo, host:80,host:443)
-mhe, -max-host-error int errores máximos para un host antes de omitirlo del escaneo (por defecto 30)
-te, -track-error string[] agrega el error dado a la lista de seguimiento de errores máximos por host (standard, file)
-nmhe, -no-mhe deshabilita la omisión del host del escaneo basado en errores
-project utiliza una carpeta de proyecto para evitar enviar la misma petición varias veces
-project-path string establece una ruta de proyecto específica (por defecto "/tmp")
-spm, -stop-at-first-match detiene el procesamiento de las peticiones HTTP después de la primera coincidencia (puede romper la lógica de la plantilla/flujo de trabajo)
-stream modo transmisión - comienza a trabajar sin ordenar la entrada
-ss, -scan-strategy value estrategia a utilizar mientras se escanea (auto/host-spray/template-spray) (por defecto auto)
-irt, -input-read-timeout value tiempo de espera en la lectura de entrada (por defecto 3m0s)
-nh, -no-httpx deshabilita análisis httpx para entradas que no son URL
-no-stdin deshabilita el procesamiento de la entrada estándar
HEADLESS:
-headless habilita las plantillas que requieren soporte de navegadores sin interfaz gráfica (headless browser) (el usuario root en Linux deshabilitará el sandbox)
-page-timeout int segundos para esperar cada página en modo sin interfaz (por defecto 20)
-sb, -show-browser muestra el navegador en la pantalla al ejecutar plantillas con modo sin interfaz
-ho, -headless-options string[] inicia Chrome en modo sin interfaz con opciones adicionales
-sc, -system-chrome utiliza el navegador Chrome instalado localmente en lugar del instalado por nuclei
-lha, -list-headless-action lista de acciones sin interfaz disponibles
DEBUG:
-debug muestra todas las peticiones y respuestas
-dreq, -debug-req muestra todas las peticiones enviadas
-dresp, -debug-resp muestra todas las respuestas recibidas
-p, -proxy string[] lista de proxies http/socks5 a utilizar (separados por comas o archivo de entrada)
-pi, -proxy-internal proxy para todas las peticiones internas
-ldf, -list-dsl-function lista todas las firmas de función DSL admitidas
-tlog, -trace-log string archivo a escribir el registro de traza de peticiones enviadas
-elog, -error-log string archivo a escribir el registro de error de peticiones enviadas
-version muestra la versión de nuclei
-hm, -hang-monitor habilita la monitorización de bloqueos de nuclei
-v, -verbose muestra salida detallada
-profile-mem string archivo opcional de volcado de memoria de nuclei
-vv muestra las plantillas cargadas para el escaneo
-svd, -show-var-dump muestra el volcado de variables para depuración
-ep, -enable-pprof habilita el servidor de depuración pprof
-tv, -templates-version muestra la versión de las plantillas nuclei (nuclei-templates) instaladas
-hc, -health-check ejecuta comprobación de diagnóstico
UPDATE:
-up, -update actualiza el motor de nuclei a la última versión lanzada
-ut, -update-templates actualiza nuclei-templates a la última versión lanzada
-ud, -update-template-dir string directorio personalizado para instalar/actualizar nuclei-templates
-duc, -disable-update-check deshabilita la comprobación automática de actualizaciones de nuclei/templates
STATISTICS:
-stats muestra estadísticas sobre el escaneo en ejecución
-sj, -stats-json muestra estadísticas en formato JSONL(ines)
-si, -stats-interval int número de segundos a esperar entre mostrar una actualización de estadísticas (por defecto 5)
-mp, -metrics-port int puerto para exponer métricas de nuclei (por defecto 9092)
CLOUD:
-auth configura la clave de API del cloud de projectdiscovery (pdcp)
-cup, -cloud-upload sube los resultados del escaneo al dashboard de pdcp
-sid, -scan-id string sube los resultados del escaneo al ID de escaneo dado
AUTHENTICATION:
-sf, -secret-file string[] ruta al archivo de configuración que contiene los secrets para el escaneo autenticado de nuclei
-ps, -prefetch-secrets precarga los secrets del archivo de secrets
EXAMPLES:
Ejecutar nuclei en un solo host:
$ nuclei -target example.com
Ejecutar nuclei con directorios de plantillas específicos:
$ nuclei -target example.com -t http/cves/ -t ssl
Ejecutar nuclei contra una lista de hosts:
$ nuclei -list hosts.txt
Ejecutar nuclei con una salida JSON:
$ nuclei -target example.com -json-export output.json
Ejecutar nuclei con salidas Markdown ordenadas (con variables de entorno):
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
Documentación adicional disponible en: https://docs.nuclei.sh/getting-started/running
```
### Ejecutando Nuclei
Consulta https://docs.projectdiscovery.io/tools/nuclei/running para obtener detalles sobre cómo ejecutar Nuclei.
### Uso de Nuclei desde código Go
La guía completa sobre cómo usar Nuclei como biblioteca/SDK está disponible en [godoc](https://pkg.go.dev/github.com/projectdiscovery/nuclei/v3/lib#section-readme).
### Recursos
Puedes acceder a la documentación principal de Nuclei en https://docs.projectdiscovery.io/tools/nuclei/, y obtener más información sobre Nuclei en la nube con [ProjectDiscovery Cloud Platform](https://cloud.projectdiscovery.io).
¡Consulta https://docs.projectdiscovery.io/tools/nuclei/resources para obtener más recursos y videos sobre Nuclei!
### Créditos
Gracias a todos los increíbles [contribuyentes de la comunidad que enviaron PRs](https://github.com/projectdiscovery/nuclei/graphs/contributors) y mantienen este proyecto actualizado. :heart:
Si tienes una idea o algún tipo de mejora, eres bienvenido a contribuir y participar en el Proyecto, siéntete libre de enviar tu PR.
<p align="center">
<a href="https://github.com/projectdiscovery/nuclei/graphs/contributors">
<img src="https://contrib.rocks/image?repo=projectdiscovery/nuclei&max=500">
</a>
</p>
También echa un vistazo a los siguientes proyectos de código abierto similares que pueden adaptarse a tu flujo de trabajo:
[FFuF](https://github.com/ffuf/ffuf), [Qsfuzz](https://github.com/ameenmaali/qsfuzz), [Inception](https://github.com/proabiral/inception), [Snallygaster](https://github.com/hannob/snallygaster), [Gofingerprint](https://github.com/Static-Flow/gofingerprint), [Sn1per](https://github.com/1N3/Sn1per/tree/master/templates), [Google tsunami](https://github.com/google/tsunami-security-scanner), [Jaeles](https://github.com/jaeles-project/jaeles), [ChopChop](https://github.com/michelin/ChopChop)
### Licencia
Nuclei se distribuye bajo la [Licencia MIT](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md)
<h1 align="left">
<a href="https://discord.gg/projectdiscovery"><img src="static/Join-Discord.png" width="380" alt="Join Discord"></a> <a href="https://docs.projectdiscovery.io"><img src="static/check-nuclei-documentation.png" width="380" alt="Check Nuclei Documentation"></a>
</h1>
+1 -2
View File
@@ -32,8 +32,7 @@
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">Korean</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">Spanish</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a>
</p>
---
-172
View File
@@ -1,172 +0,0 @@
<h1 align="center">
<br>
<a href="https://nuclei.projectdiscovery.io"><img src="static/nuclei-logo.png" width="200px" alt="Nuclei"></a>
</h1>
<h4 align="center">シンプルなYAMLベースのDSLに基づいた高速でカスタマイズ可能な脆弱性スキャナー</h4>
<p align="center">
<img src="https://img.shields.io/github/go-mod/go-version/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/downloads/projectdiscovery/nuclei/total">
<a href="https://github.com/projectdiscovery/nuclei/graphs/contributors"><img src="https://img.shields.io/github/contributors-anon/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/releases/"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/github/issues-raw/projectdiscovery/nuclei">
<a href="https://github.com/projectdiscovery/nuclei/discussions"><img src="https://img.shields.io/github/discussions/projectdiscovery/nuclei">
<a href="https://discord.gg/projectdiscovery"><img src="https://img.shields.io/discord/695645237418131507.svg?logo=discord"></a>
<a href="https://twitter.com/pdnuclei"><img src="https://img.shields.io/twitter/follow/pdnuclei.svg?logo=twitter"></a>
</p>
<p align="center">
<a href="#how-it-works">動作原理</a> •
<a href="#install-nuclei">インストール</a> •
<a href="https://docs.projectdiscovery.io/tools/nuclei/">ドキュメント</a> •
<a href="#credits">クレジット</a> •
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">FAQ</a> •
<a href="https://discord.gg/projectdiscovery">Discordに参加</a>
</p>
<p align="center">
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">英語</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中国語</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">韓国語</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">インドネシア語</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">スペイン語</a>
</p>
---
Nucleiは、テンプレートに基づいてターゲット間でリクエストを送信するために使用され、偽陽性がゼロであり、多数のホストで高速なスキャンを提供します。Nucleiは、TCP、DNS、HTTP、SSL、ファイル、Whois、Websocket、Headless、Codeなど、さまざまなプロトコルのスキャンを提供します。強力で柔軟なテンプレートを使用して、Nucleiはすべての種類のセキュリティチェックをモデル化するために使用できます。
**300人以上の** セキュリティ研究者およびエンジニアが提供するさまざまなタイプの脆弱性テンプレートを収容する[専用リポジトリ](https://github.com/projectdiscovery/nuclei-templates)を持っています。
## 動作原理
<h3 align="center">
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
</h3>
| :exclamation: **免責事項** |
|---------------------------------|
| **このプロジェクトは積極的に開発されています**。リリースによって重大な変更が発生することがあります。更新する前にリリースの変更ログを確認してください。 |
| このプロジェクトは主にスタンドアロンのCLIツールとして使用されることを目的として構築されました。**Nucleiをサービスとして実行すると、セキュリティリスクが生じる可能性があります。**注意して使用し、追加のセキュリティ対策を講じることをお勧めします。 |
# Nucleiのインストール
Nucleiを正常にインストールするには、**go1.21**が必要です。以下のコマンドを実行して最新バージョンをインストールしてください -
```sh
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
```
<details>
<summary>Brew</summary>
```sh
brew install nuclei
```
</details>
<details>
<summary>Docker</summary>
```sh
docker pull projectdiscovery/nuclei:latest
```
</details>
**より多くのインストール方法は[こちら](https://docs.projectdiscovery.io/tools/nuclei/install)で見つけることができます。**
<table>
<tr>
<td>
### Nucleiテンプレート
Nucleiは、バージョン[v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2)以降、デフォルトでテンプレートの自動ダウンロード/更新をサポートしています。[**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates)プロジェクトは、常に更新されるコミュニティ提供の即時使用可能なテンプレートのリストを提供します。
`update-templates`フラグを使用して、いつでもNucleiテンプレートを更新することができます。Nucleiの[テンプレートガイド](https://docs.projectdiscovery.io/templates/)に従って、個々のワークフローとニーズに合わせた独自のチェックを作成することができます。
YAML DSLの構文リファレンスは[こちら](SYNTAX-REFERENCE.md)で確認できます。
</td>
</tr>
</table>
### 使用方法
```sh
nuclei -h
```
これにより、ツールのヘルプが表示されます。ここには、サポートされているすべてのスイッチがあります。
```console
Nucleiは、広範な設定可能性、大規模な拡張性、および使いやすさに焦点を当てた、
高速でテンプレートベースの脆弱性スキャナーです。
使用法:
./nuclei [flags]
フラグ:
ターゲット:
-u, -target string[] スキャンする対象のURL/ホスト
-l, -list string スキャンする対象のURL/ホストのリストが含まれているファイルへのパス(1行に1つ)
-resume string resume.cfgを使用してスキャンを再開(クラスタリングは無効になります)
-sa, -scan-all-ips DNSレコードに関連付けられているすべてのIPをスキャン
-iv, -ip-version string[] ホスト名のスキャンするIPバージョン(4,6)-(デフォルトは4)
テンプレート:
-nt, -new-templates 最新のnuclei-templatesリリースに追加された新しいテンプレートのみを実行
-ntv, -new-templates-version string[] 特定のバージョンに追加された新しいテンプレートを実行
-as, -automatic-scan wappalyzer技術検出をタグマッピングに使用した自動Webスキャン
-t, -templates string[] 実行するテンプレートまたはテンプレートディレクトリのリスト(カンマ区切り、ファイル)
-turl, -template-url string[] 実行するテンプレートのURLまたはテンプレートURLのリスト(カンマ区切り、ファイル)
-w, -workflows string[] 実行するワークフローまたはワークフローディレクトリのリスト(カンマ区切り、ファイル)
-wurl, -workflow-url string[] 実行するワークフローのURLまたはワークフローURLのリスト(カンマ区切り、ファイル)
-validate Nucleiに渡されたテンプレートを検証
-nss, -no-strict-syntax テンプレートで厳密な構文チェックを無効にする
-td, -template-display テンプレートの内容を表示
-tl 利用可能なすべてのテンプレートをリスト
-sign NUCLEI_SIGNATURE_PRIVATE_KEY環境変数で定義された秘密鍵でテンプレートに署名
-code コードプロトコルベースのテンプレートのロードを有効にする
フィルタリング:
-a, -author string[] 作者に基づいて実行するテンプレート(カンマ区切り、ファイル)
-tags string[] タグに基づいて実行するテンプレート(カンマ区切り、ファイル)
-etags, -exclude-tags string[] タグに基づいて除外するテンプレート(カンマ区切り、ファイル)
-itags, -include-tags string[] デフォルトまたは設定によって除外されている場合でも実行する必要があるタグ
-id, -template-id string[] テンプレートIDに基づいて実行するテンプレート(カンマ区切り、ファイル)
-eid, -exclude-id string[] テンプレートIDに基づいて除外するテンプレート(カンマ区切り、ファイル)
-it, -include-templates string[] デフォルトまたは設定によって除外されている場合でも実行する必要があるテンプレート
-et, -exclude-templates string[] 除外するテンプレートまたはテンプレートディレクトリへのパス(カンマ区切り、ファイル)
-em, -exclude-matchers string[] 結果で除外するテンプレートマッチャー
-s, -severity value[] 重大度に基づいて実行するテンプレート。可能な値:info, low, medium, high, critical, unknown
-es, -exclude-severity value[] 重大度に基づいて除外するテンプレート。可能な値:info, low, medium, high, critical, unknown
-pt, -type value[] プロトコルタイプに基づいて実行するテンプレート。可能な値:dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
-ept, -exclude-type value[] プロトコルタイプに基づいて除外するテンプレート。可能な値:dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
-tc, -template-condition string[] 式条件に基づいて実行するテンプレート
出力:
-o, -output string 発見された問題/脆弱性を書き込む出力ファイル
-sresp, -store-resp Nucleiを通じて渡されたすべてのリクエスト/レスポンスを出力ディレクトリに保存
-srd, -store-resp-dir string Nucleiを通じて渡されたすべてのリクエスト/レスポンスをカスタムディレクトリに保存(デフォルトは「output」)
-silent 結果のみを表示
-nc, -no-color 出力内容の着色を無効にする(ANSIエスケープコード)
-j, -jsonl JSONL(ines)形式で出力を書き込む
-irr, -include-rr -omit-raw JSON、JSONL、Markdown出力にリクエスト/レスポンスペアを含める(発見のみ)[非推奨 -omit-raw使用](デフォルトはtrue)
-or, -omit-raw JSON、JSONL、Markdown出力でリクエスト/レスポンスペアを省略する(発見のみ)
-ot, -omit-template JSON、JSONL出力でエンコードされたテンプレートを省略
-nm, -no-meta CLI出力で結果のメタデータの印刷を無効にする
-ts, -timestamp CLI出力にタイムスタンプを印刷することを有効にする
-rdb, -report-db string Nucleiレポートデータベース(レポートデータを永続化するために常にこれを使用)
-ms, -matcher-status マッチ失敗のステータスを表示
-me, -markdown-export string Markdown形式で結果をエクスポートするディレクトリ
-se, -sarif-export string SARIF形式で結果をエクスポートするファイル
-je, -json-export string JSON形式で結果をエクスポートするファイル
-jle, -jsonl-export string JSONL(ine)形式で結果をエクスポートするファイル
設定:
-config string Nucleiの設定ファイルへのパス
-fr, -follow-redirects HTTPテンプレートのリダイレクトをフォローすることを有効にする
-fhr, -follow-host-redirects
+1 -2
View File
@@ -30,8 +30,7 @@
<p align="center">
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">한국어</a> •
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">스페인어</a>
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">한국어</a>
</p>
---
+14 -51
View File
@@ -1404,19 +1404,6 @@ Valid values:
<div class="dd">
<code>skip-secret-file</code> <i>bool</i>
</div>
<div class="dt">
SkipSecretFile skips the authentication or authorization configured in the secret file.
</div>
<hr />
<div class="dd">
<code>cookie-reuse</code> <i>bool</i>
</div>
@@ -1813,50 +1800,13 @@ Valid values:
Part is the part of request to fuzz.
Valid values:
- <code>query</code>
- <code>header</code>
- <code>path</code>
- <code>body</code>
- <code>cookie</code>
- <code>request</code>
</div>
<hr />
<div class="dd">
<code>parts</code> <i>[]string</i>
</div>
<div class="dt">
Parts is the list of parts to fuzz. If multiple parts need to be
defined while excluding some, this should be used instead of singular part.
query fuzzes the query part of url. More parts will be added later.
Valid values:
- <code>query</code>
- <code>header</code>
- <code>path</code>
- <code>body</code>
- <code>cookie</code>
- <code>request</code>
</div>
<hr />
@@ -4352,6 +4302,19 @@ Code contains code to execute for the javascript request.
<div class="dd">
<code>timeout</code> <i>int</i>
</div>
<div class="dt">
Timeout in seconds is optional timeout for each javascript script execution (i.e init, pre-condition, code)
</div>
<hr />
<div class="dd">
<code>stop-at-first-match</code> <i>bool</i>
</div>
-27
View File
@@ -18,7 +18,6 @@ const (
var fuzzingTestCases = []TestCaseInfo{
{Path: "fuzz/fuzz-mode.yaml", TestCase: &fuzzModeOverride{}},
{Path: "fuzz/fuzz-multi-mode.yaml", TestCase: &fuzzMultipleMode{}},
{Path: "fuzz/fuzz-type.yaml", TestCase: &fuzzTypeOverride{}},
{Path: "fuzz/fuzz-query.yaml", TestCase: &httpFuzzQuery{}},
{Path: "fuzz/fuzz-headless.yaml", TestCase: &HeadlessFuzzingQuery{}},
@@ -175,29 +174,3 @@ func (h *HeadlessFuzzingQuery) Execute(filePath string) error {
}
return expectResultsCount(got, 2)
}
type fuzzMultipleMode struct{}
// Execute executes a test case and returns an error if occurred
func (h *fuzzMultipleMode) Execute(filePath string) error {
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
xClientId := r.Header.Get("X-Client-Id")
xSecretId := r.Header.Get("X-Secret-Id")
if xClientId != "nuclei-v3" || xSecretId != "nuclei-v3" {
w.WriteHeader(http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "text/html")
resp := fmt.Sprintf("<html><body><h1>This is multi-mode fuzzing test: %v <h1></body></html>", xClientId)
fmt.Fprint(w, resp)
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?url=https://scanme.sh", debug, "-jsonl", "-fuzz")
if err != nil {
return err
}
return expectResultsCount(got, 1)
}
+1 -2
View File
@@ -23,7 +23,6 @@ import (
logutil "github.com/projectdiscovery/utils/log"
sliceutil "github.com/projectdiscovery/utils/slice"
stringsutil "github.com/projectdiscovery/utils/strings"
unitutils "github.com/projectdiscovery/utils/unit"
)
var httpTestcases = []TestCaseInfo{
@@ -510,7 +509,7 @@ func (h *httpPostMultipartBody) Execute(filePath string) error {
var routerErr error
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
if err := r.ParseMultipartForm(unitutils.Mega); err != nil {
if err := r.ParseMultipartForm(1 * 1024); err != nil {
routerErr = err
return
}
-1
View File
@@ -37,7 +37,6 @@ var (
"dns": dnsTestCases,
"workflow": workflowTestcases,
"loader": loaderTestcases,
"profile-loader": profileLoaderTestcases,
"websocket": websocketTestCases,
"headless": headlessTestcases,
"whois": whoisTestCases,
+1 -1
View File
@@ -128,7 +128,7 @@ func executeNucleiAsLibrary(templatePath, templateURL string) ([]string, error)
}
store.Load()
_ = engine.Execute(context.Background(), store.Templates(), provider.NewSimpleInputProviderWithUrls(templateURL))
_ = engine.Execute(store.Templates(), provider.NewSimpleInputProviderWithUrls(templateURL))
engine.WorkPool().Wait() // Wait for the scan to finish
return results, nil
+2 -16
View File
@@ -172,14 +172,7 @@ func (h *nonExistentTemplateList) Execute(nonExistingTemplateList string) error
ts := httptest.NewServer(router)
defer ts.Close()
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
if err != nil {
return err
}
defer os.Remove("test-config.yaml")
_, err = testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-template-url", ts.URL+"/404", "-config", "test-config.yaml")
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-template-url", ts.URL+"/404")
if err == nil {
return fmt.Errorf("expected error for nonexisting workflow url")
}
@@ -195,14 +188,7 @@ func (h *nonExistentWorkflowList) Execute(nonExistingWorkflowList string) error
ts := httptest.NewServer(router)
defer ts.Close()
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
if err != nil {
return err
}
defer os.Remove("test-config.yaml")
_, err = testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-workflow-url", ts.URL+"/404", "-config", "test-config.yaml")
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-workflow-url", ts.URL+"/404")
if err == nil {
return fmt.Errorf("expected error for nonexisting workflow url")
}
-54
View File
@@ -1,54 +0,0 @@
package main
import (
"fmt"
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
errorutil "github.com/projectdiscovery/utils/errors"
)
var profileLoaderTestcases = []TestCaseInfo{
{Path: "profile-loader/load-with-filename", TestCase: &profileLoaderByRelFile{}},
{Path: "profile-loader/load-with-id", TestCase: &profileLoaderById{}},
{Path: "profile-loader/basic.yml", TestCase: &customProfileLoader{}},
}
type profileLoaderByRelFile struct{}
func (h *profileLoaderByRelFile) Execute(testName string) error {
results, err := testutils.RunNucleiWithArgsAndGetResults(false, "-tl", "-tp", "cloud.yml")
if err != nil {
return errorutil.NewWithErr(err).Msgf("failed to load template with id")
}
if len(results) <= 10 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 10, len(results))
}
return nil
}
type profileLoaderById struct{}
func (h *profileLoaderById) Execute(testName string) error {
results, err := testutils.RunNucleiWithArgsAndGetResults(false, "-tl", "-tp", "cloud")
if err != nil {
return errorutil.NewWithErr(err).Msgf("failed to load template with id")
}
if len(results) <= 10 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 10, len(results))
}
return nil
}
// this profile with load kevs
type customProfileLoader struct{}
func (h *customProfileLoader) Execute(filepath string) error {
results, err := testutils.RunNucleiWithArgsAndGetResults(false, "-tl", "-tp", filepath)
if err != nil {
return errorutil.NewWithErr(err).Msgf("failed to load template with id")
}
if len(results) < 1 {
return fmt.Errorf("incorrect result: expected more results than %d, got %v", 1, len(results))
}
return nil
}
-21
View File
@@ -13,7 +13,6 @@ var sslTestcases = []TestCaseInfo{
{Path: "protocols/ssl/custom-cipher.yaml", TestCase: &sslCustomCipher{}},
{Path: "protocols/ssl/custom-version.yaml", TestCase: &sslCustomVersion{}},
{Path: "protocols/ssl/ssl-with-vars.yaml", TestCase: &sslWithVars{}},
{Path: "protocols/ssl/multi-req.yaml", TestCase: &sslMultiReq{}},
}
type sslBasic struct{}
@@ -119,23 +118,3 @@ func (h *sslWithVars) Execute(filePath string) error {
return expectResultsCount(results, 1)
}
type sslMultiReq struct{}
func (h *sslMultiReq) Execute(filePath string) error {
ts := testutils.NewTCPServer(&tls.Config{}, defaultStaticPort, func(conn net.Conn) {
defer conn.Close()
data := make([]byte, 4)
if _, err := conn.Read(data); err != nil {
return
}
})
defer ts.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-V")
if err != nil {
return err
}
return expectResultsCount(results, 2)
}
+14 -73
View File
@@ -12,7 +12,6 @@ import (
"strings"
"time"
_pdcp "github.com/projectdiscovery/nuclei/v3/internal/pdcp"
"github.com/projectdiscovery/utils/auth/pdcp"
"github.com/projectdiscovery/utils/env"
_ "github.com/projectdiscovery/utils/pprof"
@@ -39,15 +38,13 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/utils/monitor"
errorutil "github.com/projectdiscovery/utils/errors"
fileutil "github.com/projectdiscovery/utils/file"
unitutils "github.com/projectdiscovery/utils/unit"
updateutils "github.com/projectdiscovery/utils/update"
)
var (
cfgFile string
templateProfile string
memProfile string // optional profile file path
options = &types.Options{}
cfgFile string
memProfile string // optional profile file path
options = &types.Options{}
)
func main() {
@@ -143,10 +140,7 @@ func main() {
nucleiRunner.Close()
gologger.Info().Msgf("Creating resume file: %s\n", resumeFileName)
err := nucleiRunner.SaveResumeConfig(resumeFileName)
if err != nil {
return errorutil.NewWithErr(err).Msgf("couldn't create crash resume file")
}
return nil
return errorutil.NewWithErr(err).Msgf("couldn't create crash resume file")
})
}
@@ -205,7 +199,7 @@ on extensive configurability, massive extensibility and ease of use.`)
*/
flagSet.CreateGroup("input", "Target",
flagSet.StringSliceVarP(&options.Targets, "target", "u", nil, "target URLs/hosts to scan", goflags.CommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.Targets, "target", "u", nil, "target URLs/hosts to scan", goflags.StringSliceOptions),
flagSet.StringVarP(&options.TargetsFilePath, "list", "l", "", "path to file containing a list of target URLs/hosts to scan (one per line)"),
flagSet.StringSliceVarP(&options.ExcludeTargets, "exclude-hosts", "eh", nil, "hosts to exclude to scan from the input list (ip, cidr, hostname)", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringVar(&options.Resume, "resume", "", "resume scan using resume.cfg (clustering will be disabled)"),
@@ -231,7 +225,6 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.NoStrictSyntax, "no-strict-syntax", "nss", false, "disable strict syntax check on templates"),
flagSet.BoolVarP(&options.TemplateDisplay, "template-display", "td", false, "displays the templates content"),
flagSet.BoolVar(&options.TemplateList, "tl", false, "list all available templates"),
flagSet.BoolVar(&options.TagList, "tgl", false, "list all available tags"),
flagSet.StringSliceVarConfigOnly(&options.RemoteTemplateDomainList, "remote-template-domain", []string{"cloud.projectdiscovery.io"}, "allowed domain list to load remote templates from"),
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"),
@@ -273,13 +266,10 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.SarifExport, "sarif-export", "se", "", "file to export results in SARIF format"),
flagSet.StringVarP(&options.JSONExport, "json-export", "je", "", "file to export results in JSON format"),
flagSet.StringVarP(&options.JSONLExport, "jsonl-export", "jle", "", "file to export results in JSONL(ine) format"),
flagSet.StringSliceVarP(&options.Redact, "redact", "rd", nil, "redact given list of keys from query parameter, request header and body", goflags.CommaSeparatedStringSliceOptions),
)
flagSet.CreateGroup("configs", "Configurations",
flagSet.StringVar(&cfgFile, "config", "", "path to the nuclei configuration file"),
flagSet.StringVarP(&templateProfile, "profile", "tp", "", "template profile config file to run"),
flagSet.BoolVarP(&options.ListTemplateProfiles, "profile-list", "tpl", false, "list community template profiles"),
flagSet.BoolVarP(&options.FollowRedirects, "follow-redirects", "fr", false, "enable following redirects for http templates"),
flagSet.BoolVarP(&options.FollowHostRedirects, "follow-host-redirects", "fhr", false, "follow redirects on the same host"),
flagSet.IntVarP(&options.MaxRedirects, "max-redirects", "mr", 10, "max number of redirects to follow for http templates"),
@@ -299,17 +289,17 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.ShowMatchLine, "show-match-line", "sml", false, "show match lines for file templates, works with extractors only"),
flagSet.BoolVar(&options.ZTLS, "ztls", false, "use ztls library with autofallback to standard one for tls13 [Deprecated] autofallback to ztls is enabled by default"), //nolint:all
flagSet.StringVar(&options.SNI, "sni", "", "tls sni hostname to use (default: input domain name)"),
flagSet.DurationVarP(&options.DialerTimeout, "dialer-timeout", "dt", 0, "timeout for network requests."),
flagSet.DurationVarP(&options.DialerKeepAlive, "dialer-keep-alive", "dka", 0, "keep-alive duration for network requests."),
flagSet.BoolVarP(&options.AllowLocalFileAccess, "allow-local-file-access", "lfa", false, "allows file (payload) access anywhere on the system"),
flagSet.BoolVarP(&options.RestrictLocalNetworkAccess, "restrict-local-network-access", "lna", false, "blocks connections to the local / private network"),
flagSet.StringVarP(&options.Interface, "interface", "i", "", "network interface to use for network scan"),
flagSet.StringVarP(&options.AttackType, "attack-type", "at", "", "type of payload combinations to perform (batteringram,pitchfork,clusterbomb)"),
flagSet.StringVarP(&options.SourceIP, "source-ip", "sip", "", "source ip address to use for network scan"),
flagSet.IntVarP(&options.ResponseReadSize, "response-size-read", "rsr", 0, "max response size to read in bytes"),
flagSet.IntVarP(&options.ResponseSaveSize, "response-size-save", "rss", unitutils.Mega, "max response size to read in bytes"),
flagSet.IntVarP(&options.ResponseReadSize, "response-size-read", "rsr", 10*1024*1024, "max response size to read in bytes"),
flagSet.IntVarP(&options.ResponseSaveSize, "response-size-save", "rss", 1*1024*1024, "max response size to read in bytes"),
flagSet.CallbackVar(resetCallback, "reset", "reset removes all nuclei configuration and data files (including nuclei-templates)"),
flagSet.BoolVarP(&options.TlsImpersonate, "tls-impersonate", "tlsi", false, "enable experimental client hello (ja3) tls randomization"),
flagSet.StringVarP(&options.HttpApiEndpoint, "http-api-endpoint", "hae", "", "experimental http api endpoint"),
)
flagSet.CreateGroup("interactsh", "interactsh",
@@ -327,9 +317,6 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.FuzzingMode, "fuzzing-mode", "fm", "", "overrides fuzzing mode set in template (multiple, single)"),
flagSet.BoolVar(&fuzzFlag, "fuzz", false, "enable loading fuzzing templates (Deprecated: use -dast instead)"),
flagSet.BoolVar(&options.DAST, "dast", false, "enable / run dast (fuzz) nuclei templates"),
flagSet.BoolVarP(&options.DisplayFuzzPoints, "display-fuzz-points", "dfp", false, "display fuzz points in the output for debugging"),
flagSet.IntVar(&options.FuzzParamFrequency, "fuzz-param-frequency", 10, "frequency of uninteresting parameters for fuzzing before skipping"),
flagSet.StringVarP(&options.FuzzAggressionLevel, "fuzz-aggression", "fa", "low", "fuzzing aggression level controls payload count for fuzz (low, medium, high)"),
)
flagSet.CreateGroup("uncover", "Uncover",
@@ -419,10 +406,8 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.CreateGroup("cloud", "Cloud",
flagSet.DynamicVar(&pdcpauth, "auth", "true", "configure projectdiscovery cloud (pdcp) api key"),
flagSet.StringVarP(&options.TeamID, "team-id", "tid", _pdcp.TeamIDEnv, "upload scan results to given team id (optional)"),
flagSet.BoolVarP(&options.EnableCloudUpload, "cloud-upload", "cup", false, "upload scan results to pdcp dashboard"),
flagSet.StringVarP(&options.ScanID, "scan-id", "sid", "", "upload scan results to existing scan id (optional)"),
flagSet.StringVarP(&options.ScanName, "scan-name", "sname", "", "scan name to set (optional)"),
flagSet.StringVarP(&options.ScanID, "scan-id", "sid", "", "upload scan results to given scan id"),
)
flagSet.CreateGroup("Authentication", "Authentication",
@@ -430,6 +415,11 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.PreFetchSecrets, "prefetch-secrets", "ps", false, "prefetch secrets from the secrets file"),
)
flagSet.CreateGroup("tests", "Tests",
flagSet.BoolVarP(&options.AutogenerateTests, "autogenerate-tests", "agt", false, "enable autogeneration of nuclei test-cases (http only now)"),
flagSet.BoolVarP(&options.RunNucleiTests, "run-tests", "rts", false, "run generated nuclei test-cases"),
)
flagSet.SetCustomHelpText(`EXAMPLES:
Run nuclei on single host:
$ nuclei -target example.com
@@ -510,34 +500,6 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory)
}
defaultProfilesPath := filepath.Join(config.DefaultConfig.GetTemplateDir(), "profiles")
if templateProfile != "" {
if filepath.Ext(templateProfile) == "" {
if tp := findProfilePathById(templateProfile, defaultProfilesPath); tp != "" {
templateProfile = tp
} else {
gologger.Fatal().Msgf("'%s' is not a profile-id or profile path", templateProfile)
}
}
if !filepath.IsAbs(templateProfile) {
if filepath.Dir(templateProfile) == "profiles" {
defaultProfilesPath = filepath.Join(config.DefaultConfig.GetTemplateDir())
}
currentDir, err := os.Getwd()
if err == nil && fileutil.FileExists(filepath.Join(currentDir, templateProfile)) {
templateProfile = filepath.Join(currentDir, templateProfile)
} else {
templateProfile = filepath.Join(defaultProfilesPath, templateProfile)
}
}
if !fileutil.FileExists(templateProfile) {
gologger.Fatal().Msgf("given template profile file '%s' does not exist", templateProfile)
}
if err := flagSet.MergeConfigFile(templateProfile); err != nil {
gologger.Fatal().Msgf("Could not read template profile: %s\n", err)
}
}
if len(options.SecretsFile) > 0 {
for _, secretFile := range options.SecretsFile {
if !fileutil.FileExists(secretFile) {
@@ -663,27 +625,6 @@ Note: Make sure you have backup of your custom nuclei-templates before proceedin
os.Exit(0)
}
func findProfilePathById(profileId, templatesDir string) string {
var profilePath string
err := filepath.WalkDir(templatesDir, func(iterItem string, d fs.DirEntry, err error) error {
ext := filepath.Ext(iterItem)
isYaml := ext == extensions.YAML || ext == extensions.YML
if err != nil || d.IsDir() || !isYaml {
// skip non yaml files
return nil
}
if strings.TrimSuffix(filepath.Base(iterItem), ext) == profileId {
profilePath = iterItem
return fmt.Errorf("FOUND")
}
return nil
})
if err != nil && err.Error() != "FOUND" {
gologger.Error().Msgf("%s\n", err)
}
return profilePath
}
func init() {
// print stacktrace of errors in debug mode
if strings.EqualFold(os.Getenv("DEBUG"), "true") {
+4 -4
View File
@@ -162,7 +162,7 @@ func process(opts options) error {
var updated bool // if max-requests is updated
dataString, updated, err = parseAndAddMaxRequests(templateCatalog, path, dataString)
if err != nil {
gologger.Info().Label("max-request").Msg(logErrMsg(path, err, opts.debug, errFile))
gologger.Info().Label("max-request").Msgf(logErrMsg(path, err, opts.debug, errFile))
} else {
if updated {
gologger.Info().Label("max-request").Msgf("✅ updated template: %s\n", path)
@@ -255,7 +255,7 @@ func enhanceTemplate(data string) (string, bool, error) {
return data, false, errorutil.New("validation failed").WithTag("validate")
}
if templateResp.Error.Name != "" {
return data, false, errorutil.New("%s", templateResp.Error.Name)
return data, false, errorutil.New(templateResp.Error.Name)
}
if strings.TrimSpace(templateResp.Enhanced) == "" && !templateResp.Lint {
if templateResp.LintError.Reason != "" {
@@ -289,7 +289,7 @@ func formatTemplate(data string) (string, bool, error) {
return data, false, errorutil.New("validation failed").WithTag("validate")
}
if templateResp.Error.Name != "" {
return data, false, errorutil.New("%s", templateResp.Error.Name)
return data, false, errorutil.New(templateResp.Error.Name)
}
if strings.TrimSpace(templateResp.Updated) == "" && !templateResp.Lint {
if templateResp.LintError.Reason != "" {
@@ -345,7 +345,7 @@ func validateTemplate(data string) (bool, error) {
return false, errorutil.New("validation failed").WithTag("validate")
}
if validateResp.Error.Name != "" {
return false, errorutil.New("%s", validateResp.Error.Name)
return false, errorutil.New(validateResp.Error.Name)
}
return false, errorutil.New("template validation failed")
}
+1 -12
View File
@@ -1,24 +1,13 @@
package main
import (
"context"
nuclei "github.com/projectdiscovery/nuclei/v3/lib"
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
syncutil "github.com/projectdiscovery/utils/sync"
)
func main() {
ctx := context.Background()
// when running nuclei in parallel for first time it is a good practice to make sure
// templates exists first
tm := installer.TemplateManager{}
if err := tm.FreshInstallIfNotExists(); err != nil {
panic(err)
}
// create nuclei engine with options
ne, err := nuclei.NewThreadSafeNucleiEngineCtx(ctx)
ne, err := nuclei.NewThreadSafeNucleiEngine()
if err != nil {
panic(err)
}
+2 -6
View File
@@ -1,13 +1,9 @@
package main
import (
"context"
nuclei "github.com/projectdiscovery/nuclei/v3/lib"
)
import nuclei "github.com/projectdiscovery/nuclei/v3/lib"
func main() {
ne, err := nuclei.NewNucleiEngineCtx(context.Background(),
ne, err := nuclei.NewNucleiEngine(
nuclei.WithTemplateFilters(nuclei.TemplateFilters{Tags: []string{"oast"}}),
nuclei.EnableStatsWithOpts(nuclei.StatsOptions{MetricServerPort: 6064}), // optionally enable metrics server for better observability
)
+85 -66
View File
@@ -16,16 +16,16 @@ require (
github.com/json-iterator/go v1.1.12
github.com/julienschmidt/httprouter v1.3.0
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/miekg/dns v1.1.62
github.com/miekg/dns v1.1.57
github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/errors v0.9.1
github.com/projectdiscovery/clistats v0.1.0
github.com/projectdiscovery/fastdialer v0.2.5
github.com/projectdiscovery/hmap v0.0.55
github.com/projectdiscovery/interactsh v1.2.0
github.com/projectdiscovery/rawhttp v0.1.60
github.com/projectdiscovery/retryabledns v1.0.72
github.com/projectdiscovery/retryablehttp-go v1.0.74
github.com/projectdiscovery/clistats v0.0.20
github.com/projectdiscovery/fastdialer v0.0.67
github.com/projectdiscovery/hmap v0.0.41
github.com/projectdiscovery/interactsh v1.1.9
github.com/projectdiscovery/rawhttp v0.1.45
github.com/projectdiscovery/retryabledns v1.0.58
github.com/projectdiscovery/retryablehttp-go v1.0.55
github.com/projectdiscovery/yamldoc-go v1.0.4
github.com/remeh/sizedwaitgroup v1.0.0
github.com/rs/xid v1.5.0
@@ -35,18 +35,18 @@ require (
github.com/spf13/cast v1.5.1
github.com/syndtr/goleveldb v1.0.0
github.com/valyala/fasttemplate v1.2.2
github.com/weppos/publicsuffix-go v0.30.2
github.com/xanzy/go-gitlab v0.107.0
github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222
github.com/xanzy/go-gitlab v0.84.0
go.uber.org/multierr v1.11.0
golang.org/x/net v0.28.0
golang.org/x/oauth2 v0.22.0
golang.org/x/text v0.17.0
golang.org/x/net v0.24.0
golang.org/x/oauth2 v0.11.0
golang.org/x/text v0.14.0
gopkg.in/yaml.v2 v2.4.0
)
require (
code.gitea.io/sdk/gitea v0.17.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0
github.com/DataDog/gostackparse v0.6.0
github.com/Masterminds/semver/v3 v3.2.1
@@ -58,52 +58,53 @@ require (
github.com/aws/aws-sdk-go-v2/credentials v1.13.27
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.72
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.0
github.com/cespare/xxhash v1.1.0
github.com/charmbracelet/glamour v0.6.0
github.com/clbanning/mxj/v2 v2.7.0
github.com/denisenkom/go-mssqldb v0.12.3
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c
github.com/docker/go-units v0.5.0
github.com/dop251/goja v0.0.0-20240220182346-e401ed450204
github.com/fatih/structs v1.1.0
github.com/getkin/kin-openapi v0.126.0
github.com/getkin/kin-openapi v0.123.0
github.com/go-git/go-git/v5 v5.11.0
github.com/go-ldap/ldap/v3 v3.4.5
github.com/go-pg/pg v8.0.7+incompatible
github.com/go-sql-driver/mysql v1.7.1
github.com/goccy/go-yaml v1.11.3
github.com/h2non/filetype v1.1.3
github.com/invopop/yaml v0.3.1
github.com/labstack/echo/v4 v4.10.2
github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa
github.com/lib/pq v1.10.9
github.com/lib/pq v1.10.1
github.com/mattn/go-sqlite3 v1.14.22
github.com/mholt/archiver v3.1.1+incompatible
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.1.8
github.com/projectdiscovery/dsl v0.0.52
github.com/projectdiscovery/fasttemplate v0.0.2
github.com/projectdiscovery/freeport v0.0.5
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
github.com/projectdiscovery/goflags v0.1.65-0.20240824151034-33df02005a23
github.com/projectdiscovery/gologger v1.1.19
github.com/projectdiscovery/goflags v0.1.48
github.com/projectdiscovery/gologger v1.1.12
github.com/projectdiscovery/gostruct v0.0.2
github.com/projectdiscovery/gozero v0.0.2
github.com/projectdiscovery/httpx v1.6.7
github.com/projectdiscovery/mapcidr v1.1.34
github.com/projectdiscovery/httpx v1.6.0
github.com/projectdiscovery/mapcidr v1.1.16
github.com/projectdiscovery/martian/v3 v3.0.0-20240219194442-fed3b744f477
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
github.com/projectdiscovery/ratelimit v0.0.49
github.com/projectdiscovery/proxify v0.0.13-0.20240407134611-de309e8af9ca
github.com/projectdiscovery/ratelimit v0.0.35
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917
github.com/projectdiscovery/sarif v0.0.1
github.com/projectdiscovery/tlsx v1.1.6
github.com/projectdiscovery/uncover v1.0.9
github.com/projectdiscovery/useragent v0.0.65
github.com/projectdiscovery/utils v0.2.6
github.com/projectdiscovery/wappalyzergo v0.1.14
github.com/projectdiscovery/uncover v1.0.7
github.com/projectdiscovery/useragent v0.0.40
github.com/projectdiscovery/utils v0.0.88
github.com/projectdiscovery/wappalyzergo v0.0.116
github.com/redis/go-redis/v9 v9.1.0
github.com/seh-msft/burpxml v1.0.1
github.com/stretchr/testify v1.9.0
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706
golang.org/x/term v0.23.0
golang.org/x/term v0.19.0
gopkg.in/yaml.v3 v3.0.1
moul.io/http2curl v1.0.0
)
@@ -111,14 +112,16 @@ require (
require (
aead.dev/minisign v0.2.0 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/Shopify/sarama v1.38.1 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.27 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
@@ -126,16 +129,17 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/bits-and-blooms/bitset v1.8.0 // indirect
github.com/bits-and-blooms/bloom/v3 v3.5.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cheggaaa/pb/v3 v3.1.4 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/cloudflare/cfssl v1.6.4 // indirect
github.com/cloudflare/circl v1.3.8 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/containerd/continuity v0.4.2 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
@@ -144,31 +148,38 @@ require (
github.com/docker/cli v24.0.5+incompatible // indirect
github.com/docker/docker v24.0.9+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/eapache/channels v1.1.0 // indirect
github.com/eapache/go-resiliency v1.3.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/elastic/go-elasticsearch/v7 v7.17.10 // indirect
github.com/fatih/color v1.16.0 // 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
github.com/geoffgarside/ber v1.1.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-fed/httpsig v1.1.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/jsonpointer v0.20.2 // indirect
github.com/go-openapi/swag v0.22.9 // indirect
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/google/certificate-transparency-go v1.1.4 // indirect
github.com/google/go-github/v30 v30.1.0 // indirect
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.6 // indirect
github.com/haxii/fastproxy v0.5.37 // indirect
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/gofork v1.7.6 // indirect
@@ -177,10 +188,9 @@ require (
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kataras/jwt v0.1.10 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/compress v1.17.6 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/logrusorgru/aurora/v4 v4.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mackerelio/go-osstat v0.2.4 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -199,21 +209,25 @@ require (
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/projectdiscovery/asnmap v1.1.1 // indirect
github.com/projectdiscovery/cdncheck v1.1.0 // indirect
github.com/projectdiscovery/freeport v0.0.5 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/projectdiscovery/asnmap v1.1.0 // indirect
github.com/projectdiscovery/cdncheck v1.0.9 // indirect
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/projectdiscovery/roundrobin v0.0.6 // indirect
github.com/projectdiscovery/stringsutil v0.0.2 // indirect
github.com/projectdiscovery/tinydns v0.0.31 // indirect
github.com/quic-go/quic-go v0.42.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/refraction-networking/utls v1.6.1 // 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
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/tidwall/btree v1.7.0 // indirect
github.com/tidwall/buntdb v1.3.1 // indirect
github.com/tidwall/gjson v1.17.3 // indirect
github.com/tidwall/buntdb v1.3.0 // indirect
github.com/tidwall/gjson v1.17.0 // indirect
github.com/tidwall/grect v0.1.4 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
@@ -232,9 +246,9 @@ require (
github.com/yuin/goldmark-emoji v1.0.1 // indirect
github.com/zcalusic/sysinfo v1.0.2 // indirect
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.6.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
mellium.im/sasl v0.3.1 // indirect
)
@@ -262,12 +276,13 @@ require (
github.com/gobwas/pool v0.2.1 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
github.com/hdm/jarm-go v0.0.7 // indirect
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
@@ -278,36 +293,38 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mholt/acmez v1.2.0 // indirect
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/projectdiscovery/blackrock v0.0.1 // indirect
github.com/projectdiscovery/networkpolicy v0.0.9
github.com/projectdiscovery/networkpolicy v0.0.8
github.com/rivo/uniseg v0.4.6 // indirect
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/trivago/tgo v1.0.7
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/yl2chen/cidranger v1.0.2 // indirect
github.com/ysmood/goob v0.4.0 // indirect
github.com/ysmood/gson v0.7.3 // indirect
github.com/ysmood/leakless v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect
github.com/zmap/zcrypto v0.0.0-20240512203510-0fef58d9a9db // indirect
go.etcd.io/bbolt v1.3.10 // indirect
github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c // indirect
go.etcd.io/bbolt v1.3.8 // indirect
go.uber.org/zap v1.25.0 // indirect
goftp.io/server/v2 v2.0.1 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
golang.org/x/mod v0.20.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.24.0
google.golang.org/protobuf v1.34.2 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
golang.org/x/mod v0.14.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.17.0
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
)
@@ -347,3 +364,5 @@ require (
// https://go.dev/ref/mod#go-mod-file-retract
retract v3.2.0 // retract due to broken js protocol issue
replace github.com/go-echarts/go-echarts/v2 => github.com/tarunKoyalwar/go-echarts/v2 v2.1.1
+191 -150
View File
@@ -40,26 +40,25 @@ dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a h1:3i+FJ7IpSZHL+VAjtpQeZCRhrpP0odl5XfoLBY4fxJ8=
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a/go.mod h1:C7hXLmFmPYPjIDGfQl1clsmQ5TMEQfmzWTrJk475bUs=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613EeLayJiRAJuKlBGy+m22qWG+WRg=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0/go.mod h1:7QJP7dr2wznCMeqIrhMgWGf7XpAQnVrJqDm9nvV3Cu4=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY=
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/gostackparse v0.6.0 h1:egCGQviIabPwsyoWpGvIBGrEnNWez35aEO7OJ1vBI4o=
@@ -86,7 +85,12 @@ github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAc
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/RumbleDiscovery/rumble-tools v0.0.0-20201105153123-f2adbb3244d2/go.mod h1:jD2+mU+E2SZUuAOHZvZj4xP4frlOo+N/YrXDvASFhkE=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A=
github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g=
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/Shopify/toxiproxy/v2 v2.5.0 h1:i4LPT+qrSlKNtQf5QliVjdP08GyAH8+BUIc9gT0eahc=
github.com/Shopify/toxiproxy/v2 v2.5.0/go.mod h1:yhM2epWtAmel9CB8r2+L+PCmhH6yH2pITaPAo7jxJl0=
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
@@ -187,9 +191,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bits-and-blooms/bloom/v3 v3.5.0 h1:AKDvi1V3xJCmSR6QhcBfHbCN4Vf8FfxeWkMNQfmAGhY=
github.com/bits-and-blooms/bloom/v3 v3.5.0/go.mod h1:Y8vrn7nk1tPIlmLtW2ZPV+W7StdVMor6bC1xgpjMZFs=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
@@ -237,8 +240,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO8=
github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
@@ -261,6 +264,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
@@ -273,6 +278,8 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/cli v24.0.5+incompatible h1:WeBimjvS0eKdH4Ygx+ihVq1Q++xg36M/rMi4aXAvodc=
github.com/docker/cli v24.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0=
@@ -294,10 +301,19 @@ github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj6
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/channels v1.1.0 h1:F1taHcn7/F0i8DYqKXJnyhJcVpp2kgFcNePxXtnyu4k=
github.com/eapache/channels v1.1.0/go.mod h1:jMm2qB5Ubtg9zLd+inMZd2/NUvXgzmWXsDaLyQIGfH0=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-resiliency v1.3.0 h1:RRL0nge+cWGlxXbUzJ7yMcq6w2XBEr19dCN6HECGaT0=
github.com/eapache/go-resiliency v1.3.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6 h1:8yY/I9ndfrgrXUbOGObLHKBR4Fl3nZXwM2c7OYTT8hM=
github.com/eapache/go-xerial-snappy v0.0.0-20230111030713-bf00bc1b83b6/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/go-elasticsearch/v7 v7.17.10 h1:TCQ8i4PmIJuBunvBS6bwT2ybzVFxxUhhltAs3Gyu1yo=
github.com/elastic/go-elasticsearch/v7 v7.17.10/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
@@ -325,12 +341,10 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gaissmai/bart v0.9.5 h1:vy+r4Px6bjZ+v2QYXAsg63vpz9IfzdW146A8Cn4GPIo=
github.com/gaissmai/bart v0.9.5/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg=
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
github.com/getkin/kin-openapi v0.123.0 h1:zIik0mRwFNLyvtXK274Q6ut+dPh6nlxBp0x7mNrPhs8=
github.com/getkin/kin-openapi v0.123.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
@@ -340,8 +354,6 @@ github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-echarts/go-echarts/v2 v2.3.3 h1:uImZAk6qLkC6F9ju6mZ5SPBqTyK8xjZKwSmwnCg4bxg=
github.com/go-echarts/go-echarts/v2 v2.3.3/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI=
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
@@ -367,12 +379,14 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
github.com/go-pg/pg v8.0.7+incompatible h1:ty/sXL1OZLo+47KK9N8llRcmbA9tZasqbQ/OO4ld53g=
github.com/go-pg/pg v8.0.7+incompatible/go.mod h1:a2oXow+aFOrvwcKs3eIA0lNFmMilrxK2sOkB5NWe0vA=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@@ -392,6 +406,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/goburrow/cache v0.1.4 h1:As4KzO3hgmzPlnaMniZU9+VmoNYseUhuELbxy9mRBfw=
@@ -404,6 +420,8 @@ github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I=
github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -416,10 +434,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -452,6 +468,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -501,8 +518,8 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
@@ -524,16 +541,20 @@ github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -555,6 +576,9 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/haxii/fastproxy v0.5.37 h1:grfso8V9sNO8jZjI/vkizFXzz8fE/yrsgl+XxTb3fio=
github.com/haxii/fastproxy v0.5.37/go.mod h1:VFy3M4EmTbeKu+IccQ6UiJ1W4sPeQ75GV+1JDa8h864=
github.com/haxii/log v1.0.0/go.mod h1:y9MlOm+u2ny65yQxScWfSGZFOhRVLXz2vJlkiIx2jfI=
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf h1:umfGUaWdFP2s6457fz1+xXYIWDxdGc7HdkLS9aJ1skk=
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf/go.mod h1:V99KdStnMHZsvVOwIvhfcUzYgYkRZeQWUtumtL+SKxA=
github.com/hdm/jarm-go v0.0.7 h1:Eq0geenHrBSYuKrdVhrBdMMzOmA+CAMLzN2WrF3eL6A=
@@ -570,8 +594,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
@@ -627,8 +651,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
@@ -659,16 +683,14 @@ 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=
github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa/go.mod h1:HbwNE4XGwjgtUELkvQaAOjWrpianHYZdQVNqSdYW3UM=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo=
github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUpJYn9JA=
github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ=
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 h1:wIONC+HMNRqmWBjuMxhatuSzHaljStc4gjDeKycxy0A=
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -707,14 +729,12 @@ github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc=
github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU=
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
github.com/minio/minio-go/v6 v6.0.46/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc=
github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
@@ -739,6 +759,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
@@ -771,6 +792,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
@@ -808,8 +831,9 @@ github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -822,72 +846,80 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/praetorian-inc/fingerprintx v1.1.9 h1:zWbG/Fdan0s/dvXkeaHb/CdFTz/yEEzrAF4iCzok3r8=
github.com/praetorian-inc/fingerprintx v1.1.9/go.mod h1:k6EJIHe/Da4DH5e4JuoZHe+qSGq/KPUmXGaK+xW74OI=
github.com/projectdiscovery/asnmap v1.1.1 h1:ImJiKIaACOT7HPx4Pabb5dksolzaFYsD1kID2iwsDqI=
github.com/projectdiscovery/asnmap v1.1.1/go.mod h1:QT7jt9nQanj+Ucjr9BqGr1Q2veCCKSAVyUzLXfEcQ60=
github.com/projectdiscovery/asnmap v1.1.0 h1:ynvbLB5cNpyQ2+k9IP0Rpla+0JmCJpd3mw6KLAW13m0=
github.com/projectdiscovery/asnmap v1.1.0/go.mod h1:QNjBnGLxUBEZAgaYk/Av5cjKKWFY3i/FOfoIWCUApoY=
github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ=
github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss=
github.com/projectdiscovery/cdncheck v1.1.0 h1:qDITidmJsejzpk3rMkauCh6sjI2GH9hW/snk0cQ3kXE=
github.com/projectdiscovery/cdncheck v1.1.0/go.mod h1:sZ8U4MjHSsyaTVjBbYWHT1cwUVvUYwDX1W+WvWRicIc=
github.com/projectdiscovery/clistats v0.1.0 h1:b+LF1w0xhNd7cneKWMXb+/yUmF1n5szawxP4XGpmbxs=
github.com/projectdiscovery/clistats v0.1.0/go.mod h1:GJ2av0KnOvK0AISQnP8hyDclYIji1LVkx2l0pwnzAu4=
github.com/projectdiscovery/dsl v0.1.8 h1:ulz+o097XsYgqP4QXaAQhVSkoeD2ZPWd29wX3CTodUA=
github.com/projectdiscovery/dsl v0.1.8/go.mod h1:AYJS2WQ/q0smr2v4pEJTg4DPe6k56KFKR7UFXvzNz/4=
github.com/projectdiscovery/fastdialer v0.2.5 h1:OZg31LFIBBHbXVnOEcFNtD0gBM80zpY68QvYI0xbw80=
github.com/projectdiscovery/fastdialer v0.2.5/go.mod h1:E1vmos7AeD/KZ7rsDeImjLp5H3jjas+2utVdUxGulvY=
github.com/projectdiscovery/cdncheck v1.0.9 h1:BS15gzj9gb5AVSKqTDzPamfSgStu7nJQOocUvrssFlg=
github.com/projectdiscovery/cdncheck v1.0.9/go.mod h1:18SSl1w7rMj53CGeRIZTbDoa286a6xZIxGbaiEo4Fxs=
github.com/projectdiscovery/clistats v0.0.20 h1:5jO5SLiRJ7f0nDV0ndBNmBeesbROouPooH+DGMgoWq4=
github.com/projectdiscovery/clistats v0.0.20/go.mod h1:GJ2av0KnOvK0AISQnP8hyDclYIji1LVkx2l0pwnzAu4=
github.com/projectdiscovery/dsl v0.0.52 h1:jvIvF+qN8+MbI1MHtWJJKfWqAZQlCExL3ob7SddQbZE=
github.com/projectdiscovery/dsl v0.0.52/go.mod h1:xfcHwhy2HSaeGgh+1wqzOoCGm2XTdh5JzjBRBVHEMvI=
github.com/projectdiscovery/fastdialer v0.0.67 h1:NvBpZUiLr9Ne9N+Lvi6FFiNNLWuhk5Bc1H+oE9J8C1E=
github.com/projectdiscovery/fastdialer v0.0.67/go.mod h1:GhSAKnojJN8N9K0JNjLmwLCmEDsQ5cBAStqSCm/tm84=
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.5 h1:jnd3Oqsl4S8n0KuFkE5Hm8WGDP24ITBvmyw5pFTHS8Q=
github.com/projectdiscovery/freeport v0.0.5/go.mod h1:PY0bxSJ34HVy67LHIeF3uIutiCSDwOqKD8ruBkdiCwE=
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.65-0.20240824151034-33df02005a23 h1:6RTUy0fybNvQDZqJFz1RRFdQds4+ZhCpN299+ApOxyQ=
github.com/projectdiscovery/goflags v0.1.65-0.20240824151034-33df02005a23/go.mod h1:3FyHIVQtnycNOc1LE3O1jj/XR5XuMdF9QfHd0ujhnX4=
github.com/projectdiscovery/gologger v1.1.19 h1:b7cU32XuDrDiwhr7hlDeE6mfj/nENBtHEohe51txJCE=
github.com/projectdiscovery/gologger v1.1.19/go.mod h1:DbeKwx9IEfcvnclImX5gBlhIKUuOZwOM5itdpYXl+54=
github.com/projectdiscovery/goflags v0.1.48 h1:iJgq+YuQOEm0V7BqlV/0wx7GaI2rmGiFzPkvL/4sCj0=
github.com/projectdiscovery/goflags v0.1.48/go.mod h1:C9Qqyivehk5iYCf3VAC3+85y60Qbde1ZBMqe5wHhcVw=
github.com/projectdiscovery/gologger v1.1.12 h1:uX/QkQdip4PubJjjG0+uk5DtyAi1ANPJUvpmimXqv4A=
github.com/projectdiscovery/gologger v1.1.12/go.mod h1:DI8nywPLERS5mo8QEA9E7gd5HZ3Je14SjJBH3F5/kLw=
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.2 h1:8fJeaCjxL9tpm33uG/RsCQs6HGM/NE6eA3cjkilRQ+E=
github.com/projectdiscovery/gozero v0.0.2/go.mod h1:d8bZvDWW07LWNYWrwjZ4OO1I0cpkfqaysyDfSs9ibK8=
github.com/projectdiscovery/hmap v0.0.55 h1:By0qSeQRE/ybeITUEL6oURN+j7qX7FVjCq92duwsqcA=
github.com/projectdiscovery/hmap v0.0.55/go.mod h1:uZOF/W8yOGDb/t9omqATirhVwiboa5F/c00OVhDeE0E=
github.com/projectdiscovery/httpx v1.6.7 h1:luJAtQ+iKpiyKKDpcWw1/fF1MaRX6JZ4R3P+ol5Uikk=
github.com/projectdiscovery/httpx v1.6.7/go.mod h1:rqcuexBrb4v36ZyX0BHcHaovTurOJn2P65Tdt9cYdfE=
github.com/projectdiscovery/interactsh v1.2.0 h1:Al6jHiR+Usl9egYJDLJaWNHOcH8Rugk8gWMasc8Cmw8=
github.com/projectdiscovery/interactsh v1.2.0/go.mod h1:Wxt0fnzxsfrAZQQlpVrf3xMatP4OXZaZbjuDkIQKdYY=
github.com/projectdiscovery/hmap v0.0.41 h1:8IgTyDce3/2JzcfPVA4H+XpBRFfETULx8td3BMdSYVE=
github.com/projectdiscovery/hmap v0.0.41/go.mod h1:bCrai6x5Eijqm2U+jtcH0wZX5ZcaZhcvzoMGTZgLAf0=
github.com/projectdiscovery/httpx v1.6.0 h1:6g4UoSQpsOyZgaK+SMLLnZIAU0eYyTxBUwVl+jtm0JQ=
github.com/projectdiscovery/httpx v1.6.0/go.mod h1:dzMzOWKfeofaXcXzac3O+YmuY24P0CRnviKGxvol6MM=
github.com/projectdiscovery/interactsh v1.1.9 h1:b77SaSGrO+DtivmWwqGGY2dmNlQC3Zgmwlaj9L4Oqvc=
github.com/projectdiscovery/interactsh v1.1.9/go.mod h1:0FRQXCildcTLq7Tsa4BVZAsFCXhpWs4C4quKWigXb5I=
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb h1:MGtI4oE12ruWv11ZlPXXd7hl/uAaQZrFvrIDYDeVMd8=
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb/go.mod h1:vmgC0DTFCfoCLp0RAfsfYTZZan0QMVs+cmTbH6blfjk=
github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE=
github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI=
github.com/projectdiscovery/mapcidr v1.1.34 h1:udr83vQ7oz3kEOwlsU6NC6o08leJzSDQtls1wmXN/kM=
github.com/projectdiscovery/mapcidr v1.1.34/go.mod h1:1+1R6OkKSAKtWDXE9RvxXtXPoajXTYX0eiEdkqlhQqQ=
github.com/projectdiscovery/mapcidr v1.1.16 h1:rjj1w5D6hbTsUQXYClLcGdfBEy9bryclgi70t0vBggo=
github.com/projectdiscovery/mapcidr v1.1.16/go.mod h1:rGqpBhStdwOQ2uS62QM9qPsybwMwIhT7CTd2bxoHs8Q=
github.com/projectdiscovery/martian/v3 v3.0.0-20240219194442-fed3b744f477 h1:VJaBELAC5Hw+kc+ylrFF5nSf7Wasnb9mZxMlF/kR3gg=
github.com/projectdiscovery/martian/v3 v3.0.0-20240219194442-fed3b744f477/go.mod h1:wPvVUl2C/XOFacugXwsUp65GN0upmKfwKMyimA/AAaM=
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 h1:L/e8z8yw1pfT6bg35NiN7yd1XKtJap5Nk6lMwQ0RNi8=
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.49 h1:PYatMp8g5OuoFsZOA90e48nLd2vB6a4Tw0FZ8h9zqkQ=
github.com/projectdiscovery/ratelimit v0.0.49/go.mod h1:Xi0LTMHg4HQlmCZFzRBIhRW6N+QW5RxQ8V/Qs+Vta4k=
github.com/projectdiscovery/rawhttp v0.1.60 h1:L57kAATGRuCfOp8Fs0ly3j2wlip7R5pco2RVfwqh/II=
github.com/projectdiscovery/rawhttp v0.1.60/go.mod h1:M97w6lsphTHKeqLSio4Lw9K4KLO2riJMYAOqVMIZ3ck=
github.com/projectdiscovery/networkpolicy v0.0.8 h1:XvfBaBwSDNTesSfNQP9VLk3HX9I7x7gHm028TJ5XwI8=
github.com/projectdiscovery/networkpolicy v0.0.8/go.mod h1:xnjNqhemxUPxU+UD5Jgsc3+K8IVmcqT1SJeo6UzMtkI=
github.com/projectdiscovery/proxify v0.0.13-0.20240407134611-de309e8af9ca h1:Adduz+Lli837Ga2K1NqxVFOFxRYsWjK4zRWzHQWZtV4=
github.com/projectdiscovery/proxify v0.0.13-0.20240407134611-de309e8af9ca/go.mod h1:9x1db4kybvc6BpSvpvbMzAuWjNFrt6Foy1t1VI7CUTc=
github.com/projectdiscovery/ratelimit v0.0.35 h1:epEzFATOcXZ4tssV4Hax5Op9lrbUnQMEGMV5PoUpTKc=
github.com/projectdiscovery/ratelimit v0.0.35/go.mod h1:mPqa8UpV5I7eAN5/ZcsjLiXMhjtVvZRrHtpBRsTPuyA=
github.com/projectdiscovery/rawhttp v0.1.45 h1:5jssUybhRz2ljI3bW4kUO9MTvZ37ArG8pISYtgqzwBg=
github.com/projectdiscovery/rawhttp v0.1.45/go.mod h1:oLWuZkyKi4rddPoLEN3TeAqyLvFNfr3dxmzV2kwpPvs=
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.72 h1:+k9JRYBMpZIyEQZJWVHoCHx1TEdpiuAS7iEru2bhs3A=
github.com/projectdiscovery/retryabledns v1.0.72/go.mod h1:BDhYnqSH0Os2G37eb4L4vnKrUcik6Q6pR02Cq5PbT+0=
github.com/projectdiscovery/retryablehttp-go v1.0.74 h1:jXZsg3nNDuDjGNeL0+hiEx/dqUqPyZW1zsotWW1y70c=
github.com/projectdiscovery/retryablehttp-go v1.0.74/go.mod h1:fVRxa2fVMbomaPiOFA05kM2WrjV8wPFHW7J84eenVmQ=
github.com/projectdiscovery/retryabledns v1.0.58 h1:ut1FSB9+GZ6zQIlKJFLqIz2RZs81EmkbsHTuIrWfYLE=
github.com/projectdiscovery/retryabledns v1.0.58/go.mod h1:RobmKoNBgngAVE4H9REQtaLP1pa4TCyypHy1MWHT1mY=
github.com/projectdiscovery/retryablehttp-go v1.0.55 h1:ADgugnl9jKkNXn5m/Zd8TGPq1P7GplYlqUNKm/qTmls=
github.com/projectdiscovery/retryablehttp-go v1.0.55/go.mod h1:Kpvh4ruFPOEPYaYxgbFmlvBJr4lJKqpcbGvx1j0r/Ng=
github.com/projectdiscovery/roundrobin v0.0.6 h1:zoJAFRgP9XK7B+iKSjR+djRAuDYxnc57+Fx+qpoPvds=
github.com/projectdiscovery/roundrobin v0.0.6/go.mod h1:vTxcWqNLyMH6VE2Q/hsNNvDHFLiIzHozC1rLLT/vocQ=
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=
github.com/projectdiscovery/stringsutil v0.0.2/go.mod h1:EJ3w6bC5fBYjVou6ryzodQq37D5c6qbAYQpGmAy+DC0=
github.com/projectdiscovery/tinydns v0.0.31 h1:iQL1ze2/4PHWH+Nzsxg35kVIWkvEIatAZCDcP0c1/v4=
github.com/projectdiscovery/tinydns v0.0.31/go.mod h1:6rj/dEzXZPn+nLl4O1wUMJdfkdUQ9eCV7NsDWPakYv8=
github.com/projectdiscovery/tlsx v1.1.6 h1:iw2zwKbd2+kRQ8J1G4dLmS0CLyemd/tKz1UzcNsC77A=
github.com/projectdiscovery/tlsx v1.1.6/go.mod h1:s7SRRFdrwIZBK/RXXZi4CR/CubqFSvp8h5Bk1srEZIo=
github.com/projectdiscovery/uncover v1.0.9 h1:s5RbkD/V4r8QcPkys4gTTqMuRSgXq0JprejqLSopN9Y=
github.com/projectdiscovery/uncover v1.0.9/go.mod h1:2PUF3SpB5QNIJ8epaB2xbRzkPaxEAWRDm3Ir2ijt81U=
github.com/projectdiscovery/useragent v0.0.65 h1:x78ZwWdqpzokOHxLITUXvq+ljkTKc19z3ILGtoV1N70=
github.com/projectdiscovery/useragent v0.0.65/go.mod h1:deOP8YLJU6SCzM8k+K8PjkcOF4Ux0spqyO4ODZGIT4A=
github.com/projectdiscovery/utils v0.2.6 h1:7ZZ+tK8u3vO/X7i0HXwybNusFBtYnM363bxDxJkVnso=
github.com/projectdiscovery/utils v0.2.6/go.mod h1:XFy8Ldt537TGkj3snH0zXfF9LigRfmHPGCNfDolSdEQ=
github.com/projectdiscovery/wappalyzergo v0.1.14 h1:nt1IM4RUmqeymsXk4h6BsZbKDoS2hjFvPkT2GaI1rz4=
github.com/projectdiscovery/wappalyzergo v0.1.14/go.mod h1:/hzgxkBFTMe2wDbA93nFfoMjULw7/vIZ9QPSAnCgUa8=
github.com/projectdiscovery/uncover v1.0.7 h1:ut+2lTuvmftmveqF5RTjMWAgyLj8ltPQC7siFy9sj0A=
github.com/projectdiscovery/uncover v1.0.7/go.mod h1:HFXgm1sRPuoN0D4oATljPIdmbo/EEh1wVuxQqo/dwFE=
github.com/projectdiscovery/useragent v0.0.40 h1:1LUhReSGPkhqsM5n40OOC9dIoNqMGs1dyGFJcOmg2Fo=
github.com/projectdiscovery/useragent v0.0.40/go.mod h1:EvK1x3s948Gtqb/XOahXcauyejCL/rSgy5d1IAvsKT4=
github.com/projectdiscovery/utils v0.0.88 h1:oYfCXM+8VHNLyH/H6cOibkuDUwHUAOBAMRNPFX6NPrs=
github.com/projectdiscovery/utils v0.0.88/go.mod h1:lAWzFdGXtJRPKdhUu1Z46d8B8JbASTk1Z69WY6H/3kA=
github.com/projectdiscovery/wappalyzergo v0.0.116 h1:xy+mBpwbYo/0PSzmJOQ/RXHomEh0D3nDBcbCxsW69m8=
github.com/projectdiscovery/wappalyzergo v0.0.116/go.mod h1:hc/o+fgM8KtdpFesjfBTmHTwsR+yBd+4kYZW/DGy/x8=
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=
@@ -922,11 +954,15 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
github.com/refraction-networking/utls v1.6.1 h1:n1JG5karzdGWsI6iZmGrOv3SNzR4c+4M8J6KWGsk3lA=
github.com/refraction-networking/utls v1.6.1/go.mod h1:+EbcQOvQvXoFV9AEKbuGlljt1doLRKAVY1jJHe9EtDo=
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -940,8 +976,10 @@ github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.11.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
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/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
@@ -1008,17 +1046,17 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.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=
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9/go.mod h1:uQdBQGrE1fZ2EyOs0pLcCDd1bBV4rSThieuIIGhXZ50=
github.com/tarunKoyalwar/go-echarts/v2 v2.1.1 h1:5fsXGPmK+i18J8cDgxy7AJkiXWBARpVTb0Gbv+bAzPo=
github.com/tarunKoyalwar/go-echarts/v2 v2.1.1/go.mod h1:VEeyPT5Odx/UHeuxtIAHGu2+87MWGA5OBaZ120NFi/w=
github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=
github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tidwall/buntdb v1.3.1 h1:HKoDF01/aBhl9RjYtbaLnvX9/OuenwvQiC3OP1CcL4o=
github.com/tidwall/buntdb v1.3.1/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA=
github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
@@ -1049,8 +1087,8 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@@ -1061,13 +1099,13 @@ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+
github.com/weppos/publicsuffix-go v0.12.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
github.com/weppos/publicsuffix-go v0.30.0/go.mod h1:kBi8zwYnR0zrbm8RcuN1o9Fzgpnnn+btVN8uWPMyXAY=
github.com/weppos/publicsuffix-go v0.30.2 h1:Np18yzfMR90jNampWFs7iSh2sw/qCZkhL41/ffyihCU=
github.com/weppos/publicsuffix-go v0.30.2/go.mod h1:/hGscit36Yt+wammfBBwdMdxBT8btsTt6KvwO9OvMyM=
github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 h1:h2JizvZl9aIj6za9S5AyrkU+OzIS4CetQthH/ejO+lg=
github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ=
github.com/weppos/publicsuffix-go/publicsuffix/generator v0.0.0-20220927085643-dc0d00c92642/go.mod h1:GHfoeIdZLdZmLjMlzBftbTDntahTttUMWjxZwQJhULE=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/xanzy/go-gitlab v0.107.0 h1:P2CT9Uy9yN9lJo3FLxpMZ4xj6uWcpnigXsjvqJ6nd2Y=
github.com/xanzy/go-gitlab v0.107.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY=
github.com/xanzy/go-gitlab v0.84.0 h1:PdpCaskQSgcVDsx21c6ikf8Rfyo7SNtFAJwP9PrbCFE=
github.com/xanzy/go-gitlab v0.84.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1125,15 +1163,15 @@ github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+T
github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300/go.mod h1:mOd4yUMgn2fe2nV9KXsa9AyQBFZGzygVPovsZR+Rl5w=
github.com/zmap/zcrypto v0.0.0-20240512203510-0fef58d9a9db h1:IfONOhyZlf4qPt3ENPU+27mBbPjzTQ+swKpj7MJva9I=
github.com/zmap/zcrypto v0.0.0-20240512203510-0fef58d9a9db/go.mod h1:mo/07mo6reDaiz6BzveCuYBWb1d+aX8Pf8Nh+Q57y2g=
github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c h1:U1b4THKcgOpJ+kILupuznNwPiURtwVW3e9alJvji9+s=
github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c/go.mod h1:GSDpFDD4TASObxvfZfvpZZ3OWHIUHMlhVWlkOe4ewVk=
github.com/zmap/zflags v1.4.0-beta.1.0.20200204220219-9d95409821b6/go.mod h1:HXDUD+uue8yeLHr0eXx1lvY6CvMiHbTKw5nGmA9OUoo=
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706 h1:LaMyYFWQA7kh3ovPfAaFDTKlJu3JGng8khruOtsBVnE=
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706/go.mod h1:re2kMcs84XHb8Xl6RInt0emoKCuphfmfjHYuteviLHQ=
github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@@ -1144,8 +1182,8 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -1170,6 +1208,7 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
@@ -1180,11 +1219,10 @@ golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
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.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
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=
@@ -1195,8 +1233,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1219,8 +1257,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1263,6 +1301,7 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@@ -1275,11 +1314,9 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
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=
@@ -1289,8 +1326,8 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1304,8 +1341,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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.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=
@@ -1356,6 +1393,7 @@ golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1370,19 +1408,18 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.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=
@@ -1392,11 +1429,10 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
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.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
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=
@@ -1410,17 +1446,15 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
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.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
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.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1472,12 +1506,14 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -1502,6 +1538,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -1533,6 +1570,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20220706185917-7780775163c4 h1:7YDGQC/0sigNGzsEWyb9s72jTxlFdwVEYNJHbfQ+Dtg=
google.golang.org/genproto v0.0.0-20220706185917-7780775163c4/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@@ -1550,6 +1589,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1565,9 +1606,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1601,6 +1641,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
@@ -1,27 +0,0 @@
id: fuzz-multi-mode-test
info:
name: multi-mode fuzzing test
author: pdteam
severity: info
http:
- payloads:
inject:
- nuclei-v1
- nuclei-v2
- nuclei-v3
fuzzing:
- part: header
type: replace
mode: multiple
fuzz:
X-Client-Id: "{{inject}}"
X-Secret-Id: "{{inject}}"
matchers-condition: or
matchers:
- type: word
words:
- "nuclei-v3"
+5 -2
View File
@@ -15,18 +15,21 @@ http:
- type: dsl
dsl:
- 'method == "GET"'
- regex("/(.*?/)([0-9]+)(/.*)?",path)
condition: and
payloads:
pathsqli:
- "'OR1=1"
- '%20OR%20True'
fuzzing:
- part: path
type: postfix
type: replace-regex
mode: single
replace-regex: '/(.*?/)([0-9]+)(/.*)?'
fuzz:
- '{{pathsqli}}'
- '/${1}${2}{{pathsqli}}${3}'
matchers:
- type: status
@@ -1,2 +0,0 @@
tags:
- kev
@@ -23,4 +23,4 @@ code:
- type: dsl
dsl:
- true
# digest: 4a0a0047304502200307590191cb7c766b6c21e5777d345bdddf7adf9d6da8f7d336d585d9ac4a8b022100fd30fb0c7722778eb3d861d60e721d805925b8d8df2b979ef2104c35ec57d5cb:4a3eb6b4988d95847d4203be25ed1d46
# digest: 490a004630440220192fb8f704b078c2885047b85ac1a0491be86485c033a976d201599683a35aab0220604b1c3781e9d97079d0e5c23c18e6a2d87493c8e2b930536e692ee7d06e9247:4a3eb6b4988d95847d4203be25ed1d46
@@ -20,4 +20,4 @@ code:
- type: word
words:
- "hello from input baz"
# digest: 4a0a0047304502203fe1d7d52bc2a41886d576a90c82c3be42078baaa4b46e1f3d8519665d6f88b202210081feb82c41150c5b218e226fc4f299ded19f42ba01ef34ba60b0634b4ea6ee12:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4a0a00473045022033f72f1b9d5143f58a2dc79c2597000f34080251ac3702c36c3fad00917dfeeb0221009ba05c715c9e2e36dba471be6c0106a09ae3822d8a3e9e4bcf377e9f4a395a01:4a3eb6b4988d95847d4203be25ed1d46
@@ -18,4 +18,4 @@ code:
- type: word
words:
- "hello from input"
# digest: 4b0a00483046022100afb5ebff14a40e7f9b679ffc4d93ce7849e33eb398ebb47f2e757cd24831f9dd02210089ffa21b2763e99ebce95dfc5b91e1e62da4ccdc9d2ad5c48584fa350ba335af:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4a0a004730450220377128cb11d9f6f0fee1f4dbd841e46783de26e90a216fa55a7609ee2bc823c60221009166ee0f85e3a1811588ab19e73ea96ab3d582dc8180dbcbbad0ea9ab7e9025d:4a3eb6b4988d95847d4203be25ed1d46
@@ -26,4 +26,4 @@ code:
part: interactsh_protocol
words:
- "http"
# digest: 4b0a00483046022100939f83e74d43932a5bd792b1fd2c100eec2df60f2b2a8dd56b5c8ef5faa92b17022100f93031b0de373af7d78e623968ea5a2d67c4561ef70e3e6da15aef7e5c853115:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4b0a00483046022100d472d50bd83117d334f5217c7a40dcdf34138e90029eaace51697d902296bf37022100a393b49420a96f60d6d89b79b5135ee2233b2468d374851890eea114b08195d1:4a3eb6b4988d95847d4203be25ed1d46
@@ -21,4 +21,4 @@ code:
- type: word
words:
- "hello from input"
# digest: 4a0a00473045022100b8e676ce0c57b60c233a0203539dec20457bbb5f1790d351a5d45405b6668b2602204b1f2fa18e7db099f05329009597ceb2d9b7337562c1a676e8d50ea2f1c6fcbe:4a3eb6b4988d95847d4203be25ed1d46
# digest: 4b0a004830460221008886054bb5dd6345e434e30f31c8fddce3c484a4f33aa6321b5185675866029d022100d188a83d0fde029f8b586061c65ab72b43755c3fb10fdd59501bb9bbadbb1ff7:4a3eb6b4988d95847d4203be25ed1d46
@@ -1,34 +0,0 @@
id: multi-req
info:
name: Multi-Request
author: pdteam
severity: info
ssl:
- address: "{{Host}}:{{Port}}"
min_version: ssl30
max_version: ssl30
extractors:
- type: json
json:
- " .tls_version"
- address: "{{Host}}:{{Port}}"
min_version: tls10
max_version: tls10
extractors:
- type: json
json:
- " .tls_version"
- address: "{{Host}}:{{Port}}"
min_version: tls11
max_version: tls11
extractors:
- type: json
json:
- " .tls_version"
@@ -19,4 +19,4 @@ code:
regex:
- 'hello from (.*)'
group: 1
# digest: 490a00463044022050da011362cf08c2cb81e812c7f86d7282afe0562d4bf00d390f1300d19bc910022029e9d305da69e941ac18797645aecb217abde6557f891e141301b48e89a3c0cd:4a3eb6b4988d95847d4203be25ed1d46
# digest: 490a0046304402202c63d47bb0acdd40b3b852d95490d492ff5741b84071b2a8a40371be7797c13602202b6b977e157edf2ef70a402a2e57d4eb5a67c5ca91f0a2f9a10a966e8485ebaf:4a3eb6b4988d95847d4203be25ed1d46
@@ -18,4 +18,4 @@ code:
- type: word
words:
- "hello from first"
# digest: 4b0a00483046022100b3b8759c0df028455eb59b1433ac240e5d4604b011bb0c63680bd3cc159ac6f0022100f44aa11b640d11ad0e2902897f4eb51666ab3cd83c31dfd2590f6e43391e39b0:4a3eb6b4988d95847d4203be25ed1d46
# digest: 490a00463044022025661eab353b7f359c0d428a86b6287545d7f759375e8025cc8c9c77b616ca6502200bc2c019059622df3c88e7caa6dd7d1fb9b956010aa0de2ee2b9f7dd0a3c4954:4a3eb6b4988d95847d4203be25ed1d46
-112
View File
@@ -1,112 +0,0 @@
package httpapi
import (
"encoding/json"
"net/http"
"time"
"github.com/projectdiscovery/nuclei/v3/pkg/js/compiler"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
)
type Concurrency struct {
BulkSize int `json:"bulk_size"`
Threads int `json:"threads"`
RateLimit int `json:"rate_limit"`
RateLimitDuration string `json:"rate_limit_duration"`
PayloadConcurrency int `json:"payload_concurrency"`
ProbeConcurrency int `json:"probe_concurrency"`
JavascriptConcurrency int `json:"javascript_concurrency"`
}
// Server represents the HTTP server that handles the concurrency settings endpoints.
type Server struct {
addr string
config *types.Options
}
// New creates a new instance of Server.
func New(addr string, config *types.Options) *Server {
return &Server{
addr: addr,
config: config,
}
}
// Start initializes the server and its routes, then starts listening on the specified address.
func (s *Server) Start() error {
http.HandleFunc("/api/concurrency", s.handleConcurrency)
if err := http.ListenAndServe(s.addr, nil); err != nil {
return err
}
return nil
}
// handleConcurrency routes the request based on its method to the appropriate handler.
func (s *Server) handleConcurrency(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
s.getSettings(w, r)
case http.MethodPut:
s.updateSettings(w, r)
default:
http.Error(w, "Unsupported HTTP method", http.StatusMethodNotAllowed)
}
}
// GetSettings handles GET requests and returns the current concurrency settings
func (s *Server) getSettings(w http.ResponseWriter, _ *http.Request) {
concurrencySettings := Concurrency{
BulkSize: s.config.BulkSize,
Threads: s.config.TemplateThreads,
RateLimit: s.config.RateLimit,
RateLimitDuration: s.config.RateLimitDuration.String(),
PayloadConcurrency: s.config.PayloadConcurrency,
ProbeConcurrency: s.config.ProbeConcurrency,
JavascriptConcurrency: compiler.PoolingJsVmConcurrency,
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(concurrencySettings); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// UpdateSettings handles PUT requests to update the concurrency settings
func (s *Server) updateSettings(w http.ResponseWriter, r *http.Request) {
var newSettings Concurrency
if err := json.NewDecoder(r.Body).Decode(&newSettings); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if newSettings.RateLimitDuration != "" {
if duration, err := time.ParseDuration(newSettings.RateLimitDuration); err == nil {
s.config.RateLimitDuration = duration
} else {
http.Error(w, "Invalid duration format", http.StatusBadRequest)
return
}
}
if newSettings.BulkSize > 0 {
s.config.BulkSize = newSettings.BulkSize
}
if newSettings.Threads > 0 {
s.config.TemplateThreads = newSettings.Threads
}
if newSettings.RateLimit > 0 {
s.config.RateLimit = newSettings.RateLimit
}
if newSettings.PayloadConcurrency > 0 {
s.config.PayloadConcurrency = newSettings.PayloadConcurrency
}
if newSettings.ProbeConcurrency > 0 {
s.config.ProbeConcurrency = newSettings.ProbeConcurrency
}
if newSettings.JavascriptConcurrency > 0 {
compiler.PoolingJsVmConcurrency = newSettings.JavascriptConcurrency
s.config.JsConcurrency = newSettings.JavascriptConcurrency // no-op on speed change
}
w.WriteHeader(http.StatusOK)
}
+1 -9
View File
@@ -5,17 +5,9 @@ import (
urlutil "github.com/projectdiscovery/utils/url"
)
func getScanDashBoardURL(id string, teamID string) string {
func getScanDashBoardURL(id string) string {
ux, _ := urlutil.Parse(pdcpauth.DashBoardURL)
ux.Path = "/scans/" + id
if ux.Params == nil {
ux.Params = urlutil.NewOrderedParams()
}
if teamID != "" {
ux.Params.Add("team_id", teamID)
} else {
ux.Params.Add("team_id", NoneTeamID)
}
ux.Update()
return ux.String()
}
+10 -50
View File
@@ -9,7 +9,6 @@ import (
"io"
"net/http"
"net/url"
"regexp"
"sync/atomic"
"time"
@@ -18,9 +17,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/retryablehttp-go"
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
"github.com/projectdiscovery/utils/env"
errorutil "github.com/projectdiscovery/utils/errors"
unitutils "github.com/projectdiscovery/utils/unit"
updateutils "github.com/projectdiscovery/utils/update"
urlutil "github.com/projectdiscovery/utils/url"
)
@@ -28,19 +25,11 @@ import (
const (
uploadEndpoint = "/v1/scans/import"
appendEndpoint = "/v1/scans/%s/import"
flushTimer = time.Minute
MaxChunkSize = 4 * unitutils.Mega // 4 MB
xidRe = `^[a-z0-9]{20}$`
teamIDHeader = "X-Team-Id"
NoneTeamID = "none"
flushTimer = time.Duration(1) * time.Minute
MaxChunkSize = 1024 * 1024 * 4 // 4 MB
)
var (
xidRegex = regexp.MustCompile(xidRe)
_ output.Writer = &UploadWriter{}
// teamID if given
TeamIDEnv = env.GetEnvOrDefault("PDCP_TEAM_ID", NoneTeamID)
)
var _ output.Writer = &UploadWriter{}
// UploadWriter is a writer that uploads its output to pdcp
// server to enable web dashboard and more
@@ -52,9 +41,7 @@ type UploadWriter struct {
cancel context.CancelFunc
done chan struct{}
scanID string
scanName string
counter atomic.Int32
TeamID string
}
// NewUploadWriter creates a new upload writer
@@ -63,9 +50,8 @@ func NewUploadWriter(ctx context.Context, creds *pdcpauth.PDCPCredentials) (*Upl
return nil, fmt.Errorf("no credentials provided")
}
u := &UploadWriter{
creds: creds,
done: make(chan struct{}, 1),
TeamID: NoneTeamID,
creds: creds,
done: make(chan struct{}, 1),
}
var err error
reader, writer := io.Pipe()
@@ -100,25 +86,8 @@ func NewUploadWriter(ctx context.Context, creds *pdcpauth.PDCPCredentials) (*Upl
}
// SetScanID sets the scan id for the upload writer
func (u *UploadWriter) SetScanID(id string) error {
if !xidRegex.MatchString(id) {
return fmt.Errorf("invalid scan id provided")
}
func (u *UploadWriter) SetScanID(id string) {
u.scanID = id
return nil
}
// SetScanName sets the scan name for the upload writer
func (u *UploadWriter) SetScanName(name string) {
u.scanName = name
}
func (u *UploadWriter) SetTeamID(id string) {
if id == "" {
u.TeamID = NoneTeamID
} else {
u.TeamID = id
}
}
func (u *UploadWriter) autoCommit(ctx context.Context, r *io.PipeReader) {
@@ -147,13 +116,13 @@ func (u *UploadWriter) autoCommit(ctx context.Context, r *io.PipeReader) {
if u.scanID == "" {
gologger.Verbose().Msgf("Scan results upload to cloud skipped, no results found to upload")
} else {
gologger.Info().Msgf("%v Scan results uploaded to cloud, you can view scan results at %v", u.counter.Load(), getScanDashBoardURL(u.scanID, u.TeamID))
gologger.Info().Msgf("%v Scan results uploaded to cloud, you can view scan results at %v", u.counter.Load(), getScanDashBoardURL(u.scanID))
}
}()
// temporary buffer to store the results
buff := &bytes.Buffer{}
ticker := time.NewTicker(flushTimer)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
@@ -200,7 +169,7 @@ func (u *UploadWriter) uploadChunk(buff *bytes.Buffer) error {
// if successful, reset the buffer
buff.Reset()
// log in verbose mode
gologger.Warning().Msgf("Uploaded results chunk, you can view scan results at %v", getScanDashBoardURL(u.scanID, u.TeamID))
gologger.Warning().Msgf("Uploaded results chunk, you can view scan results at %v", getScanDashBoardURL(u.scanID))
return nil
}
@@ -251,17 +220,8 @@ func (u *UploadWriter) getRequest(bin []byte) (*retryablehttp.Request, error) {
return nil, errorutil.NewWithErr(err).Msgf("could not create cloud upload request")
}
// add pdtm meta params
req.URL.Params.Merge(updateutils.GetpdtmParams(config.Version))
// if it is upload endpoint also include name if it exists
if u.scanName != "" && req.URL.Path == uploadEndpoint {
req.URL.Params.Add("name", u.scanName)
}
req.URL.Update()
req.URL.RawQuery = updateutils.GetpdtmParams(config.Version)
req.Header.Set(pdcpauth.ApiKeyHeaderName, u.creds.APIKey)
if u.TeamID != NoneTeamID && u.TeamID != "" {
req.Header.Set(teamIDHeader, u.TeamID)
}
req.Header.Set("Content-Type", "application/octet-stream")
req.Header.Set("Accept", "application/json")
return req, nil
+12 -6
View File
@@ -1,7 +1,6 @@
package runner
import (
"context"
"sync/atomic"
"time"
@@ -17,6 +16,8 @@ import (
syncutil "github.com/projectdiscovery/utils/sync"
)
var GlobalProbeBulkSize = 50
// initializeTemplatesHTTPInput initializes the http form of input
// for any loaded http templates if input is in non-standard format.
func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
@@ -30,6 +31,11 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
}
gologger.Info().Msgf("Running httpx on input host")
var bulkSize = GlobalProbeBulkSize
if r.options.BulkSize > GlobalProbeBulkSize {
bulkSize = r.options.BulkSize
}
httpxOptions := httpx.DefaultOptions
httpxOptions.RetryMax = r.options.Retries
httpxOptions.Timeout = time.Duration(r.options.Timeout) * time.Second
@@ -39,8 +45,10 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
return nil, errors.Wrap(err, "could not create httpx client")
}
shouldFollowGlobalProbeBulkSize := bulkSize == GlobalProbeBulkSize
// Probe the non-standard URLs and store them in cache
swg, err := syncutil.New(syncutil.WithSize(r.options.BulkSize))
swg, err := syncutil.New(syncutil.WithSize(bulkSize))
if err != nil {
return nil, errors.Wrap(err, "could not create adaptive group")
}
@@ -50,10 +58,8 @@ func (r *Runner) initializeTemplatesHTTPInput() (*hybrid.HybridMap, error) {
return true
}
if r.options.ProbeConcurrency > 0 && swg.Size != r.options.ProbeConcurrency {
if err := swg.Resize(context.Background(), r.options.ProbeConcurrency); err != nil {
gologger.Error().Msgf("Could not resize workpool: %s\n", err)
}
if shouldFollowGlobalProbeBulkSize && swg.Size != GlobalProbeBulkSize {
swg.Resize(GlobalProbeBulkSize)
}
swg.Add()
+1 -3
View File
@@ -1,7 +1,6 @@
package runner
import (
"context"
"fmt"
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
@@ -72,8 +71,7 @@ func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret
tmpl := tmpls[0]
// add args to tmpl here
vars := map[string]interface{}{}
mainCtx := context.Background()
ctx := scan.NewScanContext(mainCtx, contextargs.NewWithInput(mainCtx, d.Input))
ctx := scan.NewScanContext(contextargs.NewWithInput(d.Input))
for _, v := range d.Variables {
vars[v.Key] = v.Value
ctx.Input.Add(v.Key, v.Value)
+19 -30
View File
@@ -3,7 +3,6 @@ package runner
import (
"bufio"
"fmt"
"io/fs"
"os"
"path/filepath"
"strconv"
@@ -26,7 +25,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonl"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/markdown"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/sarif"
"github.com/projectdiscovery/nuclei/v3/pkg/templates/extensions"
"github.com/projectdiscovery/nuclei/v3/pkg/testing"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/yaml"
fileutil "github.com/projectdiscovery/utils/file"
@@ -52,6 +51,8 @@ func ConfigureOptions() error {
return nil
}
var proxyServer *testing.ProxyServer
// ParseOptions parses the command line flags provided by a user
func ParseOptions(options *types.Options) {
// Check if stdin pipe was given
@@ -76,31 +77,6 @@ func ParseOptions(options *types.Options) {
}
os.Exit(0)
}
defaultProfilesPath := filepath.Join(config.DefaultConfig.GetTemplateDir(), "profiles")
if options.ListTemplateProfiles {
gologger.Print().Msgf(
"\nListing available %v nuclei template profiles for %v",
config.DefaultConfig.TemplateVersion,
config.DefaultConfig.TemplatesDirectory,
)
templatesRootDir := config.DefaultConfig.GetTemplateDir()
err := filepath.WalkDir(defaultProfilesPath, func(iterItem string, d fs.DirEntry, err error) error {
ext := filepath.Ext(iterItem)
isYaml := ext == extensions.YAML || ext == extensions.YML
if err != nil || d.IsDir() || !isYaml {
return nil
}
if profileRelPath, err := filepath.Rel(templatesRootDir, iterItem); err == nil {
gologger.Print().Msgf("%s (%s)\n", profileRelPath, strings.TrimSuffix(filepath.Base(iterItem), ext))
}
return nil
})
if err != nil {
gologger.Error().Msgf("%s\n", err)
}
os.Exit(0)
}
if options.StoreResponseDir != DefaultDumpTrafficOutputFolder && !options.StoreResponse {
gologger.Debug().Msgf("Store response directory specified, enabling \"store-resp\" flag automatically\n")
options.StoreResponse = true
@@ -110,6 +86,19 @@ func ParseOptions(options *types.Options) {
if err := ValidateOptions(options); err != nil {
gologger.Fatal().Msgf("Program exiting: %s\n", err)
}
if options.AutogenerateTests {
ps, err := testing.NewProxyServer()
if err != nil {
gologger.Fatal().Msgf("Could not create proxy server: %s\n", err)
}
proxyServer = ps
// Add the proxy server to the options
proxyURL := fmt.Sprintf("http://%s", proxyServer.ListenAddr)
options.Proxy = goflags.StringSlice([]string{proxyURL})
types.ProxyURL = proxyURL
gologger.Info().Msgf("Using %s as proxy server for automatic test-generation\n", proxyServer.ListenAddr)
}
// Load the resolvers if user asked for them
loadResolvers(options)
@@ -316,6 +305,9 @@ func createReportingOptions(options *types.Options) (*reporting.Options, error)
// configureOutput configures the output logging levels to be displayed on the screen
func configureOutput(options *types.Options) {
// disable standard logger (ref: https://github.com/golang/go/issues/19895)
defer logutil.DisableDefaultLogger()
if options.NoColor {
gologger.DefaultLogger.SetFormatter(formatter.NewCLI(true))
}
@@ -334,9 +326,6 @@ func configureOutput(options *types.Options) {
if options.Silent {
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
}
// disable standard logger (ref: https://github.com/golang/go/issues/19895)
logutil.DisableDefaultLogger()
}
// loadResolvers loads resolvers from both user-provided flags and file
+173 -84
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
_ "net/http/pprof"
"os"
"path/filepath"
@@ -15,10 +16,10 @@ import (
"github.com/projectdiscovery/nuclei/v3/internal/pdcp"
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/frequency"
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
"github.com/projectdiscovery/nuclei/v3/pkg/loader/parser"
"github.com/projectdiscovery/nuclei/v3/pkg/testing"
"github.com/projectdiscovery/nuclei/v3/pkg/scan/events"
uncoverlib "github.com/projectdiscovery/uncover"
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
@@ -33,7 +34,6 @@ import (
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/internal/colorizer"
"github.com/projectdiscovery/nuclei/v3/internal/httpapi"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
@@ -54,7 +54,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/uncover"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/excludematchers"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"
httpProtocol "github.com/projectdiscovery/nuclei/v3/pkg/protocols/http"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/http/httpclientpool"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting"
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
@@ -75,26 +74,24 @@ var (
// Runner is a client for running the enumeration process.
type Runner struct {
output output.Writer
interactsh *interactsh.Client
options *types.Options
projectFile *projectfile.ProjectFile
catalog catalog.Catalog
progress progress.Progress
colorizer aurora.Aurora
issuesClient reporting.Client
browser *engine.Browser
rateLimiter *ratelimit.Limiter
hostErrors hosterrorscache.CacheInterface
resumeCfg *types.ResumeCfg
pprofServer *http.Server
pdcpUploadErrMsg string
inputProvider provider.InputProvider
fuzzFrequencyCache *frequency.Tracker
output output.Writer
interactsh *interactsh.Client
options *types.Options
projectFile *projectfile.ProjectFile
catalog catalog.Catalog
progress progress.Progress
colorizer aurora.Aurora
issuesClient reporting.Client
browser *engine.Browser
rateLimiter *ratelimit.Limiter
hostErrors hosterrorscache.CacheInterface
resumeCfg *types.ResumeCfg
pprofServer *http.Server
pdcpUploadErrMsg string
inputProvider provider.InputProvider
//general purpose temporary directory
tmpDir string
parser parser.Parser
httpApiEndpoint *httpapi.Server
tmpDir string
parser parser.Parser
}
const pprofServerAddress = "127.0.0.1:8086"
@@ -226,17 +223,6 @@ func New(options *types.Options) (*Runner, error) {
}()
}
if options.HttpApiEndpoint != "" {
apiServer := httpapi.New(options.HttpApiEndpoint, options)
gologger.Info().Msgf("Listening api endpoint on: %s", options.HttpApiEndpoint)
runner.httpApiEndpoint = apiServer
go func() {
if err := apiServer.Start(); err != nil {
gologger.Error().Msgf("Failed to start API server: %s", err)
}
}()
}
if (len(options.Templates) == 0 || !options.NewTemplates || (options.TargetsFilePath == "" && !options.Stdin && len(options.Targets) == 0)) && options.UpdateTemplates {
os.Exit(0)
}
@@ -361,9 +347,8 @@ func (r *Runner) runStandardEnumeration(executerOpts protocols.ExecutorOptions,
// Close releases all the resources and cleans up
func (r *Runner) Close() {
// dump hosterrors cache
if r.hostErrors != nil {
r.hostErrors.Close()
if proxyServer != nil {
proxyServer.Close()
}
if r.output != nil {
r.output.Close()
@@ -420,14 +405,7 @@ func (r *Runner) setupPDCPUpload(writer output.Writer) output.Writer {
return writer
}
if r.options.ScanID != "" {
// ignore and use empty scan id if invalid
_ = uploadWriter.SetScanID(r.options.ScanID)
}
if r.options.ScanName != "" {
uploadWriter.SetScanName(r.options.ScanName)
}
if r.options.TeamID != "" {
uploadWriter.SetTeamID(r.options.TeamID)
uploadWriter.SetScanID(r.options.ScanID)
}
return output.NewMultiWriter(writer, uploadWriter)
}
@@ -453,31 +431,27 @@ func (r *Runner) RunEnumeration() error {
r.options.ExcludedTemplates = append(r.options.ExcludedTemplates, ignoreFile.Files...)
}
fuzzFreqCache := frequency.New(frequency.DefaultMaxTrackCount, r.options.FuzzParamFrequency)
r.fuzzFrequencyCache = fuzzFreqCache
// Create the executor options which will be used throughout the execution
// stage by the nuclei engine modules.
executorOpts := protocols.ExecutorOptions{
Output: r.output,
Options: r.options,
Progress: r.progress,
Catalog: r.catalog,
IssuesClient: r.issuesClient,
RateLimiter: r.rateLimiter,
Interactsh: r.interactsh,
ProjectFile: r.projectFile,
Browser: r.browser,
Colorizer: r.colorizer,
ResumeCfg: r.resumeCfg,
ExcludeMatchers: excludematchers.New(r.options.ExcludeMatchers),
InputHelper: input.NewHelper(),
TemporaryDirectory: r.tmpDir,
Parser: r.parser,
FuzzParamsFrequency: fuzzFreqCache,
Output: r.output,
Options: r.options,
Progress: r.progress,
Catalog: r.catalog,
IssuesClient: r.issuesClient,
RateLimiter: r.rateLimiter,
Interactsh: r.interactsh,
ProjectFile: r.projectFile,
Browser: r.browser,
Colorizer: r.colorizer,
ResumeCfg: r.resumeCfg,
ExcludeMatchers: excludematchers.New(r.options.ExcludeMatchers),
InputHelper: input.NewHelper(),
TemporaryDirectory: r.tmpDir,
Parser: r.parser,
}
if config.DefaultConfig.IsDebugArgEnabled(config.DebugExportURLPattern) {
if env.GetEnvOrDefault("NUCLEI_ARGS", "") == "req_url_pattern=true" {
// Go StdLib style experimental/debug feature switch
executorOpts.ExportReqURLPattern = true
}
@@ -527,23 +501,6 @@ func (r *Runner) RunEnumeration() error {
return errors.Wrap(err, "Could not create loader.")
}
// list all templates or tags as specified by user.
// This uses a separate parser to reduce time taken as
// normally nuclei does a lot of compilation and stuff
// for templates, which we don't want for these simp
if r.options.TemplateList || r.options.TemplateDisplay || r.options.TagList {
if err := store.LoadTemplatesOnlyMetadata(); err != nil {
return err
}
if r.options.TagList {
r.listAvailableStoreTags(store)
} else {
r.listAvailableStoreTemplates(store)
}
os.Exit(0)
}
if r.options.Validate {
if err := store.ValidateTemplates(); err != nil {
return err
@@ -556,6 +513,14 @@ func (r *Runner) RunEnumeration() error {
return nil // exit
}
store.Load()
if len(store.Templates()) > 1 && r.options.AutogenerateTests {
return errors.New("autogenerate-tests flag can only be used with a single template")
}
if r.inputProvider.Count() > 1 && r.options.AutogenerateTests {
return errors.New("autogenerate-tests flag can only be used with a single input")
}
// TODO: remove below functions after v3 or update warning messages
disk.PrintDeprecatedPathsMsgIfApplicable(r.options.Silent)
templates.PrintDeprecatedProtocolNameMsgIfApplicable(r.options.Silent, r.options.Verbose)
@@ -574,9 +539,26 @@ func (r *Runner) RunEnumeration() error {
_ = r.inputProvider.SetWithExclusions(host)
}
}
// list all templates
if r.options.TemplateList || r.options.TemplateDisplay {
r.listAvailableStoreTemplates(store)
os.Exit(0)
}
// display execution info like version , templates used etc
r.displayExecutionInfo(store)
// If prompted, we need to run the tests for all the loaded
// templates by first trying to detect test definitions and then
// executing them with the relevant inputs.
if r.options.RunNucleiTests {
gologger.Info().Msgf("Running nuclei-templates mock-generated tests")
if err := r.runNucleiTests(store, executorEngine); err != nil {
return errors.Wrap(err, "could not run nuclei tests")
}
return nil
}
// prefetch secrets if enabled
if executorOpts.AuthProvider != nil && r.options.PreFetchSecrets {
gologger.Info().Msgf("Pre-fetching secrets from authprovider[s]")
@@ -619,16 +601,22 @@ func (r *Runner) RunEnumeration() error {
return err
}
var isInteractMatcher bool
if r.interactsh != nil {
matched := r.interactsh.Close()
if matched {
results.CompareAndSwap(false, true)
isInteractMatcher = true
}
}
if r.options.AutogenerateTests && proxyServer != nil {
if err := r.handleTestAutogenerate(results, isInteractMatcher, store); err != nil {
return err
}
}
if executorOpts.InputHelper != nil {
_ = executorOpts.InputHelper.Close()
}
r.fuzzFrequencyCache.Close()
// todo: error propagation without canonical straight error check is required by cloud?
// use safe dereferencing to avoid potential panics in case of previous unchecked errors
@@ -643,6 +631,108 @@ func (r *Runner) RunEnumeration() error {
return err
}
func (r *Runner) runNucleiTests(store *loader.Store, engine *core.Engine) error {
// For each loaded template, check to see if there's
// a corresponding test file for that template with extension
// .nuclei_test
testFiles := make(map[string]string)
templatePathToTemplates := make(map[string]*templates.Template)
for _, template := range store.Templates() {
testFile := fmt.Sprintf("%s.nuclei_test", template.Path)
if !fileutil.FileExists(testFile) {
continue
}
testFiles[template.Path] = testFile
templatePathToTemplates[template.Path] = template
gologger.Verbose().Msgf("Found test file for template %s: %s", template.ID, filepath.Base(testFile))
}
if len(testFiles) == 0 {
gologger.Info().Msgf("No test files found for nuclei-templates")
return nil
}
gologger.Info().Msgf("Loaded %d test files for nuclei-templates", len(testFiles))
for templatePath, testFile := range testFiles {
testTemplate, err := testing.ReadNucleiTestTemplate(testFile)
if err != nil {
return errors.Wrap(err, "could not read nuclei test template")
}
mockHandler, err := testTemplate.MockServer()
if err != nil {
return errors.Wrap(err, "could not create mock handler for template")
}
testServer := httptest.NewServer(mockHandler)
template, ok := templatePathToTemplates[templatePath]
if !ok {
testServer.Close()
return errors.Errorf("no template found for path %s", templatePath)
}
// If we have interactsh matcher, we need to handle it separately
// by creating a new interactsh client and closing it after the test
// waiting for callbacks.
// TODO: Parallelize
if testTemplate.IsInteractshMatcher {
interactClient, err := interactsh.New(interactsh.DefaultOptions(r.output, r.issuesClient, r.progress))
if err != nil {
testServer.Close()
return errors.Wrap(err, "could not create interactsh client")
}
template.Options.Interactsh = interactClient
}
results := engine.ExecuteScanWithOpts([]*templates.Template{template}, provider.NewSimpleInputProviderWithUrls(testServer.URL), r.options.DisableClustering)
if !results.Load() && !testTemplate.IsInteractshMatcher {
testServer.Close()
return errors.Errorf("no results found for template %s", template.ID)
}
if testTemplate.IsInteractshMatcher {
matched := template.Options.Interactsh.Close()
if !matched {
testServer.Close()
return errors.Errorf("no results found for template %s", template.ID)
}
}
}
gologger.Info().Msgf("All tests passed successfully")
return nil
}
func (r *Runner) handleTestAutogenerate(results *atomic.Bool, isInteractMatcher bool, store *loader.Store) error {
if !results.Load() {
return errors.New("no results found to autogenerate tests")
}
intercepted := proxyServer.Intercepted()
if len(intercepted) == 0 {
return errors.New("no intercepted requests")
}
gologger.Verbose().Msgf("Intercepted requests and responses (%d)", len(intercepted))
for _, pair := range intercepted {
if r.options.Debug {
fmt.Printf("Pair: %+v\n", pair)
}
}
var gotInput string
r.inputProvider.Iterate(func(value *contextargs.MetaInput) bool {
gotInput = value.Input
return false
})
err := testing.GenerateTestsFromPair(intercepted, store.Templates()[0], gotInput, isInteractMatcher)
if err != nil {
return errors.Wrap(err, "could not generate tests from intercepted requests")
}
return nil
}
func (r *Runner) isInputNonHTTP() bool {
var nonURLInput bool
r.inputProvider.Iterate(func(value *contextargs.MetaInput) bool {
@@ -698,7 +788,7 @@ func (r *Runner) executeTemplatesInput(store *loader.Store, engine *core.Engine)
if r.inputProvider == nil {
return nil, errors.New("no input provider found")
}
results := engine.ExecuteScanWithOpts(context.Background(), finalTemplates, r.inputProvider, r.options.DisableClustering)
results := engine.ExecuteScanWithOpts(finalTemplates, r.inputProvider, r.options.DisableClustering)
return results, nil
}
@@ -727,7 +817,6 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
} else {
stats.DisplayAsWarning(templates.SkippedCodeTmplTamperedStats)
}
stats.DisplayAsWarning(httpProtocol.SetThreadToCountZero)
stats.ForceDisplayWarning(templates.SkippedUnsignedStats)
stats.ForceDisplayWarning(templates.SkippedRequestSignatureStats)
-36
View File
@@ -3,11 +3,9 @@ package runner
import (
"bytes"
"path/filepath"
"sort"
"strings"
"github.com/alecthomas/chroma/quick"
jsoniter "github.com/json-iterator/go"
"github.com/logrusorgru/aurora"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
@@ -73,40 +71,6 @@ func (r *Runner) listAvailableStoreTemplates(store *loader.Store) {
}
}
func (r *Runner) listAvailableStoreTags(store *loader.Store) {
gologger.Print().Msgf(
"\nListing available %v nuclei tags for %v",
config.DefaultConfig.TemplateVersion,
config.DefaultConfig.TemplatesDirectory,
)
tagsMap := make(map[string]int)
for _, tpl := range store.Templates() {
for _, tag := range tpl.Info.Tags.ToSlice() {
tagsMap[tag]++
}
}
type kv struct {
Key string `json:"tag"`
Value int `json:"count"`
}
var tagsList []kv
for k, v := range tagsMap {
tagsList = append(tagsList, kv{k, v})
}
sort.Slice(tagsList, func(i, j int) bool {
return tagsList[i].Value > tagsList[j].Value
})
for _, tag := range tagsList {
if r.options.JSONL {
marshalled, _ := jsoniter.Marshal(tag)
gologger.Silent().Msgf("%s\n", string(marshalled))
} else {
gologger.Silent().Msgf("%s (%d)\n", tag.Key, tag.Value)
}
}
}
func (r *Runner) highlightTemplate(body *[]byte) ([]byte, error) {
var buf bytes.Buffer
// YAML lexer, true color terminal formatter and monokai style
+2 -26
View File
@@ -10,7 +10,6 @@ import (
"github.com/projectdiscovery/ratelimit"
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/progress"
@@ -164,17 +163,11 @@ func WithConcurrency(opts Concurrency) NucleiSDKOptions {
}
// WithGlobalRateLimit sets global rate (i.e all hosts combined) limit options
// Deprecated: will be removed in favour of WithGlobalRateLimitCtx in next release
func WithGlobalRateLimit(maxTokens int, duration time.Duration) NucleiSDKOptions {
return WithGlobalRateLimitCtx(context.Background(), maxTokens, duration)
}
// WithGlobalRateLimitCtx allows setting a global rate limit for the entire engine
func WithGlobalRateLimitCtx(ctx context.Context, maxTokens int, duration time.Duration) NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.opts.RateLimit = maxTokens
e.opts.RateLimitDuration = duration
e.rateLimiter = ratelimit.New(ctx, uint(e.opts.RateLimit), e.opts.RateLimitDuration)
e.rateLimiter = ratelimit.New(context.Background(), uint(e.opts.RateLimit), e.opts.RateLimitDuration)
return nil
}
}
@@ -396,12 +389,11 @@ func WithHeaders(headers []string) NucleiSDKOptions {
func EnablePassiveMode() NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.opts.OfflineHTTP = true
e.opts.DisableHTTPProbe = true
return nil
}
}
// WithAuthProvider allows setting a custom authprovider implementation
// WithAuthOptions allows setting a custom authprovider implementation
func WithAuthProvider(provider authprovider.AuthProvider) NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.authprovider = provider
@@ -433,19 +425,3 @@ func SignedTemplatesOnly() NucleiSDKOptions {
return nil
}
}
// WithCatalog uses a supplied catalog
func WithCatalog(cat catalog.Catalog) NucleiSDKOptions {
return func(e *NucleiEngine) error {
e.catalog = cat
return nil
}
}
// DisableUpdateCheck disables nuclei update check
func DisableUpdateCheck() NucleiSDKOptions {
return func(e *NucleiEngine) error {
DefaultConfig.DisableUpdateCheck()
return nil
}
}
+1 -1
View File
@@ -82,5 +82,5 @@ func TestMain(m *testing.M) {
// no need to run this test on github actions
return
}
os.Exit(m.Run())
m.Run()
}
+9 -39
View File
@@ -26,7 +26,7 @@ type unsafeOptions struct {
}
// createEphemeralObjects creates ephemeral nuclei objects/instances/types
func createEphemeralObjects(ctx context.Context, base *NucleiEngine, opts *types.Options) (*unsafeOptions, error) {
func createEphemeralObjects(base *NucleiEngine, opts *types.Options) (*unsafeOptions, error) {
u := &unsafeOptions{}
u.executerOpts = protocols.ExecutorOptions{
Output: base.customWriter,
@@ -49,31 +49,15 @@ func createEphemeralObjects(ctx context.Context, base *NucleiEngine, opts *types
opts.RateLimitDuration = time.Second
}
if opts.RateLimit == 0 && opts.RateLimitDuration == 0 {
u.executerOpts.RateLimiter = ratelimit.NewUnlimited(ctx)
u.executerOpts.RateLimiter = ratelimit.NewUnlimited(context.Background())
} else {
u.executerOpts.RateLimiter = ratelimit.New(ctx, uint(opts.RateLimit), opts.RateLimitDuration)
u.executerOpts.RateLimiter = ratelimit.New(context.Background(), uint(opts.RateLimit), opts.RateLimitDuration)
}
u.engine = core.New(opts)
u.engine.SetExecuterOptions(u.executerOpts)
return u, nil
}
// closeEphemeralObjects closes all resources used by ephemeral nuclei objects/instances/types
func closeEphemeralObjects(u *unsafeOptions) {
if u.executerOpts.RateLimiter != nil {
u.executerOpts.RateLimiter.Stop()
}
// dereference all objects that were inherited from base nuclei engine
// since these are meant to be closed globally by base nuclei engine
u.executerOpts.Output = nil
u.executerOpts.IssuesClient = nil
u.executerOpts.Interactsh = nil
u.executerOpts.HostErrorsCache = nil
u.executerOpts.Progress = nil
u.executerOpts.Catalog = nil
u.executerOpts.Parser = nil
}
// ThreadSafeNucleiEngine is a tweaked version of nuclei.Engine whose methods are thread-safe
// and can be used concurrently. Non-thread-safe methods start with Global prefix
type ThreadSafeNucleiEngine struct {
@@ -83,7 +67,7 @@ type ThreadSafeNucleiEngine struct {
// NewThreadSafeNucleiEngine creates a new nuclei engine with given options
// whose methods are thread-safe and can be used concurrently
// Note: Non-thread-safe methods start with Global prefix
func NewThreadSafeNucleiEngineCtx(ctx context.Context, opts ...NucleiSDKOptions) (*ThreadSafeNucleiEngine, error) {
func NewThreadSafeNucleiEngine(opts ...NucleiSDKOptions) (*ThreadSafeNucleiEngine, error) {
// default options
e := &NucleiEngine{
opts: types.DefaultOptions(),
@@ -94,17 +78,12 @@ func NewThreadSafeNucleiEngineCtx(ctx context.Context, opts ...NucleiSDKOptions)
return nil, err
}
}
if err := e.init(ctx); err != nil {
if err := e.init(); err != nil {
return nil, err
}
return &ThreadSafeNucleiEngine{eng: e}, nil
}
// Deprecated: use NewThreadSafeNucleiEngineCtx instead
func NewThreadSafeNucleiEngine(opts ...NucleiSDKOptions) (*ThreadSafeNucleiEngine, error) {
return NewThreadSafeNucleiEngineCtx(context.Background(), opts...)
}
// GlobalLoadAllTemplates loads all templates from nuclei-templates repo
// This method will load all templates based on filters given at the time of nuclei engine creation in opts
func (e *ThreadSafeNucleiEngine) GlobalLoadAllTemplates() error {
@@ -116,11 +95,11 @@ func (e *ThreadSafeNucleiEngine) GlobalResultCallback(callback func(event *outpu
e.eng.resultCallbacks = []func(*output.ResultEvent){callback}
}
// ExecuteNucleiWithOptsCtx executes templates on targets and calls callback on each result(only if results are found)
// ExecuteWithCallback executes templates on targets and calls callback on each result(only if results are found)
// This method can be called concurrently and it will use some global resources but can be runned parallelly
// by invoking this method with different options and targets
// Note: Not all options are thread-safe. this method will throw error if you try to use non-thread-safe options
func (e *ThreadSafeNucleiEngine) ExecuteNucleiWithOptsCtx(ctx context.Context, targets []string, opts ...NucleiSDKOptions) error {
func (e *ThreadSafeNucleiEngine) ExecuteNucleiWithOpts(targets []string, opts ...NucleiSDKOptions) error {
baseOpts := *e.eng.opts
tmpEngine := &NucleiEngine{opts: &baseOpts, mode: threadSafe}
for _, option := range opts {
@@ -128,14 +107,11 @@ func (e *ThreadSafeNucleiEngine) ExecuteNucleiWithOptsCtx(ctx context.Context, t
return err
}
}
// create ephemeral nuclei objects/instances/types using base nuclei engine
unsafeOpts, err := createEphemeralObjects(ctx, e.eng, tmpEngine.opts)
unsafeOpts, err := createEphemeralObjects(e.eng, tmpEngine.opts)
if err != nil {
return err
}
// cleanup and stop all resources
defer closeEphemeralObjects(unsafeOpts)
// load templates
workflowLoader, err := workflow.NewLoader(&unsafeOpts.executerOpts)
@@ -162,18 +138,12 @@ func (e *ThreadSafeNucleiEngine) ExecuteNucleiWithOptsCtx(ctx context.Context, t
engine := core.New(tmpEngine.opts)
engine.SetExecuterOptions(unsafeOpts.executerOpts)
_ = engine.ExecuteScanWithOpts(ctx, store.Templates(), inputProvider, false)
_ = engine.ExecuteScanWithOpts(store.Templates(), inputProvider, false)
engine.WorkPool().Wait()
return nil
}
// ExecuteNucleiWithOpts is same as ExecuteNucleiWithOptsCtx but with default context
// This is a placeholder and will be deprecated in future major release
func (e *ThreadSafeNucleiEngine) ExecuteNucleiWithOpts(targets []string, opts ...NucleiSDKOptions) error {
return e.ExecuteNucleiWithOptsCtx(context.Background(), targets, opts...)
}
// Close all resources used by nuclei engine
func (e *ThreadSafeNucleiEngine) Close() {
e.eng.Close()
+14 -66
View File
@@ -3,11 +3,10 @@ package nuclei
import (
"bufio"
"bytes"
"context"
"io"
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
@@ -18,7 +17,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"
"github.com/projectdiscovery/nuclei/v3/pkg/reporting"
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
@@ -65,7 +63,7 @@ type NucleiEngine struct {
// unexported core fields
interactshClient *interactsh.Client
catalog catalog.Catalog
catalog *disk.DiskCatalog
rateLimiter *ratelimit.Limiter
store *loader.Store
httpxClient providerTypes.InputLivenessProbe
@@ -178,54 +176,22 @@ func (e *NucleiEngine) SignTemplate(tmplSigner *signer.TemplateSigner, data []by
if err != nil {
return data, err
}
_, content := signer.ExtractSignatureAndContent(data)
buff := bytes.NewBuffer(content)
buff := bytes.NewBuffer(signer.RemoveSignatureFromData(data))
buff.WriteString("\n" + signatureData)
return buff.Bytes(), err
}
func (e *NucleiEngine) closeInternal() {
if e.interactshClient != nil {
e.interactshClient.Close()
}
if e.rc != nil {
e.rc.Close()
}
if e.customWriter != nil {
e.customWriter.Close()
}
if e.customProgress != nil {
e.customProgress.Stop()
}
if e.hostErrCache != nil {
e.hostErrCache.Close()
}
if e.executerOpts.RateLimiter != nil {
e.executerOpts.RateLimiter.Stop()
}
if e.rateLimiter != nil {
e.rateLimiter.Stop()
}
if e.inputProvider != nil {
e.inputProvider.Close()
}
if e.browserInstance != nil {
e.browserInstance.Close()
}
if e.httpxClient != nil {
_ = e.httpxClient.Close()
}
}
// Close all resources used by nuclei engine
func (e *NucleiEngine) Close() {
e.closeInternal()
protocolinit.Close()
e.interactshClient.Close()
e.rc.Close()
e.customWriter.Close()
e.hostErrCache.Close()
e.executerOpts.RateLimiter.Stop()
}
// ExecuteCallbackWithCtx executes templates on targets and calls callback on each result(only if results are found)
// enable matcher-status option if you expect this callback to be called for all results regardless if it matched or not
func (e *NucleiEngine) ExecuteCallbackWithCtx(ctx context.Context, callback ...func(event *output.ResultEvent)) error {
// ExecuteWithCallback executes templates on targets and calls callback on each result(only if results are found)
func (e *NucleiEngine) ExecuteWithCallback(callback ...func(event *output.ResultEvent)) error {
if !e.templatesLoaded {
_ = e.LoadAllTemplates()
}
@@ -244,34 +210,21 @@ func (e *NucleiEngine) ExecuteCallbackWithCtx(ctx context.Context, callback ...f
}
e.resultCallbacks = append(e.resultCallbacks, filtered...)
templatesAndWorkflows := append(e.store.Templates(), e.store.Workflows()...)
if len(templatesAndWorkflows) == 0 {
return ErrNoTemplatesAvailable
}
_ = e.engine.ExecuteScanWithOpts(ctx, templatesAndWorkflows, e.inputProvider, false)
_ = e.engine.ExecuteScanWithOpts(e.store.Templates(), e.inputProvider, false)
defer e.engine.WorkPool().Wait()
return nil
}
// ExecuteWithCallback is same as ExecuteCallbackWithCtx but with default context
// Note this is deprecated and will be removed in future major release
func (e *NucleiEngine) ExecuteWithCallback(callback ...func(event *output.ResultEvent)) error {
return e.ExecuteCallbackWithCtx(context.Background(), callback...)
}
// Options return nuclei Type Options
func (e *NucleiEngine) Options() *types.Options {
return e.opts
}
// Engine returns core Executer of nuclei
func (e *NucleiEngine) Engine() *core.Engine {
return e.engine
}
// NewNucleiEngineCtx creates a new nuclei engine instance with given context
func NewNucleiEngineCtx(ctx context.Context, options ...NucleiSDKOptions) (*NucleiEngine, error) {
// NewNucleiEngine creates a new nuclei engine instance
func NewNucleiEngine(options ...NucleiSDKOptions) (*NucleiEngine, error) {
// default options
e := &NucleiEngine{
opts: types.DefaultOptions(),
@@ -282,13 +235,8 @@ func NewNucleiEngineCtx(ctx context.Context, options ...NucleiSDKOptions) (*Nucl
return nil, err
}
}
if err := e.init(ctx); err != nil {
if err := e.init(); err != nil {
return nil, err
}
return e, nil
}
// Deprecated: use NewNucleiEngineCtx instead
func NewNucleiEngine(options ...NucleiSDKOptions) (*NucleiEngine, error) {
return NewNucleiEngineCtx(context.Background(), options...)
}
+10 -23
View File
@@ -35,10 +35,8 @@ import (
"github.com/projectdiscovery/ratelimit"
)
var sharedInit *sync.Once
// applyRequiredDefaults to options
func (e *NucleiEngine) applyRequiredDefaults(ctx context.Context) {
func (e *NucleiEngine) applyRequiredDefaults() {
mockoutput := testutils.NewMockOutputWriter(e.opts.OmitTemplate)
mockoutput.WriteCallback = func(event *output.ResultEvent) {
if len(e.resultCallbacks) > 0 {
@@ -82,7 +80,7 @@ func (e *NucleiEngine) applyRequiredDefaults(ctx context.Context) {
e.interactshOpts = interactsh.DefaultOptions(e.customWriter, e.rc, e.customProgress)
}
if e.rateLimiter == nil {
e.rateLimiter = ratelimit.New(ctx, 150, time.Second)
e.rateLimiter = ratelimit.New(context.Background(), 150, time.Second)
}
if e.opts.ExcludeTags == nil {
e.opts.ExcludeTags = []string{}
@@ -95,7 +93,7 @@ func (e *NucleiEngine) applyRequiredDefaults(ctx context.Context) {
}
// init
func (e *NucleiEngine) init(ctx context.Context) error {
func (e *NucleiEngine) init() error {
if e.opts.Verbose {
gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
} else if e.opts.Debug {
@@ -118,15 +116,9 @@ func (e *NucleiEngine) init(ctx context.Context) error {
e.parser = templates.NewParser()
if sharedInit == nil || protocolstate.ShouldInit() {
sharedInit = &sync.Once{}
}
sharedInit.Do(func() {
_ = protocolinit.Init(e.opts)
})
e.applyRequiredDefaults(ctx)
_ = protocolstate.Init(e.opts)
_ = protocolinit.Init(e.opts)
e.applyRequiredDefaults()
var err error
// setup progressbar
@@ -154,9 +146,7 @@ func (e *NucleiEngine) init(ctx context.Context) error {
return err
}
if e.catalog == nil {
e.catalog = disk.NewCatalog(config.DefaultConfig.TemplatesDirectory)
}
e.catalog = disk.NewCatalog(config.DefaultConfig.TemplatesDirectory)
e.executerOpts = protocols.ExecutorOptions{
Output: e.customWriter,
@@ -209,9 +199,9 @@ func (e *NucleiEngine) init(ctx context.Context) error {
e.opts.RateLimitDuration = time.Second
}
if e.opts.RateLimit == 0 && e.opts.RateLimitDuration == 0 {
e.executerOpts.RateLimiter = ratelimit.NewUnlimited(ctx)
e.executerOpts.RateLimiter = ratelimit.NewUnlimited(context.Background())
} else {
e.executerOpts.RateLimiter = ratelimit.New(ctx, uint(e.opts.RateLimit), e.opts.RateLimitDuration)
e.executerOpts.RateLimiter = ratelimit.New(context.Background(), uint(e.opts.RateLimit), e.opts.RateLimitDuration)
}
}
@@ -231,10 +221,7 @@ func (e *NucleiEngine) init(ctx context.Context) error {
// and also upgrade templates to latest version if available
installer.NucleiSDKVersionCheck()
if DefaultConfig.CanCheckForUpdates() {
return e.processUpdateCheckResults()
}
return nil
return e.processUpdateCheckResults()
}
type syncOnce struct {
+60
View File
@@ -0,0 +1,60 @@
package nuclei_test
import (
"testing"
nuclei "github.com/projectdiscovery/nuclei/v3/lib"
"github.com/stretchr/testify/require"
)
func TestSimpleNuclei(t *testing.T) {
ne, err := nuclei.NewNucleiEngine(
nuclei.WithTemplateFilters(nuclei.TemplateFilters{ProtocolTypes: "dns"}),
nuclei.EnableStatsWithOpts(nuclei.StatsOptions{JSON: true}),
)
require.Nil(t, err)
ne.LoadTargets([]string{"scanme.sh"}, false) // probe non http/https target is set to false here
// when callback is nil it nuclei will print JSON output to stdout
err = ne.ExecuteWithCallback(nil)
require.Nil(t, err)
defer ne.Close()
}
func TestSimpleNucleiRemote(t *testing.T) {
ne, err := nuclei.NewNucleiEngine(
nuclei.WithTemplatesOrWorkflows(
nuclei.TemplateSources{
RemoteTemplates: []string{"https://cloud.projectdiscovery.io/public/nameserver-fingerprint.yaml"},
},
),
)
require.Nil(t, err)
ne.LoadTargets([]string{"scanme.sh"}, false) // probe non http/https target is set to false here
err = ne.LoadAllTemplates()
require.Nil(t, err, "could not load templates")
// when callback is nil it nuclei will print JSON output to stdout
err = ne.ExecuteWithCallback(nil)
require.Nil(t, err)
defer ne.Close()
}
func TestThreadSafeNuclei(t *testing.T) {
// create nuclei engine with options
ne, err := nuclei.NewThreadSafeNucleiEngine()
require.Nil(t, err)
// scan 1 = run dns templates on scanme.sh
t.Run("scanme.sh", func(t *testing.T) {
err = ne.ExecuteNucleiWithOpts([]string{"scanme.sh"}, nuclei.WithTemplateFilters(nuclei.TemplateFilters{ProtocolTypes: "dns"}))
require.Nil(t, err)
})
// scan 2 = run dns templates on honey.scanme.sh
t.Run("honey.scanme.sh", func(t *testing.T) {
err = ne.ExecuteNucleiWithOpts([]string{"honey.scanme.sh"}, nuclei.WithTemplateFilters(nuclei.TemplateFilters{ProtocolTypes: "dns"}))
require.Nil(t, err)
})
// wait for all scans to finish
defer ne.Close()
}
-135
View File
@@ -1,135 +0,0 @@
package sdk_test
import (
"context"
"os"
"os/exec"
"testing"
"time"
nuclei "github.com/projectdiscovery/nuclei/v3/lib"
"github.com/projectdiscovery/utils/env"
"github.com/stretchr/testify/require"
"github.com/tarunKoyalwar/goleak"
)
var knownLeaks = []goleak.Option{
// prettyify the output and generate dependency graph and more details instead of just stack output
goleak.Pretty(),
// net/http transport maintains idle connections which are closed with cooldown
// hence they don't count as leaks
goleak.IgnoreAnyFunction("net/http.(*http2ClientConn).readLoop"),
}
func TestSimpleNuclei(t *testing.T) {
fn := func() {
defer func() {
// resources like leveldb have a delay to commit in-memory resources
// to disk, typically 1-2 seconds, so we wait for 2 seconds
time.Sleep(2 * time.Second)
goleak.VerifyNone(t, knownLeaks...)
}()
ne, err := nuclei.NewNucleiEngineCtx(
context.TODO(),
nuclei.WithTemplateFilters(nuclei.TemplateFilters{ProtocolTypes: "dns"}), // filter dns templates
nuclei.EnableStatsWithOpts(nuclei.StatsOptions{JSON: true}),
)
require.Nil(t, err)
ne.LoadTargets([]string{"scanme.sh"}, false) // probe non http/https target is set to false here
// when callback is nil it nuclei will print JSON output to stdout
err = ne.ExecuteWithCallback(nil)
require.Nil(t, err)
defer ne.Close()
}
// this is shared test so needs to be run as seperate process
if env.GetEnvOrDefault("TestSimpleNuclei", false) {
// run as new process
cmd := exec.Command(os.Args[0], "-test.run=TestSimpleNuclei")
cmd.Env = append(os.Environ(), "TestSimpleNuclei=true")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("process ran with error %s, output: %s", err, out)
}
} else {
fn()
}
}
func TestSimpleNucleiRemote(t *testing.T) {
fn := func() {
defer func() {
// resources like leveldb have a delay to commit in-memory resources
// to disk, typically 1-2 seconds, so we wait for 2 seconds
time.Sleep(2 * time.Second)
goleak.VerifyNone(t, knownLeaks...)
}()
ne, err := nuclei.NewNucleiEngineCtx(
context.TODO(),
nuclei.WithTemplatesOrWorkflows(
nuclei.TemplateSources{
RemoteTemplates: []string{"https://cloud.projectdiscovery.io/public/nameserver-fingerprint.yaml"},
},
),
)
require.Nil(t, err)
ne.LoadTargets([]string{"scanme.sh"}, false) // probe non http/https target is set to false here
err = ne.LoadAllTemplates()
require.Nil(t, err, "could not load templates")
// when callback is nil it nuclei will print JSON output to stdout
err = ne.ExecuteWithCallback(nil)
require.Nil(t, err)
defer ne.Close()
}
// this is shared test so needs to be run as seperate process
if env.GetEnvOrDefault("TestSimpleNucleiRemote", false) {
cmd := exec.Command(os.Args[0], "-test.run=TestSimpleNucleiRemote")
cmd.Env = append(os.Environ(), "TestSimpleNucleiRemote=true")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("process ran with error %s, output: %s", err, out)
}
} else {
fn()
}
}
func TestThreadSafeNuclei(t *testing.T) {
fn := func() {
defer func() {
// resources like leveldb have a delay to commit in-memory resources
// to disk, typically 1-2 seconds, so we wait for 2 seconds
time.Sleep(2 * time.Second)
goleak.VerifyNone(t, knownLeaks...)
}()
// create nuclei engine with options
ne, err := nuclei.NewThreadSafeNucleiEngineCtx(context.TODO())
require.Nil(t, err)
// scan 1 = run dns templates on scanme.sh
t.Run("scanme.sh", func(t *testing.T) {
err = ne.ExecuteNucleiWithOpts([]string{"scanme.sh"}, nuclei.WithTemplateFilters(nuclei.TemplateFilters{ProtocolTypes: "dns"}))
require.Nil(t, err)
})
// scan 2 = run dns templates on honey.scanme.sh
t.Run("honey.scanme.sh", func(t *testing.T) {
err = ne.ExecuteNucleiWithOpts([]string{"honey.scanme.sh"}, nuclei.WithTemplateFilters(nuclei.TemplateFilters{ProtocolTypes: "dns"}))
require.Nil(t, err)
})
// wait for all scans to finish
defer ne.Close()
}
if env.GetEnvOrDefault("TestThreadSafeNuclei", false) {
cmd := exec.Command(os.Args[0], "-test.run=TestThreadSafeNuclei")
cmd.Env = append(os.Environ(), "TestThreadSafeNuclei=true")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("process ran with error %s, output: %s", err, out)
}
} else {
fn()
}
}
+5 -21
View File
@@ -457,22 +457,6 @@
"title": "part of rule",
"description": "Part of request rule to fuzz"
},
"parts": {
"items": {
"type": "string",
"enum": [
"query",
"header",
"path",
"body",
"cookie",
"request"
]
},
"type": "array",
"title": "parts of rule",
"description": "Part of request rule to fuzz"
},
"mode": {
"type": "string",
"enum": [
@@ -787,11 +771,6 @@
"title": "signature is the http request signature method",
"description": "Signature is the HTTP Request signature Method"
},
"skip-secret-file": {
"type": "boolean",
"title": "bypass secret file",
"description": "Skips the authentication or authorization configured in the secret file"
},
"cookie-reuse": {
"type": "boolean",
"title": "optional cookie reuse enable",
@@ -946,6 +925,11 @@
"title": "code to execute in javascript",
"description": "Executes inline javascript code for the request"
},
"timeout": {
"type": "integer",
"title": "timeout for javascript execution",
"description": "Timeout in seconds is optional timeout for entire javascript script execution"
},
"stop-at-first-match": {
"type": "boolean",
"title": "stop at first match",
+1 -1
View File
@@ -219,7 +219,7 @@ func GetAuthDataFromFile(file string) (*Authx, error) {
return GetAuthDataFromJSON(bin)
}
// GetTemplatePathsFromSecretFile reads the template IDs from the secret file
// GetTemplateIDsFromSecretFile reads the template IDs from the secret file
func GetTemplatePathsFromSecretFile(file string) ([]string, error) {
auth, err := GetAuthDataFromFile(file)
if err != nil {
+32 -49
View File
@@ -16,8 +16,8 @@ import (
type FileAuthProvider struct {
Path string
store *authx.Authx
compiled map[*regexp.Regexp][]authx.AuthStrategy
domains map[string][]authx.AuthStrategy
compiled map[*regexp.Regexp]authx.AuthStrategy
domains map[string]authx.AuthStrategy
}
// NewFileAuthProvider creates a new file based auth provider
@@ -51,36 +51,29 @@ func NewFileAuthProvider(path string, callback authx.LazyFetchSecret) (AuthProvi
// init initializes the file auth provider
func (f *FileAuthProvider) init() {
for _, _secret := range f.store.Secrets {
secret := _secret // allocate copy of pointer
for _, secret := range f.store.Secrets {
if len(secret.DomainsRegex) > 0 {
for _, domain := range secret.DomainsRegex {
if f.compiled == nil {
f.compiled = make(map[*regexp.Regexp][]authx.AuthStrategy)
f.compiled = make(map[*regexp.Regexp]authx.AuthStrategy)
}
compiled, err := regexp.Compile(domain)
if err != nil {
continue
}
if ss, ok := f.compiled[compiled]; ok {
f.compiled[compiled] = append(ss, secret.GetStrategy())
} else {
f.compiled[compiled] = []authx.AuthStrategy{secret.GetStrategy()}
}
f.compiled[compiled] = secret.GetStrategy()
}
}
for _, domain := range secret.Domains {
if f.domains == nil {
f.domains = make(map[string][]authx.AuthStrategy)
f.domains = make(map[string]authx.AuthStrategy)
}
domain = strings.TrimSpace(domain)
domain = strings.TrimSuffix(domain, ":80")
domain = strings.TrimSuffix(domain, ":443")
if ss, ok := f.domains[domain]; ok {
f.domains[domain] = append(ss, secret.GetStrategy())
} else {
f.domains[domain] = []authx.AuthStrategy{secret.GetStrategy()}
f.domains[strings.TrimSpace(domain)] = secret.GetStrategy()
if strings.HasSuffix(domain, ":80") {
f.domains[strings.TrimSuffix(domain, ":80")] = secret.GetStrategy()
}
if strings.HasSuffix(domain, ":443") {
f.domains[strings.TrimSuffix(domain, ":443")] = secret.GetStrategy()
}
}
}
@@ -88,38 +81,32 @@ func (f *FileAuthProvider) init() {
if len(dynamic.DomainsRegex) > 0 {
for _, domain := range dynamic.DomainsRegex {
if f.compiled == nil {
f.compiled = make(map[*regexp.Regexp][]authx.AuthStrategy)
f.compiled = make(map[*regexp.Regexp]authx.AuthStrategy)
}
compiled, err := regexp.Compile(domain)
if err != nil {
continue
}
if ss, ok := f.compiled[compiled]; !ok {
f.compiled[compiled] = []authx.AuthStrategy{&authx.DynamicAuthStrategy{Dynamic: dynamic}}
} else {
f.compiled[compiled] = append(ss, &authx.DynamicAuthStrategy{Dynamic: dynamic})
}
f.compiled[compiled] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
}
}
for _, domain := range dynamic.Domains {
if f.domains == nil {
f.domains = make(map[string][]authx.AuthStrategy)
f.domains = make(map[string]authx.AuthStrategy)
}
domain = strings.TrimSpace(domain)
domain = strings.TrimSuffix(domain, ":80")
domain = strings.TrimSuffix(domain, ":443")
if ss, ok := f.domains[domain]; !ok {
f.domains[domain] = []authx.AuthStrategy{&authx.DynamicAuthStrategy{Dynamic: dynamic}}
} else {
f.domains[domain] = append(ss, &authx.DynamicAuthStrategy{Dynamic: dynamic})
f.domains[strings.TrimSpace(domain)] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
if strings.HasSuffix(domain, ":80") {
f.domains[strings.TrimSuffix(domain, ":80")] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
}
if strings.HasSuffix(domain, ":443") {
f.domains[strings.TrimSuffix(domain, ":443")] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
}
}
}
}
// LookupAddr looks up a given domain/address and returns appropriate auth strategy
func (f *FileAuthProvider) LookupAddr(addr string) []authx.AuthStrategy {
func (f *FileAuthProvider) LookupAddr(addr string) authx.AuthStrategy {
if strings.Contains(addr, ":") {
// default normalization for host:port
host, port, err := net.SplitHostPort(addr)
@@ -141,12 +128,12 @@ func (f *FileAuthProvider) LookupAddr(addr string) []authx.AuthStrategy {
}
// LookupURL looks up a given URL and returns appropriate auth strategy
func (f *FileAuthProvider) LookupURL(u *url.URL) []authx.AuthStrategy {
func (f *FileAuthProvider) LookupURL(u *url.URL) authx.AuthStrategy {
return f.LookupAddr(u.Host)
}
// LookupURLX looks up a given URL and returns appropriate auth strategy
func (f *FileAuthProvider) LookupURLX(u *urlutil.URL) []authx.AuthStrategy {
func (f *FileAuthProvider) LookupURLX(u *urlutil.URL) authx.AuthStrategy {
return f.LookupAddr(u.Host)
}
@@ -163,21 +150,17 @@ func (f *FileAuthProvider) GetTemplatePaths() []string {
// PreFetchSecrets pre-fetches the secrets from the auth provider
func (f *FileAuthProvider) PreFetchSecrets() error {
for _, ss := range f.domains {
for _, s := range ss {
if val, ok := s.(*authx.DynamicAuthStrategy); ok {
if err := val.Dynamic.Fetch(false); err != nil {
return err
}
for _, s := range f.domains {
if val, ok := s.(*authx.DynamicAuthStrategy); ok {
if err := val.Dynamic.Fetch(false); err != nil {
return err
}
}
}
for _, ss := range f.compiled {
for _, s := range ss {
if val, ok := s.(*authx.DynamicAuthStrategy); ok {
if err := val.Dynamic.Fetch(false); err != nil {
return err
}
for _, s := range f.compiled {
if val, ok := s.(*authx.DynamicAuthStrategy); ok {
if err := val.Dynamic.Fetch(false); err != nil {
return err
}
}
}
+3 -3
View File
@@ -22,13 +22,13 @@ var (
type AuthProvider interface {
// LookupAddr looks up a given domain/address and returns appropriate auth strategy
// for it (accepted inputs are scanme.sh or scanme.sh:443)
LookupAddr(string) []authx.AuthStrategy
LookupAddr(string) authx.AuthStrategy
// LookupURL looks up a given URL and returns appropriate auth strategy
// it accepts a valid url struct and returns the auth strategy
LookupURL(*url.URL) []authx.AuthStrategy
LookupURL(*url.URL) authx.AuthStrategy
// LookupURLX looks up a given URL and returns appropriate auth strategy
// it accepts pd url struct (i.e urlutil.URL) and returns the auth strategy
LookupURLX(*urlutil.URL) []authx.AuthStrategy
LookupURLX(*urlutil.URL) authx.AuthStrategy
// GetTemplatePaths returns the template path for the auth provider
// that will be used for dynamic secret fetching
GetTemplatePaths() []string
+3 -3
View File
@@ -19,7 +19,7 @@ func NewMultiAuthProvider(providers ...AuthProvider) AuthProvider {
return &MultiAuthProvider{Providers: providers}
}
func (m *MultiAuthProvider) LookupAddr(host string) []authx.AuthStrategy {
func (m *MultiAuthProvider) LookupAddr(host string) authx.AuthStrategy {
for _, provider := range m.Providers {
strategy := provider.LookupAddr(host)
if strategy != nil {
@@ -29,7 +29,7 @@ func (m *MultiAuthProvider) LookupAddr(host string) []authx.AuthStrategy {
return nil
}
func (m *MultiAuthProvider) LookupURL(u *url.URL) []authx.AuthStrategy {
func (m *MultiAuthProvider) LookupURL(u *url.URL) authx.AuthStrategy {
for _, provider := range m.Providers {
strategy := provider.LookupURL(u)
if strategy != nil {
@@ -39,7 +39,7 @@ func (m *MultiAuthProvider) LookupURL(u *url.URL) []authx.AuthStrategy {
return nil
}
func (m *MultiAuthProvider) LookupURLX(u *urlutil.URL) []authx.AuthStrategy {
func (m *MultiAuthProvider) LookupURLX(u *urlutil.URL) authx.AuthStrategy {
for _, provider := range m.Providers {
strategy := provider.LookupURLX(u)
if strategy != nil {
+1 -11
View File
@@ -31,7 +31,7 @@ const (
CLIConfigFileName = "config.yaml"
ReportingConfigFilename = "reporting-config.yaml"
// Version is the current version of nuclei
Version = `v3.3.1`
Version = `v3.2.4`
// Directory Names of custom templates
CustomS3TemplatesDirName = "s3"
CustomGitHubTemplatesDirName = "github"
@@ -68,13 +68,3 @@ func trimDevIfExists(version string) string {
}
return version
}
// similar to go pattern of enabling debug related features
// we add custom/extra switches for debugging purposes
const (
// DebugArgHostErrorStats is used to print host error stats
// when it is closed
DebugArgHostErrorStats = "host-error-stats"
// DebugExportReqURLPattern is used to export request URL pattern
DebugExportURLPattern = "req-url-pattern"
)
+5 -47
View File
@@ -46,10 +46,9 @@ type Config struct {
LatestNucleiIgnoreHash string `json:"nuclei-latest-ignore-hash,omitempty"`
// internal / unexported fields
disableUpdates bool `json:"-"` // disable updates both version check and template updates
homeDir string `json:"-"` // User Home Directory
configDir string `json:"-"` // Nuclei Global Config Directory
debugArgs []string `json:"-"` // debug args
disableUpdates bool `json:"-"` // disable updates both version check and template updates
homeDir string `json:"-"` // User Home Directory
configDir string `json:"-"` // Nuclei Global Config Directory
}
// IsCustomTemplate determines whether a given template is custom-built or part of the official Nuclei templates.
@@ -167,12 +166,12 @@ func (c *Config) GetTemplateIndexFilePath() string {
return filepath.Join(c.TemplatesDirectory, NucleiTemplatesIndexFileName)
}
// GetChecksumFilePath returns checksum file path of nuclei templates
// GetTemplatesConfigFilePath returns checksum file path of nuclei templates
func (c *Config) GetChecksumFilePath() string {
return filepath.Join(c.TemplatesDirectory, NucleiTemplatesCheckSumFileName)
}
// GetFlagsConfigFilePath returns the nuclei cli config file path
// GetCLIOptsConfigFilePath returns the nuclei cli config file path
func (c *Config) GetFlagsConfigFilePath() string {
return filepath.Join(c.configDir, CLIConfigFileName)
}
@@ -330,46 +329,6 @@ func (c *Config) copyIgnoreFile() {
}
}
// IsDebugArgEnabled checks if debug arg is enabled
// this could be a feature specific to debugging like PPROF or printing stats
// of max host error etc
func (c *Config) IsDebugArgEnabled(arg string) bool {
for _, v := range c.debugArgs {
if v == arg {
return true
}
}
return false
}
// parseDebugArgs from string
func (c *Config) parseDebugArgs(data string) {
// use space as seperator instead of commas
tmp := strings.Fields(data)
for _, v := range tmp {
key := v
value := ""
// if it is key value pair then split it
if strings.Contains(v, "=") {
parts := strings.SplitN(v, "=", 2)
if len(parts) != 2 {
continue
}
key, value = strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
}
if value == "false" || value == "0" {
// if false or disabled then skip
continue
}
switch key {
case DebugArgHostErrorStats:
c.debugArgs = append(c.debugArgs, DebugArgHostErrorStats)
case DebugExportURLPattern:
c.debugArgs = append(c.debugArgs, DebugExportURLPattern)
}
}
}
func init() {
// first attempt to migrate all files from old config directory to new config directory
goflags.AttemptConfigMigration() // regardless how many times this is called it will only migrate once based on condition
@@ -418,7 +377,6 @@ func init() {
// and even if it is changed we don't follow it since it is not expected behavior
// If custom templates are in default locations only then they are loaded while running nuclei
DefaultConfig.SetTemplatesDir(DefaultConfig.TemplatesDirectory)
DefaultConfig.parseDebugArgs(env.GetEnvOrDefault("NUCLEI_ARGS", ""))
}
// Add Default Config adds default when .templates-config.json file is not present
+10 -22
View File
@@ -11,25 +11,17 @@ import (
// DiskCatalog is a template catalog helper implementation based on disk
type DiskCatalog struct {
templatesDirectory string
templatesFS fs.FS // Due to issues with how Go has implemented fs.FS, we'll have to also implement normal os operations, as well. See: https://github.com/golang/go/issues/44279
templatesFS fs.FS // TODO: Refactor to use this
}
// NewCatalog creates a new Catalog structure using provided input items
// using disk based items
func NewCatalog(directory string) *DiskCatalog {
catalog := &DiskCatalog{templatesDirectory: directory}
if directory == "" {
catalog.templatesDirectory = config.DefaultConfig.GetTemplateDir()
}
return catalog
}
// NewFSCatalog creates a new Catalog structure using provided input items
// using the fs.FS as its filesystem.
func NewFSCatalog(fs fs.FS, directory string) *DiskCatalog {
catalog := &DiskCatalog{
templatesDirectory: directory,
templatesFS: fs,
if directory != "" {
catalog.templatesFS = os.DirFS(directory)
} else {
catalog.templatesFS = os.DirFS(config.DefaultConfig.GetTemplateDir())
}
return catalog
}
@@ -37,15 +29,11 @@ func NewFSCatalog(fs fs.FS, directory string) *DiskCatalog {
// OpenFile opens a file and returns an io.ReadCloser to the file.
// It is used to read template and payload files based on catalog responses.
func (d *DiskCatalog) OpenFile(filename string) (io.ReadCloser, error) {
if d.templatesFS == nil {
file, err := os.Open(filename)
if err != nil {
if file, errx := os.Open(BackwardsCompatiblePaths(d.templatesDirectory, filename)); errx == nil {
return file, nil
}
file, err := os.Open(filename)
if err != nil {
if file, errx := os.Open(BackwardsCompatiblePaths(d.templatesDirectory, filename)); errx == nil {
return file, nil
}
return file, err
}
return d.templatesFS.Open(filename)
return file, err
}
+37 -110
View File
@@ -79,21 +79,17 @@ func (c *DiskCatalog) GetTemplatePath(target string) ([]string, error) {
}
// try to handle deprecated template paths
absPath := target
if c.templatesFS == nil {
absPath = BackwardsCompatiblePaths(c.templatesDirectory, target)
if absPath != target && strings.TrimPrefix(absPath, c.templatesDirectory+string(filepath.Separator)) != target {
if config.DefaultConfig.LogAllEvents {
gologger.DefaultLogger.Print().Msgf("[%v] requested Template path %s is deprecated, please update to %s\n", aurora.Yellow("WRN").String(), target, absPath)
}
deprecatedPathsCounter++
absPath := BackwardsCompatiblePaths(c.templatesDirectory, target)
if absPath != target && strings.TrimPrefix(absPath, c.templatesDirectory+string(filepath.Separator)) != target {
if config.DefaultConfig.LogAllEvents {
gologger.DefaultLogger.Print().Msgf("[%v] requested Template path %s is deprecated, please update to %s\n", aurora.Yellow("WRN").String(), target, absPath)
}
deprecatedPathsCounter++
}
var err error
absPath, err = c.convertPathToAbsolute(absPath)
if err != nil {
return nil, errors.Wrapf(err, "could not find template file")
}
absPath, err := c.convertPathToAbsolute(absPath)
if err != nil {
return nil, errors.Wrapf(err, "could not find template file")
}
// Template input is either a file or a directory
@@ -147,60 +143,24 @@ func (c *DiskCatalog) findGlobPathMatches(absPath string, processed map[string]s
if c.templatesDirectory == "" {
templateDir = "./"
}
if c.templatesFS == nil {
matches, _ := fs.Glob(os.DirFS(filepath.Join(templateDir, "http")), inputGlob)
if len(matches) != 0 {
return matches
}
// condition to support network cve related globs
matches, _ = fs.Glob(os.DirFS(filepath.Join(templateDir, "network")), inputGlob)
return matches
} else {
sub, err := fs.Sub(c.templatesFS, filepath.Join(templateDir, "http"))
if err != nil {
return nil
}
matches, _ := fs.Glob(sub, inputGlob)
if len(matches) != 0 {
return matches
}
// condition to support network cve related globs
sub, err = fs.Sub(c.templatesFS, filepath.Join(templateDir, "network"))
if err != nil {
return nil
}
matches, _ = fs.Glob(sub, inputGlob)
matches, _ := fs.Glob(os.DirFS(filepath.Join(templateDir, "http")), inputGlob)
if len(matches) != 0 {
return matches
}
// condition to support network cve related globs
matches, _ = fs.Glob(os.DirFS(filepath.Join(templateDir, "network")), inputGlob)
return matches
}
var matched []string
var matches []string
if c.templatesFS == nil {
var err error
matches, err = filepath.Glob(relPath)
if len(matches) != 0 {
matched = append(matched, matches...)
} else {
matched = append(matched, OldPathsResolver(relPath)...)
}
if err != nil && len(matched) == 0 {
return nil, errors.Errorf("wildcard found, but unable to glob: %s\n", err)
}
matches, err := fs.Glob(c.templatesFS, relPath)
if len(matches) != 0 {
matched = append(matched, matches...)
} else {
var err error
matches, err = fs.Glob(c.templatesFS, relPath)
if len(matches) != 0 {
matched = append(matched, matches...)
} else {
matched = append(matched, OldPathsResolver(relPath)...)
}
if err != nil && len(matched) == 0 {
return nil, errors.Errorf("wildcard found, but unable to glob: %s\n", err)
}
matched = append(matched, OldPathsResolver(relPath)...)
}
if err != nil && len(matched) == 0 {
return nil, errors.Errorf("wildcard found, but unable to glob: %s\n", err)
}
results := make([]string, 0, len(matches))
for _, match := range matches {
@@ -215,23 +175,11 @@ func (c *DiskCatalog) findGlobPathMatches(absPath string, processed map[string]s
// findFileMatches finds if a path is an absolute file. If the path
// is a file, it returns true otherwise false with no errors.
func (c *DiskCatalog) findFileMatches(absPath string, processed map[string]struct{}) (match string, matched bool, err error) {
if c.templatesFS != nil {
absPath = strings.TrimPrefix(absPath, "/")
}
var info fs.File
if c.templatesFS == nil {
info, err = os.Open(absPath)
} else {
info, err = c.templatesFS.Open(absPath)
}
info, err := os.Stat(absPath)
if err != nil {
return "", false, err
}
stat, err := info.Stat()
if err != nil {
return "", false, err
}
if !stat.Mode().IsRegular() {
if !info.Mode().IsRegular() {
return "", false, nil
}
if _, ok := processed[absPath]; !ok {
@@ -244,43 +192,22 @@ func (c *DiskCatalog) findFileMatches(absPath string, processed map[string]struc
// findDirectoryMatches finds matches for templates from a directory
func (c *DiskCatalog) findDirectoryMatches(absPath string, processed map[string]struct{}) ([]string, error) {
var results []string
var err error
if c.templatesFS == nil {
err = filepath.WalkDir(
absPath,
func(path string, d fs.DirEntry, err error) error {
// continue on errors
if err != nil {
return nil
}
if !d.IsDir() && config.GetTemplateFormatFromExt(path) != config.Unknown {
if _, ok := processed[path]; !ok {
results = append(results, path)
processed[path] = struct{}{}
}
}
err := filepath.WalkDir(
absPath,
func(path string, d fs.DirEntry, err error) error {
// continue on errors
if err != nil {
return nil
},
)
} else {
err = fs.WalkDir(
c.templatesFS,
absPath,
func(path string, d fs.DirEntry, err error) error {
// continue on errors
if err != nil {
return nil
}
if !d.IsDir() && config.GetTemplateFormatFromExt(path) != config.Unknown {
if _, ok := processed[path]; !ok {
results = append(results, path)
processed[path] = struct{}{}
}
if !d.IsDir() && config.GetTemplateFormatFromExt(path) != config.Unknown {
if _, ok := processed[path]; !ok {
results = append(results, path)
processed[path] = struct{}{}
}
}
return nil
},
)
}
}
return nil
},
)
return results, err
}
+65 -116
View File
@@ -7,7 +7,6 @@ import (
"os"
"sort"
"strings"
"sync"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
@@ -24,7 +23,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/workflows"
"github.com/projectdiscovery/retryablehttp-go"
errorutil "github.com/projectdiscovery/utils/errors"
sliceutil "github.com/projectdiscovery/utils/slice"
stringsutil "github.com/projectdiscovery/utils/strings"
urlutil "github.com/projectdiscovery/utils/url"
)
@@ -257,46 +255,6 @@ func init() {
templateIDPathMap = make(map[string]string)
}
// LoadTemplatesOnlyMetadata loads only the metadata of the templates
func (store *Store) LoadTemplatesOnlyMetadata() error {
templatePaths, errs := store.config.Catalog.GetTemplatesPath(store.finalTemplates)
store.logErroredTemplates(errs)
filteredTemplatePaths := store.pathFilter.Match(templatePaths)
validPaths := make(map[string]struct{})
for templatePath := range filteredTemplatePaths {
loaded, err := store.config.ExecutorOptions.Parser.LoadTemplate(templatePath, store.tagFilter, nil, store.config.Catalog)
if loaded || store.pathFilter.MatchIncluded(templatePath) {
validPaths[templatePath] = struct{}{}
}
if err != nil {
if strings.Contains(err.Error(), templates.ErrExcluded.Error()) {
stats.Increment(templates.TemplatesExcludedStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] %v\n", aurora.Yellow("WRN").String(), err.Error())
}
continue
}
gologger.Warning().Msg(err.Error())
}
}
parserItem, ok := store.config.ExecutorOptions.Parser.(*templates.Parser)
if !ok {
return errors.New("invalid parser")
}
templatesCache := parserItem.Cache()
for templatePath := range validPaths {
template, _, _ := templatesCache.Has(templatePath)
if template != nil {
template.Path = templatePath
store.templates = append(store.templates, template)
}
}
return nil
}
// ValidateTemplates takes a list of templates and validates them
// erroring out on discovering any faulty templates.
func (store *Store) ValidateTemplates() error {
@@ -427,10 +385,10 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
store.logErroredTemplates(errs)
templatePathMap := store.pathFilter.Match(includedTemplates)
loadedTemplates := sliceutil.NewSyncSlice[*templates.Template]()
loadedTemplates := make([]*templates.Template, 0, len(templatePathMap))
loadTemplate := func(tmpl *templates.Template) {
loadedTemplates.Append(tmpl)
loadedTemplates = append(loadedTemplates, tmpl)
// increment signed/unsigned counters
if tmpl.Verified {
if tmpl.TemplateVerifier == "" {
@@ -443,89 +401,80 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
}
}
var wgLoadTemplates sync.WaitGroup
for templatePath := range templatePathMap {
wgLoadTemplates.Add(1)
go func(templatePath string) {
defer wgLoadTemplates.Done()
loaded, err := store.config.ExecutorOptions.Parser.LoadTemplate(templatePath, store.tagFilter, tags, store.config.Catalog)
if loaded || store.pathFilter.MatchIncluded(templatePath) {
parsed, err := templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions)
if err != nil {
// exclude templates not compatible with offline matching from total runtime warning stats
if !errors.Is(err, templates.ErrIncompatibleWithOfflineMatching) {
stats.Increment(templates.RuntimeWarningsStats)
}
gologger.Warning().Msgf("Could not parse template %s: %s\n", templatePath, err)
} else if parsed != nil {
if !parsed.Verified && store.config.ExecutorOptions.Options.DisableUnsignedTemplates {
// skip unverified templates when prompted to
stats.Increment(templates.SkippedUnsignedStats)
return
}
// if template has request signature like aws then only signed and verified templates are allowed
if parsed.UsesRequestSignature() && !parsed.Verified {
stats.Increment(templates.SkippedRequestSignatureStats)
return
}
// DAST only templates
if store.config.ExecutorOptions.Options.DAST {
// check if the template is a DAST template
if parsed.IsFuzzing() {
loadTemplate(parsed)
}
} else if len(parsed.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
// donot include headless template in final list if headless flag is not set
stats.Increment(templates.ExcludedHeadlessTmplStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Headless flag is required for headless template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else if len(parsed.RequestsCode) > 0 && !store.config.ExecutorOptions.Options.EnableCodeTemplates {
// donot include 'Code' protocol custom template in final list if code flag is not set
stats.Increment(templates.ExcludedCodeTmplStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Code flag is required for code protocol template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else if len(parsed.RequestsCode) > 0 && !parsed.Verified && len(parsed.Workflows) == 0 {
// donot include unverified 'Code' protocol custom template in final list
stats.Increment(templates.SkippedCodeTmplTamperedStats)
// these will be skipped so increment skip counter
stats.Increment(templates.SkippedUnsignedStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Tampered/Unsigned template at %v.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else if parsed.IsFuzzing() && !store.config.ExecutorOptions.Options.DAST {
stats.Increment(templates.ExludedDastTmplStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] -dast flag is required for DAST template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else {
loaded, err := store.config.ExecutorOptions.Parser.LoadTemplate(templatePath, store.tagFilter, tags, store.config.Catalog)
if loaded || store.pathFilter.MatchIncluded(templatePath) {
parsed, err := templates.Parse(templatePath, store.preprocessor, store.config.ExecutorOptions)
if err != nil {
// exclude templates not compatible with offline matching from total runtime warning stats
if !errors.Is(err, templates.ErrIncompatibleWithOfflineMatching) {
stats.Increment(templates.RuntimeWarningsStats)
}
gologger.Warning().Msgf("Could not parse template %s: %s\n", templatePath, err)
} else if parsed != nil {
if !parsed.Verified && store.config.ExecutorOptions.Options.DisableUnsignedTemplates {
// skip unverified templates when prompted to
stats.Increment(templates.SkippedUnsignedStats)
continue
}
// if template has request signature like aws then only signed and verified templates are allowed
if parsed.UsesRequestSignature() && !parsed.Verified {
stats.Increment(templates.SkippedRequestSignatureStats)
continue
}
// DAST only templates
if store.config.ExecutorOptions.Options.DAST {
// check if the template is a DAST template
if parsed.IsFuzzing() {
loadTemplate(parsed)
}
}
}
if err != nil {
if strings.Contains(err.Error(), templates.ErrExcluded.Error()) {
stats.Increment(templates.TemplatesExcludedStats)
} else if len(parsed.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
// donot include headless template in final list if headless flag is not set
stats.Increment(templates.ExcludedHeadlessTmplStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] %v\n", aurora.Yellow("WRN").String(), err.Error())
gologger.Print().Msgf("[%v] Headless flag is required for headless template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
return
} else if len(parsed.RequestsCode) > 0 && !store.config.ExecutorOptions.Options.EnableCodeTemplates {
// donot include 'Code' protocol custom template in final list if code flag is not set
stats.Increment(templates.ExcludedCodeTmplStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Code flag is required for code protocol template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else if len(parsed.RequestsCode) > 0 && !parsed.Verified && len(parsed.Workflows) == 0 {
// donot include unverified 'Code' protocol custom template in final list
stats.Increment(templates.SkippedCodeTmplTamperedStats)
// these will be skipped so increment skip counter
stats.Increment(templates.SkippedUnsignedStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] Tampered/Unsigned template at %v.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else if parsed.IsFuzzing() && !store.config.ExecutorOptions.Options.DAST {
stats.Increment(templates.ExludedDastTmplStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] -dast flag is required for DAST template '%s'.\n", aurora.Yellow("WRN").String(), templatePath)
}
} else {
loadTemplate(parsed)
}
gologger.Warning().Msg(err.Error())
}
}(templatePath)
}
if err != nil {
if strings.Contains(err.Error(), templates.ErrExcluded.Error()) {
stats.Increment(templates.TemplatesExcludedStats)
if config.DefaultConfig.LogAllEvents {
gologger.Print().Msgf("[%v] %v\n", aurora.Yellow("WRN").String(), err.Error())
}
continue
}
gologger.Warning().Msg(err.Error())
}
}
wgLoadTemplates.Wait()
sort.SliceStable(loadedTemplates.Slice, func(i, j int) bool {
return loadedTemplates.Slice[i].Path < loadedTemplates.Slice[j].Path
sort.SliceStable(loadedTemplates, func(i, j int) bool {
return loadedTemplates[i].Path < loadedTemplates[j].Path
})
return loadedTemplates.Slice
return loadedTemplates
}
// IsHTTPBasedProtocolUsed returns true if http/headless protocol is being used for
+12 -25
View File
@@ -1,7 +1,6 @@
package core
import (
"context"
"sync"
"sync/atomic"
@@ -21,18 +20,18 @@ import (
//
// All the execution logic for the templates/workflows happens in this part
// of the engine.
func (e *Engine) Execute(ctx context.Context, templates []*templates.Template, target provider.InputProvider) *atomic.Bool {
return e.ExecuteScanWithOpts(ctx, templates, target, false)
func (e *Engine) Execute(templates []*templates.Template, target provider.InputProvider) *atomic.Bool {
return e.ExecuteScanWithOpts(templates, target, false)
}
// ExecuteWithResults a list of templates with results
func (e *Engine) ExecuteWithResults(ctx context.Context, templatesList []*templates.Template, target provider.InputProvider, callback func(*output.ResultEvent)) *atomic.Bool {
func (e *Engine) ExecuteWithResults(templatesList []*templates.Template, target provider.InputProvider, callback func(*output.ResultEvent)) *atomic.Bool {
e.Callback = callback
return e.ExecuteScanWithOpts(ctx, templatesList, target, false)
return e.ExecuteScanWithOpts(templatesList, target, false)
}
// ExecuteScanWithOpts executes scan with given scanStrategy
func (e *Engine) ExecuteScanWithOpts(ctx context.Context, templatesList []*templates.Template, target provider.InputProvider, noCluster bool) *atomic.Bool {
func (e *Engine) ExecuteScanWithOpts(templatesList []*templates.Template, target provider.InputProvider, noCluster bool) *atomic.Bool {
results := &atomic.Bool{}
selfcontainedWg := &sync.WaitGroup{}
@@ -84,14 +83,14 @@ func (e *Engine) ExecuteScanWithOpts(ctx context.Context, templatesList []*templ
}
// Execute All SelfContained in parallel
e.executeAllSelfContained(ctx, selfContained, results, selfcontainedWg)
e.executeAllSelfContained(selfContained, results, selfcontainedWg)
strategyResult := &atomic.Bool{}
switch e.options.ScanStrategy {
case scanstrategy.TemplateSpray.String():
strategyResult = e.executeTemplateSpray(ctx, filtered, target)
strategyResult = e.executeTemplateSpray(filtered, target)
case scanstrategy.HostSpray.String():
strategyResult = e.executeHostSpray(ctx, filtered, target)
strategyResult = e.executeHostSpray(filtered, target)
}
results.CompareAndSwap(false, strategyResult.Load())
@@ -101,7 +100,7 @@ func (e *Engine) ExecuteScanWithOpts(ctx context.Context, templatesList []*templ
}
// executeTemplateSpray executes scan using template spray strategy where targets are iterated over each template
func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool {
func (e *Engine) executeTemplateSpray(templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool {
results := &atomic.Bool{}
// wp is workpool that contains different waitgroups for
@@ -109,12 +108,6 @@ func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*temp
wp := e.GetWorkPool()
for _, template := range templatesList {
select {
case <-ctx.Done():
return results
default:
}
// resize check point - nop if there are no changes
wp.RefreshWithConfig(e.GetWorkPoolConfig())
@@ -132,7 +125,7 @@ func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*temp
// All other request types are executed here
// Note: executeTemplateWithTargets creates goroutines and blocks
// given template is executed on all targets
e.executeTemplateWithTargets(ctx, tpl, target, results)
e.executeTemplateWithTargets(tpl, target, results)
}(template)
}
wp.Wait()
@@ -140,21 +133,15 @@ func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*temp
}
// executeHostSpray executes scan using host spray strategy where templates are iterated over each target
func (e *Engine) executeHostSpray(ctx context.Context, templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool {
func (e *Engine) executeHostSpray(templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool {
results := &atomic.Bool{}
wp, _ := syncutil.New(syncutil.WithSize(e.options.BulkSize + e.options.HeadlessBulkSize))
target.Iterate(func(value *contextargs.MetaInput) bool {
select {
case <-ctx.Done():
return false
default:
}
wp.Add()
go func(targetval *contextargs.MetaInput) {
defer wp.Done()
e.executeTemplatesOnTarget(ctx, templatesList, targetval, results)
e.executeTemplatesOnTarget(templatesList, targetval, results)
}(value)
return true
})
+61 -25
View File
@@ -1,7 +1,6 @@
package core
import (
"context"
"sync"
"sync/atomic"
@@ -18,16 +17,16 @@ import (
// Executors are low level executors that deals with template execution on a target
// executeAllSelfContained executes all self contained templates that do not use `target`
func (e *Engine) executeAllSelfContained(ctx context.Context, alltemplates []*templates.Template, results *atomic.Bool, sg *sync.WaitGroup) {
func (e *Engine) executeAllSelfContained(alltemplates []*templates.Template, results *atomic.Bool, sg *sync.WaitGroup) {
for _, v := range alltemplates {
sg.Add(1)
go func(template *templates.Template) {
defer sg.Done()
var err error
var match bool
ctx := scan.NewScanContext(ctx, contextargs.New(ctx))
ctx := scan.NewScanContext(contextargs.New())
if e.Callback != nil {
if results, err := template.Executer.ExecuteWithResults(ctx); err == nil {
if results, err := template.Executer.ExecuteWithResults(ctx); err != nil {
for _, result := range results {
e.Callback(result)
}
@@ -46,7 +45,7 @@ func (e *Engine) executeAllSelfContained(ctx context.Context, alltemplates []*te
}
// executeTemplateWithTarget executes a given template on x targets (with a internal targetpool(i.e concurrency))
func (e *Engine) executeTemplateWithTargets(ctx context.Context, template *templates.Template, target provider.InputProvider, results *atomic.Bool) {
func (e *Engine) executeTemplateWithTargets(template *templates.Template, target provider.InputProvider, results *atomic.Bool) {
// this is target pool i.e max target to execute
wg := e.workPool.InputPool(template.Type())
@@ -78,12 +77,6 @@ func (e *Engine) executeTemplateWithTargets(ctx context.Context, template *templ
}
target.Iterate(func(scannedValue *contextargs.MetaInput) bool {
select {
case <-ctx.Done():
return false // exit
default:
}
// Best effort to track the host progression
// skips indexes lower than the minimum in-flight at interruption time
var skip bool
@@ -107,7 +100,7 @@ func (e *Engine) executeTemplateWithTargets(ctx context.Context, template *templ
currentInfo.Unlock()
// Skip if the host has had errors
if e.executerOpts.HostErrorsCache != nil && e.executerOpts.HostErrorsCache.Check(contextargs.NewWithMetaInput(ctx, scannedValue)) {
if e.executerOpts.HostErrorsCache != nil && e.executerOpts.HostErrorsCache.Check(scannedValue.ID()) {
return true
}
@@ -121,15 +114,15 @@ func (e *Engine) executeTemplateWithTargets(ctx context.Context, template *templ
var match bool
var err error
ctxArgs := contextargs.New(ctx)
ctxArgs := contextargs.New()
ctxArgs.MetaInput = value
ctx := scan.NewScanContext(ctx, ctxArgs)
ctx := scan.NewScanContext(ctxArgs)
switch template.Type() {
case types.WorkflowProtocol:
match = e.executeWorkflow(ctx, template.CompiledWorkflow)
default:
if e.Callback != nil {
if results, err := template.Executer.ExecuteWithResults(ctx); err == nil {
if results, err := template.Executer.ExecuteWithResults(ctx); err != nil {
for _, result := range results {
e.Callback(result)
}
@@ -156,7 +149,7 @@ func (e *Engine) executeTemplateWithTargets(ctx context.Context, template *templ
}
// executeTemplatesOnTarget execute given templates on given single target
func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*templates.Template, target *contextargs.MetaInput, results *atomic.Bool) {
func (e *Engine) executeTemplatesOnTarget(alltemplates []*templates.Template, target *contextargs.MetaInput, results *atomic.Bool) {
// all templates are executed on single target
// wp is workpool that contains different waitgroups for
@@ -165,12 +158,6 @@ func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*t
wp := e.GetWorkPool()
for _, tpl := range alltemplates {
select {
case <-ctx.Done():
return
default:
}
// resize check point - nop if there are no changes
wp.RefreshWithConfig(e.GetWorkPoolConfig())
@@ -186,15 +173,15 @@ func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*t
var match bool
var err error
ctxArgs := contextargs.New(ctx)
ctxArgs := contextargs.New()
ctxArgs.MetaInput = value
ctx := scan.NewScanContext(ctx, ctxArgs)
ctx := scan.NewScanContext(ctxArgs)
switch template.Type() {
case types.WorkflowProtocol:
match = e.executeWorkflow(ctx, template.CompiledWorkflow)
default:
if e.Callback != nil {
if results, err := template.Executer.ExecuteWithResults(ctx); err == nil {
if results, err := template.Executer.ExecuteWithResults(ctx); err != nil {
for _, result := range results {
e.Callback(result)
}
@@ -212,3 +199,52 @@ func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*t
}
wp.Wait()
}
type ChildExecuter struct {
e *Engine
results *atomic.Bool
}
// Close closes the executer returning bool results
func (e *ChildExecuter) Close() *atomic.Bool {
e.e.workPool.Wait()
return e.results
}
// Execute executes a template and URLs
func (e *ChildExecuter) Execute(template *templates.Template, value *contextargs.MetaInput) {
templateType := template.Type()
// resize check point - nop if there are no changes
e.e.WorkPool().RefreshWithConfig(e.e.GetWorkPoolConfig())
var wg *syncutil.AdaptiveWaitGroup
if templateType == types.HeadlessProtocol {
wg = e.e.workPool.Headless
} else {
wg = e.e.workPool.Default
}
wg.Add()
go func(tpl *templates.Template) {
defer wg.Done()
ctxArgs := contextargs.New()
ctxArgs.MetaInput = value
ctx := scan.NewScanContext(ctxArgs)
match, err := template.Executer.Execute(ctx)
if err != nil {
gologger.Warning().Msgf("[%s] Could not execute step: %s\n", e.e.executerOpts.Colorizer.BrightBlue(template.ID), err)
}
e.results.CompareAndSwap(false, match)
}(template)
}
// ExecuteWithOpts executes with the full options
func (e *Engine) ChildExecuter() *ChildExecuter {
return &ChildExecuter{
e: e,
results: &atomic.Bool{},
}
}
+4 -4
View File
@@ -21,7 +21,7 @@ func (e *Engine) executeWorkflow(ctx *scan.ScanContext, w *workflows.Workflow) b
// at this point we should be at the start root execution of a workflow tree, hence we create global shared instances
workflowCookieJar, _ := cookiejar.New(nil)
ctxArgs := contextargs.New(ctx.Context())
ctxArgs := contextargs.New()
ctxArgs.MetaInput = ctx.Input.MetaInput
ctxArgs.CookieJar = workflowCookieJar
@@ -98,7 +98,7 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, ctx *scan
}
if err != nil {
if w.Options.HostErrorsCache != nil {
w.Options.HostErrorsCache.MarkFailed(ctx.Input, err)
w.Options.HostErrorsCache.MarkFailed(ctx.Input.MetaInput.ID(), err)
}
if len(template.Executers) == 1 {
mainErr = err
@@ -139,7 +139,7 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, ctx *scan
defer swg.Done()
// create a new context with the same input but with unset callbacks
subCtx := scan.NewScanContext(ctx.Context(), ctx.Input)
subCtx := scan.NewScanContext(ctx.Input)
if err := e.runWorkflowStep(subtemplate, subCtx, results, swg, w); err != nil {
gologger.Warning().Msgf(workflowStepExecutionError, subtemplate.Template, err)
}
@@ -165,7 +165,7 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, ctx *scan
go func(template *workflows.WorkflowTemplate) {
// create a new context with the same input but with unset callbacks
subCtx := scan.NewScanContext(ctx.Context(), ctx.Input)
subCtx := scan.NewScanContext(ctx.Input)
if err := e.runWorkflowStep(template, subCtx, results, swg, w); err != nil {
gologger.Warning().Msgf(workflowStepExecutionError, template.Template, err)
}
+12 -13
View File
@@ -1,7 +1,6 @@
package core
import (
"context"
"testing"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/stringslice"
@@ -26,8 +25,8 @@ func TestWorkflowsSimple(t *testing.T) {
}}
engine := &Engine{}
input := contextargs.NewWithInput(context.Background(), "https://test.com")
ctx := scan.NewScanContext(context.Background(), input)
input := contextargs.NewWithInput("https://test.com")
ctx := scan.NewScanContext(input)
matched := engine.executeWorkflow(ctx, workflow)
require.True(t, matched, "could not get correct match value")
}
@@ -50,8 +49,8 @@ func TestWorkflowsSimpleMultiple(t *testing.T) {
}}
engine := &Engine{}
input := contextargs.NewWithInput(context.Background(), "https://test.com")
ctx := scan.NewScanContext(context.Background(), input)
input := contextargs.NewWithInput("https://test.com")
ctx := scan.NewScanContext(input)
matched := engine.executeWorkflow(ctx, workflow)
require.True(t, matched, "could not get correct match value")
@@ -78,8 +77,8 @@ func TestWorkflowsSubtemplates(t *testing.T) {
}}
engine := &Engine{}
input := contextargs.NewWithInput(context.Background(), "https://test.com")
ctx := scan.NewScanContext(context.Background(), input)
input := contextargs.NewWithInput("https://test.com")
ctx := scan.NewScanContext(input)
matched := engine.executeWorkflow(ctx, workflow)
require.True(t, matched, "could not get correct match value")
@@ -104,8 +103,8 @@ func TestWorkflowsSubtemplatesNoMatch(t *testing.T) {
}}
engine := &Engine{}
input := contextargs.NewWithInput(context.Background(), "https://test.com")
ctx := scan.NewScanContext(context.Background(), input)
input := contextargs.NewWithInput("https://test.com")
ctx := scan.NewScanContext(input)
matched := engine.executeWorkflow(ctx, workflow)
require.False(t, matched, "could not get correct match value")
@@ -135,8 +134,8 @@ func TestWorkflowsSubtemplatesWithMatcher(t *testing.T) {
}}
engine := &Engine{}
input := contextargs.NewWithInput(context.Background(), "https://test.com")
ctx := scan.NewScanContext(context.Background(), input)
input := contextargs.NewWithInput("https://test.com")
ctx := scan.NewScanContext(input)
matched := engine.executeWorkflow(ctx, workflow)
require.True(t, matched, "could not get correct match value")
@@ -166,8 +165,8 @@ func TestWorkflowsSubtemplatesWithMatcherNoMatch(t *testing.T) {
}}
engine := &Engine{}
input := contextargs.NewWithInput(context.Background(), "https://test.com")
ctx := scan.NewScanContext(context.Background(), input)
input := contextargs.NewWithInput("https://test.com")
ctx := scan.NewScanContext(input)
matched := engine.executeWorkflow(ctx, workflow)
require.False(t, matched, "could not get correct match value")
+4 -11
View File
@@ -1,9 +1,6 @@
package core
import (
"context"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
syncutil "github.com/projectdiscovery/utils/sync"
)
@@ -74,18 +71,14 @@ func (w *WorkPool) RefreshWithConfig(config WorkPoolConfig) {
if w.config.HeadlessInputConcurrency != config.HeadlessInputConcurrency {
w.config.HeadlessInputConcurrency = config.HeadlessInputConcurrency
}
w.Refresh(context.Background())
w.Refresh()
}
func (w *WorkPool) Refresh(ctx context.Context) {
func (w *WorkPool) Refresh() {
if w.Default.Size != w.config.TypeConcurrency {
if err := w.Default.Resize(ctx, w.config.TypeConcurrency); err != nil {
gologger.Warning().Msgf("Could not resize workpool: %s\n", err)
}
w.Default.Resize(w.config.TypeConcurrency)
}
if w.Headless.Size != w.config.HeadlessTypeConcurrency {
if err := w.Headless.Resize(ctx, w.config.HeadlessTypeConcurrency); err != nil {
gologger.Warning().Msgf("Could not resize workpool: %s\n", err)
}
w.Headless.Resize(w.config.HeadlessTypeConcurrency)
}
}
+3 -3
View File
@@ -83,8 +83,8 @@ func (bk *customTemplateGitLabRepo) Download(_ context.Context) {
// Get the directory listing for the files in the project
tree, _, err := bk.gitLabClient.Repositories.ListTree(projectID, &gitlab.ListTreeOptions{
Ref: gitlab.Ptr(project.DefaultBranch),
Recursive: gitlab.Ptr(true),
Ref: gitlab.String(project.DefaultBranch),
Recursive: gitlab.Bool(true),
})
if err != nil {
gologger.Error().Msgf("error retrieving files from GitLab project: %s (%d) %s", project.Name, projectID, err)
@@ -95,7 +95,7 @@ func (bk *customTemplateGitLabRepo) Download(_ context.Context) {
// If the object is not a file or file extension is not .yaml, skip it
if file.Type == "blob" && filepath.Ext(file.Path) == ".yaml" {
gf := &gitlab.GetFileOptions{
Ref: gitlab.Ptr(project.DefaultBranch),
Ref: gitlab.String(project.DefaultBranch),
}
f, _, err := bk.gitLabClient.RepositoryFiles.GetFile(projectID, file.Path, gf)
if err != nil {
-3
View File
@@ -83,9 +83,6 @@ func (q *Header) Delete(key string) error {
func (q *Header) Rebuild() (*retryablehttp.Request, error) {
cloned := q.req.Clone(context.Background())
q.value.parsed.Iterate(func(key string, value any) bool {
if strings.TrimSpace(key) == "" {
return true
}
if strings.EqualFold(key, "Host") {
return true
}
+12 -38
View File
@@ -2,12 +2,10 @@ package component
import (
"context"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
"github.com/projectdiscovery/retryablehttp-go"
urlutil "github.com/projectdiscovery/utils/url"
)
// Path is a component for a request Path
@@ -33,18 +31,13 @@ func (q *Path) Name() string {
// parsed component
func (q *Path) Parse(req *retryablehttp.Request) (bool, error) {
q.req = req
q.value = NewValue("")
q.value = NewValue(req.URL.Path)
splitted := strings.Split(req.URL.Path, "/")
values := make(map[string]interface{})
for i := range splitted {
pathTillNow := strings.Join(splitted[:i+1], "/")
if pathTillNow == "" {
continue
}
values[strconv.Itoa(i)] = pathTillNow
parsed, err := dataformat.Get(dataformat.RawDataFormat).Decode(q.value.String())
if err != nil {
return false, err
}
q.value.SetParsed(dataformat.KVMap(values), "")
q.value.SetParsed(parsed, dataformat.RawDataFormat)
return true, nil
}
@@ -63,8 +56,7 @@ func (q *Path) Iterate(callback func(key string, value interface{}) error) (err
// SetValue sets a value in the component
// for a key
func (q *Path) SetValue(key string, value string) error {
escaped := urlutil.ParamEncode(value)
if !q.value.SetParsedValue(key, escaped) {
if !q.value.SetParsedValue(key, value) {
return ErrSetValue
}
return nil
@@ -81,31 +73,13 @@ func (q *Path) Delete(key string) error {
// Rebuild returns a new request with the
// component rebuilt
func (q *Path) Rebuild() (*retryablehttp.Request, error) {
originalValues := make(map[string]interface{})
splitted := strings.Split(q.req.URL.Path, "/")
for i := range splitted {
pathTillNow := strings.Join(splitted[:i+1], "/")
if pathTillNow == "" {
continue
}
originalValues[strconv.Itoa(i)] = pathTillNow
encoded, err := q.value.Encode()
if err != nil {
return nil, errors.Wrap(err, "could not encode query")
}
originalPath := q.req.URL.Path
lengthSplitted := len(q.value.parsed.Map)
for i := lengthSplitted; i > 0; i-- {
key := strconv.Itoa(i)
original := originalValues[key].(string)
new := q.value.parsed.Map[key].(string)
originalPath = strings.Replace(originalPath, original, new, 1)
}
rebuiltPath := originalPath
// Clone the request and update the path
cloned := q.req.Clone(context.Background())
if err := cloned.UpdateRelPath(rebuiltPath, true); err != nil {
cloned.URL.RawPath = rebuiltPath
if err := cloned.UpdateRelPath(encoded, true); err != nil {
cloned.URL.RawPath = encoded
}
return cloned, nil
}
+3 -37
View File
@@ -28,10 +28,10 @@ func TestURLComponent(t *testing.T) {
return nil
})
require.Equal(t, []string{"1"}, keys, "unexpected keys")
require.Equal(t, []string{"value"}, keys, "unexpected keys")
require.Equal(t, []string{"/testpath"}, values, "unexpected values")
err = urlComponent.SetValue("1", "/newpath")
err = urlComponent.SetValue("value", "/newpath")
if err != nil {
t.Fatal(err)
}
@@ -40,41 +40,7 @@ func TestURLComponent(t *testing.T) {
if err != nil {
t.Fatal(err)
}
require.Equal(t, "/newpath", rebuilt.URL.Path, "unexpected URL path")
require.Equal(t, "https://example.com/newpath", rebuilt.URL.String(), "unexpected full URL")
}
func TestURLComponent_NestedPaths(t *testing.T) {
path := NewPath()
req, err := retryablehttp.NewRequest(http.MethodGet, "https://example.com/user/753/profile", nil)
if err != nil {
t.Fatal(err)
}
found, err := path.Parse(req)
if err != nil {
t.Fatal(err)
}
if !found {
t.Fatal("expected path to be found")
}
isSet := false
_ = path.Iterate(func(key string, value interface{}) error {
if !isSet && value.(string) == "/user/753" {
isSet = true
if setErr := path.SetValue(key, "/user/753'"); setErr != nil {
t.Fatal(setErr)
}
}
return nil
})
newReq, err := path.Rebuild()
if err != nil {
t.Fatal(err)
}
if newReq.URL.Path != "/user/753'/profile" {
t.Fatal("expected path to be modified")
}
}
-1
View File
@@ -61,7 +61,6 @@ func (q *Query) Iterate(callback func(key string, value interface{}) error) (err
// SetValue sets a value in the component
// for a key
func (q *Query) SetValue(key string, value string) error {
// Is this safe?
if !q.value.SetParsedValue(key, value) {
return ErrSetValue
}
+7 -50
View File
@@ -1,7 +1,6 @@
package fuzz
import (
"encoding/json"
"fmt"
"io"
"regexp"
@@ -16,8 +15,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/retryablehttp-go"
errorutil "github.com/projectdiscovery/utils/errors"
mapsutil "github.com/projectdiscovery/utils/maps"
sliceutil "github.com/projectdiscovery/utils/slice"
urlutil "github.com/projectdiscovery/utils/url"
)
@@ -48,8 +45,6 @@ type ExecuteRuleInput struct {
Values map[string]interface{}
// BaseRequest is the base http request for fuzzing rule
BaseRequest *retryablehttp.Request
// DisplayFuzzPoints is a flag to display fuzz points
DisplayFuzzPoints bool
}
// GeneratedRequest is a single generated request for rule
@@ -62,8 +57,6 @@ type GeneratedRequest struct {
DynamicValues map[string]interface{}
// Component is the component for the request
Component component.Component
// Parameter being fuzzed
Parameter string
}
// Execute executes a fuzzing rule accepting a callback on which
@@ -81,9 +74,8 @@ func (rule *Rule) Execute(input *ExecuteRuleInput) (err error) {
var finalComponentList []component.Component
// match rule part with component name
displayDebugFuzzPoints := make(map[string]map[string]string)
for _, componentName := range component.Components {
if !(rule.Part == componentName || sliceutil.Contains(rule.Parts, componentName) || rule.partType == requestPartType) {
if rule.partType != requestPartType && rule.Part != componentName {
continue
}
component := component.New(componentName)
@@ -95,25 +87,12 @@ func (rule *Rule) Execute(input *ExecuteRuleInput) (err error) {
if !discovered {
continue
}
// check rule applicable on this component
if !rule.checkRuleApplicableOnComponent(component) {
continue
}
// Debugging display for fuzz points
if input.DisplayFuzzPoints {
displayDebugFuzzPoints[componentName] = make(map[string]string)
_ = component.Iterate(func(key string, value interface{}) error {
displayDebugFuzzPoints[componentName][key] = fmt.Sprintf("%v", value)
return nil
})
}
finalComponentList = append(finalComponentList, component)
}
if len(displayDebugFuzzPoints) > 0 {
marshalled, _ := json.MarshalIndent(displayDebugFuzzPoints, "", " ")
gologger.Info().Msgf("[%s] Fuzz points for %s [%s]\n%s\n", rule.options.TemplateID, input.Input.MetaInput.Input, input.BaseRequest.Method, string(marshalled))
}
if len(finalComponentList) == 0 {
return ErrRuleNotApplicable.Msgf("no component matched on this rule")
@@ -166,27 +145,14 @@ mainLoop:
func (rule *Rule) evaluateVarsWithInteractsh(data map[string]interface{}, interactshUrls []string) (map[string]interface{}, []string) {
// Check if Interactsh options are configured
if rule.options.Interactsh != nil {
interactshUrlsMap := make(map[string]struct{})
for _, url := range interactshUrls {
interactshUrlsMap[url] = struct{}{}
}
interactshUrls = mapsutil.GetKeys(interactshUrlsMap)
// Iterate through the data to replace and evaluate variables with Interactsh URLs
for k, v := range data {
value := fmt.Sprint(v)
// Replace variables with Interactsh URLs and collect new URLs
got, oastUrls := rule.options.Interactsh.Replace(value, interactshUrls)
if got != value {
data[k] = got
}
got, oastUrls := rule.options.Interactsh.Replace(fmt.Sprint(v), interactshUrls)
// Append new OAST URLs if any
if len(oastUrls) > 0 {
for _, url := range oastUrls {
if _, ok := interactshUrlsMap[url]; !ok {
interactshUrlsMap[url] = struct{}{}
interactshUrls = append(interactshUrls, url)
}
}
interactshUrls = append(interactshUrls, oastUrls...)
}
// Evaluate the replaced data
evaluatedData, err := expressions.Evaluate(got, data)
@@ -245,19 +211,11 @@ func (rule *Rule) executeRuleValues(input *ExecuteRuleInput, ruleComponent compo
})
// if mode is multiple now build and execute it
if rule.modeType == multipleModeType {
rule.Fuzz.KV.Iterate(func(key, value string) bool {
var evaluated string
evaluated, input.InteractURLs = rule.executeEvaluate(input, key, "", value, input.InteractURLs)
if err := ruleComponent.SetValue(key, evaluated); err != nil {
return true
}
return true
})
req, err := ruleComponent.Rebuild()
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
}
}
@@ -293,9 +251,8 @@ func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *proto
} else {
rule.partType = valueType
}
}
if rule.Part == "" && len(rule.Parts) == 0 {
return errors.Errorf("no part specified for rule")
} else {
rule.partType = queryPartType
}
if rule.Type != "" {
-152
View File
@@ -1,152 +0,0 @@
package frequency
import (
"net"
"net/url"
"os"
"strings"
"sync"
"sync/atomic"
"github.com/bluele/gcache"
"github.com/projectdiscovery/gologger"
)
// Tracker implements a frequency tracker for a given input
// which is used to determine uninteresting input parameters
// which are not that interesting from fuzzing perspective for a template
// and target combination.
//
// This is used to reduce the number of requests made during fuzzing
// for parameters that are less likely to give results for a rule.
type Tracker struct {
frequencies gcache.Cache
paramOccurenceThreshold int
isDebug bool
}
const (
DefaultMaxTrackCount = 10000
DefaultParamOccurenceThreshold = 10
)
type cacheItem struct {
errors atomic.Int32
sync.Once
}
// New creates a new frequency tracker with a given maximum
// number of params to track in LRU fashion with a max error threshold
func New(maxTrackCount, paramOccurenceThreshold int) *Tracker {
gc := gcache.New(maxTrackCount).ARC().Build()
var isDebug bool
if os.Getenv("FREQ_DEBUG") != "" {
isDebug = true
}
return &Tracker{
isDebug: isDebug,
frequencies: gc,
paramOccurenceThreshold: paramOccurenceThreshold,
}
}
func (t *Tracker) Close() {
t.frequencies.Purge()
}
// MarkParameter marks a parameter as frequently occuring once.
//
// The logic requires a parameter to be marked as frequently occuring
// multiple times before it's considered as frequently occuring.
func (t *Tracker) MarkParameter(parameter, target, template string) {
normalizedTarget := normalizeTarget(target)
key := getFrequencyKey(parameter, normalizedTarget, template)
if t.isDebug {
gologger.Verbose().Msgf("[%s] Marking %s as found uninteresting", template, key)
}
existingCacheItem, err := t.frequencies.GetIFPresent(key)
if err != nil || existingCacheItem == nil {
newItem := &cacheItem{errors: atomic.Int32{}}
newItem.errors.Store(1)
_ = t.frequencies.Set(key, newItem)
return
}
existingCacheItemValue := existingCacheItem.(*cacheItem)
existingCacheItemValue.errors.Add(1)
_ = t.frequencies.Set(key, existingCacheItemValue)
}
// IsParameterFrequent checks if a parameter is frequently occuring
// in the input with no much results.
func (t *Tracker) IsParameterFrequent(parameter, target, template string) bool {
normalizedTarget := normalizeTarget(target)
key := getFrequencyKey(parameter, normalizedTarget, template)
if t.isDebug {
gologger.Verbose().Msgf("[%s] Checking if %s is frequently found uninteresting", template, key)
}
existingCacheItem, err := t.frequencies.GetIFPresent(key)
if err != nil {
return false
}
existingCacheItemValue := existingCacheItem.(*cacheItem)
if existingCacheItemValue.errors.Load() >= int32(t.paramOccurenceThreshold) {
existingCacheItemValue.Do(func() {
gologger.Verbose().Msgf("[%s] Skipped %s from parameter for %s as found uninteresting %d times", template, parameter, target, existingCacheItemValue.errors.Load())
})
return true
}
return false
}
// UnmarkParameter unmarks a parameter as frequently occuring. This carries
// more weight and resets the frequency counter for the parameter causing
// it to be checked again. This is done when results are found.
func (t *Tracker) UnmarkParameter(parameter, target, template string) {
normalizedTarget := normalizeTarget(target)
key := getFrequencyKey(parameter, normalizedTarget, template)
if t.isDebug {
gologger.Verbose().Msgf("[%s] Unmarking %s as frequently found uninteresting", template, key)
}
_ = t.frequencies.Remove(key)
}
func getFrequencyKey(parameter, target, template string) string {
var sb strings.Builder
sb.WriteString(target)
sb.WriteString(":")
sb.WriteString(template)
sb.WriteString(":")
sb.WriteString(parameter)
str := sb.String()
return str
}
func normalizeTarget(value string) string {
finalValue := value
if strings.HasPrefix(value, "http") {
if parsed, err := url.Parse(value); err == nil {
hostname := parsed.Host
finalPort := parsed.Port()
if finalPort == "" {
if parsed.Scheme == "https" {
finalPort = "443"
} else {
finalPort = "80"
}
hostname = net.JoinHostPort(parsed.Host, finalPort)
}
finalValue = hostname
}
}
return finalValue
}
+2 -17
View File
@@ -24,27 +24,12 @@ type Rule struct {
ruleType ruleType
// description: |
// Part is the part of request to fuzz.
//
// query fuzzes the query part of url. More parts will be added later.
// values:
// - "query"
// - "header"
// - "path"
// - "body"
// - "cookie"
// - "request"
Part string `yaml:"part,omitempty" json:"part,omitempty" jsonschema:"title=part of rule,description=Part of request rule to fuzz,enum=query,enum=header,enum=path,enum=body,enum=cookie,enum=request"`
partType partType
// description: |
// Parts is the list of parts to fuzz. If multiple parts need to be
// defined while excluding some, this should be used instead of singular part.
// values:
// - "query"
// - "header"
// - "path"
// - "body"
// - "cookie"
// - "request"
Parts []string `yaml:"parts,omitempty" json:"parts,omitempty" jsonschema:"title=parts of rule,description=Part of request rule to fuzz,enum=query,enum=header,enum=path,enum=body,enum=cookie,enum=request"`
// description: |
// Mode is the mode of fuzzing to perform.
//
+3 -5
View File
@@ -7,9 +7,7 @@ import (
)
func TestRuleMatchKeyOrValue(t *testing.T) {
rule := &Rule{
Part: "query",
}
rule := &Rule{}
err := rule.Compile(nil, nil)
require.NoError(t, err, "could not compile rule")
@@ -17,7 +15,7 @@ func TestRuleMatchKeyOrValue(t *testing.T) {
require.True(t, result, "could not get correct result")
t.Run("key", func(t *testing.T) {
rule := &Rule{Keys: []string{"url"}, Part: "query"}
rule := &Rule{Keys: []string{"url"}}
err := rule.Compile(nil, nil)
require.NoError(t, err, "could not compile rule")
@@ -27,7 +25,7 @@ func TestRuleMatchKeyOrValue(t *testing.T) {
require.False(t, result, "could not get correct result")
})
t.Run("value", func(t *testing.T) {
rule := &Rule{ValuesRegex: []string{`https?:\/\/?([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)*(\/[\/\d\w\.-]*)*(?:[\?])*(.+)*`}, Part: "query"}
rule := &Rule{ValuesRegex: []string{`https?:\/\/?([-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b)*(\/[\/\d\w\.-]*)*(?:[\?])*(.+)*`}}
err := rule.Compile(nil, nil)
require.NoError(t, err, "could not compile rule")
+7 -26
View File
@@ -2,7 +2,6 @@ package fuzz
import (
"io"
"strconv"
"strings"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/component"
@@ -10,7 +9,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/retryablehttp-go"
sliceutil "github.com/projectdiscovery/utils/slice"
)
// executePartRule executes part rules based on type
@@ -20,7 +18,7 @@ func (rule *Rule) executePartRule(input *ExecuteRuleInput, payload ValueOrKeyVal
// checkRuleApplicableOnComponent checks if a rule is applicable on given component
func (rule *Rule) checkRuleApplicableOnComponent(component component.Component) bool {
if rule.Part != component.Name() && !sliceutil.Contains(rule.Parts, component.Name()) && rule.partType != requestPartType {
if rule.Part != component.Name() {
return false
}
foundAny := false
@@ -70,7 +68,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); qerr != nil {
return qerr
}
// fmt.Printf("executed with value: %s\n", evaluated)
@@ -92,7 +90,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 +125,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); qerr != nil {
return err
}
@@ -146,29 +144,12 @@ 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 {
// 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
if _, err := strconv.Atoi(parameter); err == nil || (parameter == "" && parameterValue != "") {
parameter = parameterValue
}
// If the parameter is frequent, skip it if the option is enabled
if rule.options.FuzzParamsFrequency != nil {
if rule.options.FuzzParamsFrequency.IsParameterFrequent(
parameter,
httpReq.URL.String(),
rule.options.TemplateID,
) {
return nil
}
}
func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.Request, interactURLs []string, component component.Component) error {
request := GeneratedRequest{
Request: httpReq,
InteractURLs: interactURLs,
DynamicValues: input.Values,
Component: component,
Parameter: parameter,
}
if !input.Callback(request) {
return types.ErrNoMoreRequests
@@ -181,9 +162,9 @@ func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.
// for fuzzing.
func (rule *Rule) executeEvaluate(input *ExecuteRuleInput, _, value, payload string, interactshURLs []string) (string, []string) {
// TODO: Handle errors
values := generators.MergeMaps(rule.options.Variables.GetAll(), map[string]interface{}{
values := generators.MergeMaps(input.Values, map[string]interface{}{
"value": value,
}, rule.options.Options.Vars.AsMap(), input.Values)
}, rule.options.Options.Vars.AsMap(), rule.options.Variables.GetAll())
firstpass, _ := expressions.Evaluate(payload, values)
interactData, interactshURLs := rule.options.Interactsh.Replace(firstpass, interactshURLs)
evaluated, _ := expressions.Evaluate(interactData, values)
+38 -37
View File
@@ -2,13 +2,12 @@ package formats
import (
"errors"
"fmt"
"os"
"strings"
"github.com/projectdiscovery/nuclei/v3/pkg/input/types"
fileutil "github.com/projectdiscovery/utils/file"
mapsutil "github.com/projectdiscovery/utils/maps"
"gopkg.in/yaml.v3"
)
// ParseReqRespCallback is a callback function for discovered raw requests
@@ -42,7 +41,8 @@ type Format interface {
}
var (
ErrNoVarsDumpFile = errors.New("no required params file found")
DefaultVarDumpFileName = "required_openapi_params.yaml"
ErrNoVarsDumpFile = errors.New("no required params file found")
)
// == OpenAPIParamsCfgFile ==
@@ -52,51 +52,52 @@ var (
// OpenAPIParamsCfgFile is the structure of the required vars dump file
type OpenAPIParamsCfgFile struct {
FileName string `yaml:"-"`
Var []string `yaml:"var"`
OptionalVars []string `yaml:"-"` // this will be written to the file as comments
}
// UpdateMissingVarsFile writes the required vars dump file
func UpdateMissingVarsFile(vars *OpenAPIParamsCfgFile) error {
existing := make(map[string]string)
if fileutil.FileExists(vars.FileName) {
bin, err := os.ReadFile(vars.FileName)
if err != nil {
return err
}
for _, v := range strings.Split(string(bin), "\n") {
v = strings.TrimSpace(v)
parts := strings.Split(v, "=")
if len(parts) == 1 {
existing[parts[0]] = ""
} else if len(parts) == 2 {
existing[parts[0]] = parts[1]
}
}
// ReadOpenAPIVarDumpFile reads the required vars dump file
func ReadOpenAPIVarDumpFile() (*OpenAPIParamsCfgFile, error) {
var vars OpenAPIParamsCfgFile
if !fileutil.FileExists(DefaultVarDumpFileName) {
return nil, ErrNoVarsDumpFile
}
// add missing vars to existing
bin, err := os.ReadFile(DefaultVarDumpFileName)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(bin, &vars)
if err != nil {
return nil, err
}
filtered := []string{}
for _, v := range vars.Var {
if _, ok := existing[v]; !ok {
existing[v] = ""
v = strings.TrimSpace(v)
if !strings.HasSuffix(v, "=") {
filtered = append(filtered, v)
}
}
// add optional vars to existing
for _, v := range vars.OptionalVars {
if _, ok := existing[v]; !ok {
existing[v] = ""
}
}
f, err := os.OpenFile(vars.FileName, os.O_WRONLY|os.O_CREATE, 0644)
vars.Var = filtered
return &vars, nil
}
// WriteOpenAPIVarDumpFile writes the required vars dump file
func WriteOpenAPIVarDumpFile(vars *OpenAPIParamsCfgFile) error {
f, err := os.OpenFile(DefaultVarDumpFileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
for _, v := range mapsutil.GetSortedKeys(existing) {
if strings.TrimSpace(v) == "" {
continue
}
f.WriteString(fmt.Sprintf("%s=%s\n", v, existing[v]))
bin, err := yaml.Marshal(vars)
if err != nil {
return err
}
return nil
_, _ = f.Write(bin)
if len(vars.OptionalVars) > 0 {
_, _ = f.WriteString("\n # Optional parameters\n")
for _, v := range vars.OptionalVars {
_, _ = f.WriteString(" # - " + v + "=\n")
}
}
return f.Sync()
}
+3 -7
View File
@@ -28,10 +28,9 @@ var _ formats.Format = &JSONFormat{}
type proxifyRequest struct {
URL string `json:"url"`
Request struct {
Header map[string]string `json:"header"`
Body string `json:"body"`
Raw string `json:"raw"`
Endpoint string `json:"endpoint"`
Header map[string]string `json:"header"`
Body string `json:"body"`
Raw string `json:"raw"`
} `json:"request"`
}
@@ -64,9 +63,6 @@ func (j *JSONFormat) Parse(input string, resultsCb formats.ParseReqRespCallback)
return errors.Wrap(err, "could not decode json file")
}
if request.URL == "" && request.Request.Endpoint != "" {
request.URL = request.Request.Endpoint
}
rawRequest, err := types.ParseRawRequestWithURL(request.Request.Raw, request.URL)
if err != nil {
gologger.Warning().Msgf("jsonl: Could not parse raw request %s: %s\n", request.URL, err)
+7 -7
View File
@@ -18,7 +18,7 @@ func getSchemaExample(schema *openapi3.Schema) (interface{}, bool) {
return schema.Default, true
}
if len(schema.Enum) > 0 {
if schema.Enum != nil && len(schema.Enum) > 0 {
return schema.Enum[0], true
}
return nil, false
@@ -175,9 +175,9 @@ func openAPIExample(schema *openapi3.Schema, cache map[*openapi3.Schema]*cachedS
}
switch {
case schema.Type.Is("boolean"):
case schema.Type == "boolean":
return true, nil
case schema.Type.Is("number"), schema.Type.Is("integer"):
case schema.Type == "number", schema.Type == "integer":
value := 0.0
if schema.Min != nil && *schema.Min > value {
@@ -208,11 +208,11 @@ func openAPIExample(schema *openapi3.Schema, cache map[*openapi3.Schema]*cachedS
value += float64(int(*schema.MultipleOf) - (int(value) % int(*schema.MultipleOf)))
}
if schema.Type.Is("integer") {
if schema.Type == "integer" {
return int(value), nil
}
return value, nil
case schema.Type.Is("string"):
case schema.Type == "string":
if ex := stringFormatExample(schema.Format); ex != "" {
return ex, nil
}
@@ -226,7 +226,7 @@ func openAPIExample(schema *openapi3.Schema, cache map[*openapi3.Schema]*cachedS
example = example[:*schema.MaxLength]
}
return example, nil
case schema.Type.Is("array"), schema.Items != nil:
case schema.Type == "array", schema.Items != nil:
example := []interface{}{}
if schema.Items != nil && schema.Items.Value != nil {
@@ -242,7 +242,7 @@ func openAPIExample(schema *openapi3.Schema, cache map[*openapi3.Schema]*cachedS
}
}
return example, nil
case schema.Type.Is("object"), len(schema.Properties) > 0:
case schema.Type == "object", len(schema.Properties) > 0:
example := map[string]interface{}{}
for k, v := range schema.Properties {
+35 -62
View File
@@ -20,7 +20,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
httpTypes "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/utils/errkit"
errorutil "github.com/projectdiscovery/utils/errors"
"github.com/projectdiscovery/utils/generic"
mapsutil "github.com/projectdiscovery/utils/maps"
@@ -36,6 +35,7 @@ func GenerateRequestsFromSchema(schema *openapi3.T, opts formats.InputFormatOpti
if len(schema.Servers) == 0 {
return errors.New("no servers found in openapi schema")
}
// new set of globalParams obtained from security schemes
globalParams := openapi3.NewParameters()
@@ -47,6 +47,22 @@ func GenerateRequestsFromSchema(schema *openapi3.T, opts formats.InputFormatOpti
globalParams = append(globalParams, params...)
}
// validate global param requirements
for _, param := range globalParams {
if val, ok := opts.Variables[param.Value.Name]; ok {
param.Value.Example = val
} else {
// if missing check for validation
if opts.SkipFormatValidation {
gologger.Verbose().Msgf("openapi: skipping all requests due to missing global auth parameter: %s\n", param.Value.Name)
return nil
} else {
// fatal error
gologger.Fatal().Msgf("openapi: missing global auth parameter: %s\n", param.Value.Name)
}
}
}
missingVarMap := make(map[string]struct{})
optionalVarMap := make(map[string]struct{})
missingParamValueCallback := func(param *openapi3.Parameter, opts *generateReqOptions) {
@@ -57,45 +73,18 @@ func GenerateRequestsFromSchema(schema *openapi3.T, opts formats.InputFormatOpti
missingVarMap[param.Name] = struct{}{}
}
// validate global param requirements
for _, param := range globalParams {
if val, ok := opts.Variables[param.Value.Name]; ok && val != "" {
param.Value.Example = val
delete(missingVarMap, param.Value.Name)
} else {
// if missing check for validation
if opts.SkipFormatValidation {
gologger.Verbose().Msgf("openapi: skipping all requests due to missing global auth parameter: %s\n", param.Value.Name)
return nil
} else {
// put them in missingVarMap
missingVarMap[param.Value.Name] = struct{}{}
}
}
}
for _, serverURL := range schema.Servers {
pathURL := serverURL.URL
// Split the server URL into baseURL and serverPath
u, err := url.Parse(pathURL)
if err != nil {
return errors.Wrap(err, "could not parse server url")
}
baseURL := fmt.Sprintf("%s://%s", u.Scheme, u.Host)
serverPath := u.Path
for path, v := range schema.Paths.Map() {
// a path item can have parameters
ops := v.Operations()
requestPath := path
if serverPath != "" {
requestPath = serverPath + path
}
for method, ov := range ops {
if err := generateRequestsFromOp(&generateReqOptions{
requiredOnly: opts.RequiredOnly,
method: method,
pathURL: baseURL,
pathURL: pathURL,
requestPath: requestPath,
op: ov,
schema: schema,
@@ -110,20 +99,18 @@ func GenerateRequestsFromSchema(schema *openapi3.T, opts formats.InputFormatOpti
}
}
}
if len(missingVarMap) > 0 && !opts.SkipFormatValidation {
filename := fileNameFromTitle(schema.Info.Title)
gologger.Error().Msgf("openapi: Found %d missing/empty parameters, use -skip-format-validation flag to skip requests or update missing parameters generated in %s file, add pass it to nuclei using '-var %s'\n", len(missingVarMap), filename, filename)
gologger.Error().Msgf("openapi: Found %d missing parameters, use -skip-format-validation flag to skip requests or update missing parameters generated in %s file,you can also specify these vars using -var flag in (key=value) format\n", len(missingVarMap), formats.DefaultVarDumpFileName)
gologger.Verbose().Msgf("openapi: missing params: %+v", mapsutil.GetSortedKeys(missingVarMap))
if config.CurrentAppMode == config.AppModeCLI {
// generate var dump file
vars := &formats.OpenAPIParamsCfgFile{
FileName: filename,
}
vars := &formats.OpenAPIParamsCfgFile{}
for k := range missingVarMap {
vars.Var = append(vars.Var, k)
vars.Var = append(vars.Var, k+"=")
}
vars.OptionalVars = mapsutil.GetSortedKeys(optionalVarMap)
if err := formats.UpdateMissingVarsFile(vars); err != nil {
if err := formats.WriteOpenAPIVarDumpFile(vars); err != nil {
gologger.Error().Msgf("openapi: could not write params file: %s\n", err)
}
// exit with status code 1
@@ -192,10 +179,6 @@ func generateRequestsFromOp(opts *generateReqOptions) error {
for _, parameter := range reqParams {
value := parameter.Value
if value.Schema == nil || value.Schema.Value == nil {
continue
}
// paramValue or default value to use
var paramValue interface{}
@@ -206,7 +189,7 @@ func generateRequestsFromOp(opts *generateReqOptions) error {
paramValue = value.Schema.Value.Default
} else if value.Schema.Value.Example != nil {
paramValue = value.Schema.Value.Example
} else if len(value.Schema.Value.Enum) > 0 {
} else if value.Schema.Value.Enum != nil && len(value.Schema.Value.Enum) > 0 {
paramValue = value.Schema.Value.Enum[0]
} else {
if !opts.opts.SkipFormatValidation {
@@ -270,10 +253,6 @@ func generateRequestsFromOp(opts *generateReqOptions) error {
for content, value := range opts.op.RequestBody.Value.Content {
cloned := req.Clone(req.Context())
if value.Schema == nil {
// skip if schema is not present this is most likely a invalid content-type not recognized by openapi
continue
}
example, err := generateExampleFromSchema(value.Schema.Value)
if err != nil {
continue
@@ -395,25 +374,31 @@ func GetGlobalParamsForSecurityRequirement(schema *openapi3.T, requirement *open
if len(schema.Components.SecuritySchemes) == 0 {
return nil, errorutil.NewWithTag("openapi", "security requirements (%+v) without any security schemes found in openapi file", schema.Security)
}
missing := []string{}
found := false
// this api is protected for each security scheme pull its corresponding scheme
schemaLabel:
for _, security := range *requirement {
for name := range security {
if scheme, ok := schema.Components.SecuritySchemes[name]; ok {
found = true
param, err := GenerateParameterFromSecurityScheme(scheme)
if err != nil {
return nil, err
}
globalParams = append(globalParams, &openapi3.ParameterRef{Value: param})
} else {
missing = append(missing, name)
continue schemaLabel
}
}
if !found && len(security) > 1 {
// if this is case then both security schemes are required
return nil, errorutil.NewWithTag("openapi", "security requirement (%+v) not found in openapi file", security)
}
}
if len(missing) > 0 {
return nil, errkit.New("missing schema of following security requirements (%+v)", missing)
if !found {
return nil, errorutil.NewWithTag("openapi", "security requirement (%+v) not found in openapi file", requirement)
}
return globalParams, nil
}
@@ -474,15 +459,3 @@ func GenerateParameterFromSecurityScheme(scheme *openapi3.SecuritySchemeRef) (*o
}
return nil, errorutil.NewWithTag("openapi", "unsupported security scheme type (%s) found in openapi file", scheme.Value.Type)
}
func fileNameFromTitle(title string) string {
parts := strings.Fields(title)
if len(parts) == 0 {
return "openapi_vars.txt"
}
if len(parts) > 2 {
parts = parts[:2]
}
fileName := strings.ToLower(strings.Join(parts, "_"))
return fileName + "_vars.txt"
}
+2 -7
View File
@@ -2,7 +2,6 @@ package swagger
import (
"encoding/json"
"io"
"os"
"path"
@@ -11,7 +10,7 @@ import (
"github.com/pkg/errors"
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats/openapi"
"github.com/invopop/yaml"
"gopkg.in/yaml.v2"
"github.com/getkin/kin-openapi/openapi2conv"
)
@@ -50,11 +49,7 @@ func (j *SwaggerFormat) Parse(input string, resultsCb formats.ParseReqRespCallba
ext := path.Ext(input)
if ext == ".yaml" || ext == ".yml" {
data, err_data := io.ReadAll(file)
if err_data != nil {
return errors.Wrap(err, "could not read data file")
}
err = yaml.Unmarshal(data, schemav2)
err = yaml.NewDecoder(file).Decode(schemav2)
} else {
err = json.NewDecoder(file).Decode(schemav2)
}
+2 -2
View File
@@ -27,8 +27,8 @@ func TestSwaggerAPIParser(t *testing.T) {
}
expectedURLs := []string{
"https://localhost/v1/users",
"https://localhost/v1/users/1?test=asc",
"https://localhost/users",
"https://localhost/users/1?test=asc",
}
require.ElementsMatch(t, gotMethodsToURLs, expectedURLs, "could not get swagger urls")
}
+3 -4
View File
@@ -66,10 +66,9 @@ func (i *HttpInputProvider) Count() int64 {
// Iterate over all inputs in order
func (i *HttpInputProvider) Iterate(callback func(value *contextargs.MetaInput) bool) {
err := i.format.Parse(i.inputFile, func(request *types.RequestResponse) bool {
metaInput := contextargs.NewMetaInput()
metaInput.ReqResp = request
metaInput.Input = request.URL.String()
return callback(metaInput)
return callback(&contextargs.MetaInput{
ReqResp: request,
})
})
if err != nil {
gologger.Warning().Msgf("Could not parse input file while iterating: %s\n", err)
+22 -3
View File
@@ -1,17 +1,19 @@
package provider
import (
"errors"
"fmt"
"strings"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider/http"
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider/list"
"github.com/projectdiscovery/nuclei/v3/pkg/input/types"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
configTypes "github.com/projectdiscovery/nuclei/v3/pkg/types"
errorutil "github.com/projectdiscovery/utils/errors"
stringsutil "github.com/projectdiscovery/utils/strings"
)
var (
@@ -30,7 +32,7 @@ func IsErrNotImplemented(err error) bool {
if err == nil {
return false
}
if stringsutil.ContainsAll(err.Error(), "provider", "does not implement") {
if strings.Contains(err.Error(), "provider") && strings.Contains(err.Error(), "does not implement") {
return true
}
return false
@@ -79,6 +81,23 @@ type InputOptions struct {
// NewInputProvider creates a new input provider based on the options
// and returns it
func NewInputProvider(opts InputOptions) (InputProvider, error) {
// optionally load generated vars values if available
val, err := formats.ReadOpenAPIVarDumpFile()
if err != nil && !errors.Is(err, formats.ErrNoVarsDumpFile) {
// log error and continue
gologger.Error().Msgf("Could not read vars dump file: %s\n", err)
}
extraVars := make(map[string]interface{})
if val != nil {
for _, v := range val.Var {
v = strings.TrimSpace(v)
// split into key value
parts := strings.SplitN(v, "=", 2)
if len(parts) == 2 {
extraVars[parts[0]] = parts[1]
}
}
}
// check if input provider is supported
if strings.EqualFold(opts.Options.InputFileMode, "list") {
@@ -93,7 +112,7 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
InputFile: opts.Options.TargetsFilePath,
InputMode: opts.Options.InputFileMode,
Options: formats.InputFormatOptions{
Variables: opts.Options.Vars.AsMap(),
Variables: generators.MergeMaps(extraVars, opts.Options.Vars.AsMap()),
SkipFormatValidation: opts.Options.SkipFormatValidation,
RequiredOnly: opts.Options.FormatUseRequiredOnly,
},
+13 -27
View File
@@ -122,7 +122,7 @@ func (i *ListInputProvider) Iterate(callback func(value *contextargs.MetaInput)
})
}
callbackFunc := func(k, _ []byte) error {
metaInput := contextargs.NewMetaInput()
metaInput := &contextargs.MetaInput{}
if err := metaInput.Unmarshal(string(k)); err != nil {
return err
}
@@ -153,16 +153,14 @@ func (i *ListInputProvider) Set(value string) {
}
return fmt.Sprintf("got empty hostname for %v skipping ip selection", URL)
})
metaInput := contextargs.NewMetaInput()
metaInput.Input = URL
metaInput := &contextargs.MetaInput{Input: URL}
i.setItem(metaInput)
return
}
// Check if input is ip or hostname
if iputil.IsIP(urlx.Hostname()) {
metaInput := contextargs.NewMetaInput()
metaInput.Input = URL
metaInput := &contextargs.MetaInput{Input: URL}
i.setItem(metaInput)
return
}
@@ -183,9 +181,7 @@ func (i *ListInputProvider) Set(value string) {
if ip == "" {
continue
}
metaInput := contextargs.NewMetaInput()
metaInput.Input = value
metaInput.CustomIP = ip
metaInput := &contextargs.MetaInput{Input: value, CustomIP: ip}
i.setItem(metaInput)
}
return
@@ -215,13 +211,11 @@ func (i *ListInputProvider) Set(value string) {
}
for _, ip := range ips {
metaInput := contextargs.NewMetaInput()
if ip != "" {
metaInput.Input = URL
metaInput.CustomIP = ip
metaInput := &contextargs.MetaInput{Input: URL, CustomIP: ip}
i.setItem(metaInput)
} else {
metaInput.Input = URL
metaInput := &contextargs.MetaInput{Input: URL}
i.setItem(metaInput)
}
}
@@ -359,8 +353,7 @@ func (i *ListInputProvider) scanInputFromReader(reader io.Reader) {
// isExcluded checks if a URL is in the exclusion list
func (i *ListInputProvider) isExcluded(URL string) bool {
metaInput := contextargs.NewMetaInput()
metaInput.Input = URL
metaInput := &contextargs.MetaInput{Input: URL}
key, err := metaInput.MarshalString()
if err != nil {
gologger.Warning().Msgf("%s\n", err)
@@ -385,16 +378,14 @@ func (i *ListInputProvider) Del(value string) {
}
return fmt.Sprintf("got empty hostname for %v skipping ip selection", URL)
})
metaInput := contextargs.NewMetaInput()
metaInput.Input = URL
metaInput := &contextargs.MetaInput{Input: URL}
i.delItem(metaInput)
return
}
// Check if input is ip or hostname
if iputil.IsIP(urlx.Hostname()) {
metaInput := contextargs.NewMetaInput()
metaInput.Input = URL
metaInput := &contextargs.MetaInput{Input: URL}
i.delItem(metaInput)
return
}
@@ -415,9 +406,7 @@ func (i *ListInputProvider) Del(value string) {
if ip == "" {
continue
}
metaInput := contextargs.NewMetaInput()
metaInput.Input = value
metaInput.CustomIP = ip
metaInput := &contextargs.MetaInput{Input: value, CustomIP: ip}
i.delItem(metaInput)
}
return
@@ -447,13 +436,11 @@ func (i *ListInputProvider) Del(value string) {
}
for _, ip := range ips {
metaInput := contextargs.NewMetaInput()
if ip != "" {
metaInput.Input = URL
metaInput.CustomIP = ip
metaInput := &contextargs.MetaInput{Input: URL, CustomIP: ip}
i.delItem(metaInput)
} else {
metaInput.Input = URL
metaInput := &contextargs.MetaInput{Input: URL}
i.delItem(metaInput)
}
}
@@ -527,8 +514,7 @@ func (i *ListInputProvider) addTargets(targets []string) {
func (i *ListInputProvider) removeTargets(targets []string) {
for _, target := range targets {
metaInput := contextargs.NewMetaInput()
metaInput.Input = target
metaInput := &contextargs.MetaInput{Input: target}
i.delItem(metaInput)
}
}
+4 -12
View File
@@ -13,7 +13,6 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
"github.com/projectdiscovery/nuclei/v3/pkg/types"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/expand"
"github.com/projectdiscovery/utils/auth/pdcp"
"github.com/stretchr/testify/require"
)
@@ -40,7 +39,7 @@ func Test_expandCIDR(t *testing.T) {
// scan
got := []string{}
input.hostMap.Scan(func(k, _ []byte) error {
metainput := contextargs.NewMetaInput()
var metainput contextargs.MetaInput
if err := metainput.Unmarshal(string(k)); err != nil {
return err
}
@@ -69,7 +68,7 @@ func (m *mockDnsHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
msg.Authoritative = true
domain := msg.Question[0].Name
msg.Answer = append(msg.Answer, &dns.AAAA{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 60},
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 60},
AAAA: net.ParseIP("2400:6180:0:d0::91:1001"),
})
}
@@ -141,7 +140,7 @@ func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
// scan
got := []string{}
input.hostMap.Scan(func(k, v []byte) error {
metainput := contextargs.NewMetaInput()
var metainput contextargs.MetaInput
if err := metainput.Unmarshal(string(k)); err != nil {
return err
}
@@ -154,13 +153,6 @@ func Test_scanallips_normalizeStoreInputValue(t *testing.T) {
}
func Test_expandASNInputValue(t *testing.T) {
// skip this test if pdcp keys are not present
h := pdcp.PDCPCredHandler{}
creds, err := h.GetCreds()
if err != nil || creds == nil || creds.APIKey == "" {
t.Logf("Skipping asnmap test as pdcp keys are not present")
t.SkipNow()
}
tests := []struct {
asn string
expectedOutputFile string
@@ -184,7 +176,7 @@ func Test_expandASNInputValue(t *testing.T) {
// scan the hmap
got := []string{}
input.hostMap.Scan(func(k, v []byte) error {
metainput := contextargs.NewMetaInput()
var metainput contextargs.MetaInput
if err := metainput.Unmarshal(string(k)); err != nil {
return err
}
+3 -9
View File
@@ -43,9 +43,7 @@ func (s *SimpleInputProvider) Iterate(callback func(value *contextargs.MetaInput
// Set adds an item to the input provider
func (s *SimpleInputProvider) Set(value string) {
metaInput := contextargs.NewMetaInput()
metaInput.Input = value
s.Inputs = append(s.Inputs, metaInput)
s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: value})
}
// SetWithProbe adds an item to the input provider with HTTP probing
@@ -54,17 +52,13 @@ func (s *SimpleInputProvider) SetWithProbe(value string, probe types.InputLivene
if err != nil {
return err
}
metaInput := contextargs.NewMetaInput()
metaInput.Input = probedValue
s.Inputs = append(s.Inputs, metaInput)
s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: probedValue})
return nil
}
// SetWithExclusions adds an item to the input provider if it doesn't match any of the exclusions
func (s *SimpleInputProvider) SetWithExclusions(value string) error {
metaInput := contextargs.NewMetaInput()
metaInput.Input = value
s.Inputs = append(s.Inputs, metaInput)
s.Inputs = append(s.Inputs, &contextargs.MetaInput{Input: value})
return nil
}
+1 -12
View File
@@ -47,8 +47,6 @@ func (h *Helper) Transform(input string, protocol templateTypes.ProtocolType) st
return h.convertInputToType(input, typeHostWithOptionalPort, "")
case templateTypes.WebsocketProtocol:
return h.convertInputToType(input, typeWebsocket, "")
case templateTypes.SSLProtocol:
return h.convertInputToType(input, typeHostWithPort, "443")
}
return input
}
@@ -96,8 +94,6 @@ func (h *Helper) convertInputToType(input string, inputType inputType, defaultPo
if _, err := filepath.Match(input, ""); err != filepath.ErrBadPattern && !isURL {
return input
}
// if none of these satisfy the condition return empty
return ""
case typeHostOnly:
if hasHost {
return host
@@ -115,10 +111,6 @@ func (h *Helper) convertInputToType(input string, inputType inputType, defaultPo
return string(probed)
}
}
// try to parse it as absolute url and return
if absUrl, err := urlutil.ParseAbsoluteURL(input, false); err == nil {
return absUrl.String()
}
case typeHostWithPort, typeHostWithOptionalPort:
if hasHost && hasPort {
return net.JoinHostPort(host, port)
@@ -136,9 +128,6 @@ func (h *Helper) convertInputToType(input string, inputType inputType, defaultPo
if uri != nil && stringsutil.EqualFoldAny(uri.Scheme, "ws", "wss") {
return input
}
// empty if prefix is not given
return ""
}
// do not return empty
return input
return ""
}
+2 -2
View File
@@ -30,7 +30,7 @@ func TestConvertInputToType(t *testing.T) {
{"https://google.com:443", typeHostOnly, "google.com", ""},
// url
{"test.com", typeURL, "test.com", ""},
{"test.com", typeURL, "", ""},
{"google.com", typeURL, "https://google.com", ""},
{"https://google.com", typeURL, "https://google.com", ""},
@@ -43,7 +43,7 @@ func TestConvertInputToType(t *testing.T) {
{"input_test.*", typeFilepath, "input_test.*", ""},
// host-port
{"google.com", typeHostWithPort, "google.com", ""},
{"google.com", typeHostWithPort, "", ""},
{"google.com:443", typeHostWithPort, "google.com:443", ""},
{"https://google.com", typeHostWithPort, "google.com:443", ""},
{"https://google.com:443", typeHostWithPort, "google.com:443", ""},
+2 -11
View File
@@ -12,7 +12,6 @@ import (
"sync"
"github.com/projectdiscovery/retryablehttp-go"
"github.com/projectdiscovery/useragent"
"github.com/projectdiscovery/utils/conversion"
mapsutil "github.com/projectdiscovery/utils/maps"
urlutil "github.com/projectdiscovery/utils/url"
@@ -74,10 +73,6 @@ func (rr *RequestResponse) BuildRequest() (*retryablehttp.Request, error) {
req.Header.Add(k, v)
return true
})
if req.Header.Get("User-Agent") == "" {
userAgent := useragent.PickRandom()
req.Header.Set("User-Agent", userAgent.Raw)
}
rr.req = req
})
return rr.req, rr.reqErr
@@ -123,15 +118,11 @@ func (rr *RequestResponse) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &m); err != nil {
return err
}
urlStrRaw, ok := m["url"]
urlStr, ok := m["url"]
if !ok {
return fmt.Errorf("missing url in request response")
}
var urlStr string
if err := json.Unmarshal(urlStrRaw, &urlStr); err != nil {
return err
}
parsed, err := urlutil.ParseAbsoluteURL(urlStr, false)
parsed, err := urlutil.ParseAbsoluteURL(string(urlStr), false)
if err != nil {
return err
}
Loaded 100 of 227 files, more files were not shown because too many files have changed in this diff. Show more