mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2026-11-08 02:08:33 -10:00
Compare commits
305
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38f25f5263 | ||
|
|
0fc4a02a05 | ||
|
|
b649829bc3 | ||
|
|
9a3053e9be | ||
|
|
889972f3de | ||
|
|
f7d30f6389 | ||
|
|
36aae9cc55 | ||
|
|
a12bd9fbf8 | ||
|
|
4bb9374207 | ||
|
|
16735f5243 | ||
|
|
557b4fba38 | ||
|
|
1f985459b8 | ||
|
|
3a07fa9c22 | ||
|
|
b2d4efef1e | ||
|
|
36262a4152 | ||
|
|
7fb7b7ad92 | ||
|
|
a0ec8a0546 | ||
|
|
a229666d41 | ||
|
|
e0ea25d856 | ||
|
|
13dfe8802a | ||
|
|
97b8c510a1 | ||
|
|
fa6a7e8486 | ||
|
|
fbe2981e8d | ||
|
|
436c386272 | ||
|
|
28abf56e75 | ||
|
|
a09fcc196b | ||
|
|
2b4b058886 | ||
|
|
63687c2ce0 | ||
|
|
abfd43268a | ||
|
|
b046f7686f | ||
|
|
13af7ccd49 | ||
|
|
40c83ddb18 | ||
|
|
e07c61689e | ||
|
|
91a18c79fc | ||
|
|
c76421d3d8 | ||
|
|
26311c1668 | ||
|
|
e7d628c414 | ||
|
|
54e81c96f1 | ||
|
|
afc24616a4 | ||
|
|
ba6a050d48 | ||
|
|
3e4ec90cea | ||
|
|
9fdb5cd5b6 | ||
|
|
f0b87ac26e | ||
|
|
49f1de351f | ||
|
|
4cd697ed3f | ||
|
|
c096c7a808 | ||
|
|
cc1941b634 | ||
|
|
ba99750956 | ||
|
|
444f824167 | ||
|
|
31016178e2 | ||
|
|
529ac9d749 | ||
|
|
7547f1a5c3 | ||
|
|
6cb670d260 | ||
|
|
afb5a7ce59 | ||
|
|
465800fb21 | ||
|
|
267997ef60 | ||
|
|
4fcecb16d8 | ||
|
|
bc27db2541 | ||
|
|
402c286a8e | ||
|
|
97403c203e | ||
|
|
b57d086afc | ||
|
|
9339b53002 | ||
|
|
a1e5d181ec | ||
|
|
2f1398832a | ||
|
|
4da1554dc4 | ||
|
|
db002068c8 | ||
|
|
3b50a1fcdb | ||
|
|
4d02224880 | ||
|
|
2039b5c43e | ||
|
|
40a08a4db3 | ||
|
|
88b460c2e3 | ||
|
|
8a4be44631 | ||
|
|
49811d24a1 | ||
|
|
cb1bbff0f0 | ||
|
|
ebdabef420 | ||
|
|
0442aa79da | ||
|
|
7a9facfc26 | ||
|
|
abc63f1f8d | ||
|
|
f5f5f5fc21 | ||
|
|
efb27cfd49 | ||
|
|
5f952fc87a | ||
|
|
505ebc752f | ||
|
|
44f398c08d | ||
|
|
d7c8c8af80 | ||
|
|
7e4b4a8c55 | ||
|
|
92213e1335 | ||
|
|
159a8a53cf | ||
|
|
98948d0266 | ||
|
|
2c832f5590 | ||
|
|
53f56e179d | ||
|
|
cc5c5509dc | ||
|
|
aab2cadb64 | ||
|
|
4ef058758c | ||
|
|
d68af67e6e | ||
|
|
888a732fbc | ||
|
|
3f0de96726 | ||
|
|
1cd42c46c7 | ||
|
|
82680980a5 | ||
|
|
690089e1ce | ||
|
|
f0624820d3 | ||
|
|
7ba5d51b00 | ||
|
|
8b9acb2927 | ||
|
|
23825c77b2 | ||
|
|
ed3e06a701 | ||
|
|
d0463e8ca3 | ||
|
|
d1614857bd | ||
|
|
1f945d6d50 | ||
|
|
e4dae52d5a | ||
|
|
c9f67897c4 | ||
|
|
c93a2b1ba4 | ||
|
|
6a561c6470 | ||
|
|
828dac9002 | ||
|
|
9983d7415c | ||
|
|
a118daa375 | ||
|
|
b8e818ac29 | ||
|
|
3e6c62b03b | ||
|
|
182e000f2c | ||
|
|
21205253c3 | ||
|
|
b18f99e462 | ||
|
|
694835c459 | ||
|
|
3eee9678d0 | ||
|
|
b69de15777 | ||
|
|
1610d96bc2 | ||
|
|
6347efa590 | ||
|
|
4cd065df5f | ||
|
|
3d2f31a56f | ||
|
|
0a536e6ce0 | ||
|
|
c8cc419e81 | ||
|
|
87e99be4f6 | ||
|
|
2ac9aaf871 | ||
|
|
a45e4bbd19 | ||
|
|
72da91a399 | ||
|
|
bd6330f72a | ||
|
|
8b1d9aa0d7 | ||
|
|
39f8be2125 | ||
|
|
59e69b561d | ||
|
|
fcdead9157 | ||
|
|
f7f8d53019 | ||
|
|
4ef78ae5fa | ||
|
|
e88c7e31d0 | ||
|
|
7f4cdf6196 | ||
|
|
6b0ba0f4f3 | ||
|
|
cc332979aa | ||
|
|
2b5a8f5b63 | ||
|
|
f30d0b3b8d | ||
|
|
042b33de3d | ||
|
|
5bb730849c | ||
|
|
7bc257d7a5 | ||
|
|
04a6159713 | ||
|
|
0c4c0af4e9 | ||
|
|
cb05f55251 | ||
|
|
841d8913e5 | ||
|
|
9a5272985c | ||
|
|
fdb8e0a8c6 | ||
|
|
88b281ae47 | ||
|
|
e0b2542868 | ||
|
|
6b71af448a | ||
|
|
bf58b4d756 | ||
|
|
aac1af1308 | ||
|
|
4a85e73fbb | ||
|
|
c23e1864d6 | ||
|
|
2670b6865f | ||
|
|
b424ba9f50 | ||
|
|
faed7798fc | ||
|
|
253fbc3619 | ||
|
|
4a39fdb8d6 | ||
|
|
5627da8c19 | ||
|
|
710f1ad240 | ||
|
|
56af26a502 | ||
|
|
8e1072e2b0 | ||
|
|
b53b530b6a | ||
|
|
bfdc507c6c | ||
|
|
ddf9b2fbec | ||
|
|
5e102b782b | ||
|
|
d1f4c98cd7 | ||
|
|
87c8cd8e01 | ||
|
|
35a0d673ad | ||
|
|
46782ff90c | ||
|
|
b1152efd42 | ||
|
|
d84aea93cc | ||
|
|
50023428d0 | ||
|
|
7af08e2b04 | ||
|
|
3064788d35 | ||
|
|
0da993afe6 | ||
|
|
4d5eb9c484 | ||
|
|
8a3818230d | ||
|
|
943a6f6643 | ||
|
|
091ca32b1c | ||
|
|
326f8774fd | ||
|
|
c94d226a49 | ||
|
|
c9fe07557c | ||
|
|
e16350cde6 | ||
|
|
0f79044dae | ||
|
|
c6bafd88eb | ||
|
|
80b3cc0627 | ||
|
|
02fadbcf77 | ||
|
|
f2f250738c | ||
|
|
1c76398aea | ||
|
|
0675aa48a3 | ||
|
|
f29b94521e | ||
|
|
d20ec34f63 | ||
|
|
1af29f97a9 | ||
|
|
1293a34707 | ||
|
|
c6e5bdd857 | ||
|
|
2f7eea410d | ||
|
|
2609d2d135 | ||
|
|
e0466e102c | ||
|
|
1e49cd9800 | ||
|
|
a5c7fe6094 | ||
|
|
2e6c3821ff | ||
|
|
9019e36be5 | ||
|
|
f363b307d4 | ||
|
|
153b9394f6 | ||
|
|
c6a2e57a25 | ||
|
|
0b90504a0d | ||
|
|
3a6625bf26 | ||
|
|
1643f51839 | ||
|
|
543c834173 | ||
|
|
350fa4c10c | ||
|
|
653ea98b21 | ||
|
|
3f8c37c9e9 | ||
|
|
a7b815d561 | ||
|
|
b5b26ba378 | ||
|
|
9fa178f64e | ||
|
|
de29517572 | ||
|
|
b84488e1cd | ||
|
|
4316943601 | ||
|
|
6179e9dd41 | ||
|
|
471d6730f4 | ||
|
|
2df1b2e88e | ||
|
|
ddcc9211be | ||
|
|
0787ff29e0 | ||
|
|
ff23949bb0 | ||
|
|
2655c29458 | ||
|
|
64885dcde6 | ||
|
|
38e130201e | ||
|
|
0c325b1453 | ||
|
|
e34fb3162e | ||
|
|
59575116f8 | ||
|
|
82e6f0c1c2 | ||
|
|
372eab80c8 | ||
|
|
ec0a8ba3ab | ||
|
|
980ca115fa | ||
|
|
cafe13afdf | ||
|
|
24f4ad545a | ||
|
|
c67a579ab1 | ||
|
|
2418319df4 | ||
|
|
6d325a4ebe | ||
|
|
33dbb51505 | ||
|
|
f930e9a58f | ||
|
|
cb2e6523f9 | ||
|
|
c5a3949473 | ||
|
|
1fa0e2b473 | ||
|
|
9f08fe21d8 | ||
|
|
33464a39c7 | ||
|
|
0e881ebb78 | ||
|
|
5b2897cc20 | ||
|
|
ec682695b6 | ||
|
|
01b9ddad4c | ||
|
|
327a15f94f | ||
|
|
1b33bdd4e3 | ||
|
|
b4669b398e | ||
|
|
d7d5adff53 | ||
|
|
90bbecb51c | ||
|
|
59e936399b | ||
|
|
d776dbb2dd | ||
|
|
0433c83730 | ||
|
|
f1253e16c9 | ||
|
|
efc01c90c5 | ||
|
|
6c32eb7d1e | ||
|
|
6cbd73f780 | ||
|
|
ebbfcadb9a | ||
|
|
7f3c5e5083 | ||
|
|
26e6127755 | ||
|
|
2e78b50f80 | ||
|
|
455a900a96 | ||
|
|
ceea533681 | ||
|
|
f50d39b28a | ||
|
|
deb0dd2a5f | ||
|
|
3e1cd27943 | ||
|
|
0b71d983a5 | ||
|
|
bc229a46ca | ||
|
|
49d8579662 | ||
|
|
f080d614c3 | ||
|
|
8f22eb596e | ||
|
|
d4e81fd9e6 | ||
|
|
d7997e47ec | ||
|
|
cdb39d851b | ||
|
|
860507bbe9 | ||
|
|
2bd68993e7 | ||
|
|
3c2af0e47c | ||
|
|
ead444b88b | ||
|
|
c9a9bd3bfc | ||
|
|
1c24ceda45 | ||
|
|
5cb32a4310 | ||
|
|
42bb6d705f | ||
|
|
ec89a23bc5 | ||
|
|
e90554443e | ||
|
|
3ff085c5ed | ||
|
|
1e3cfd75ea | ||
|
|
34599eabb9 | ||
|
|
68cac06818 | ||
|
|
b4b106db99 | ||
|
|
2b89a2e1a0 | ||
|
|
c7006a9168 |
No files matched your search
@@ -0,0 +1,72 @@
|
||||
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
|
||||
@@ -0,0 +1,37 @@
|
||||
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
|
||||
@@ -1,21 +0,0 @@
|
||||
---
|
||||
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. -->
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
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! -->
|
||||
@@ -0,0 +1,8 @@
|
||||
addReviewers: true
|
||||
reviewers:
|
||||
- dogancanbakir
|
||||
- dwisiswant0
|
||||
|
||||
numberOfReviewers: 1
|
||||
skipKeywords:
|
||||
- '@dependabot'
|
||||
@@ -1,10 +1,12 @@
|
||||
name: 🤖 dep auto merge
|
||||
name: 🤖 Auto Merge
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
workflow_run:
|
||||
workflows: ["♾️ Compatibility Check"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
@@ -12,11 +14,11 @@ permissions:
|
||||
repository-projects: write
|
||||
|
||||
jobs:
|
||||
automerge:
|
||||
auto-merge:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.DEPENDABOT_PAT }}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
name: 🔨 Build Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Test Builds
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.21.x]
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- 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: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Go Mod hygiene
|
||||
run: |
|
||||
go clean -modcache
|
||||
go mod tidy
|
||||
|
||||
- name: Build
|
||||
run: go build .
|
||||
working-directory: cmd/nuclei/
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
|
||||
run: go test ./...
|
||||
|
||||
- name: Integration Tests
|
||||
timeout-minutes: 50
|
||||
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 }}
|
||||
working-directory: integration_tests/
|
||||
|
||||
- name: Race Condition Tests
|
||||
if: ${{ matrix.os != 'windows-latest' }} # known issue: https://github.com/golang/go/issues/46099
|
||||
run: go run -race . -l ../functional-test/targets.txt -id tech-detect,tls-version
|
||||
working-directory: cmd/nuclei/
|
||||
|
||||
- name: Example SDK Simple
|
||||
run: go run .
|
||||
working-directory: examples/simple/
|
||||
|
||||
- name: Example SDK Advanced
|
||||
run: go run .
|
||||
working-directory: examples/advanced/
|
||||
|
||||
- name: Example SDK with speed control
|
||||
run: go run .
|
||||
working-directory: examples/with_speed_control/
|
||||
@@ -1,39 +0,0 @@
|
||||
name: 🚨 CodeQL Analysis
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
@@ -0,0 +1,19 @@
|
||||
name: ♾️ Compatibility Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
branches:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
check:
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- run: go mod download && go mod verify && go vet ./...
|
||||
@@ -1,4 +1,4 @@
|
||||
name: 🌥 Docker Push
|
||||
name: 🐳 Docker Push
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
steps:
|
||||
- name: Git Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get GitHub tag
|
||||
id: meta
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
name: 🧪 Functional Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.go'
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
jobs:
|
||||
functional:
|
||||
name: Functional Test
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Functional Tests
|
||||
env:
|
||||
GH_ACTION: true
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
run: |
|
||||
chmod +x run.sh
|
||||
bash run.sh ${{ matrix.os }}
|
||||
working-directory: cmd/functional-test
|
||||
@@ -0,0 +1,27 @@
|
||||
name: ⏰ Generate Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish-docs:
|
||||
if: "${{ !endsWith(github.actor, '[bot]') }}"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/setup/git@v1
|
||||
- run: make syntax-docs
|
||||
- run: git status -s | wc -l | xargs -I {} echo CHANGES={} >> $GITHUB_OUTPUT
|
||||
id: status
|
||||
- uses: projectdiscovery/actions/commit@v1
|
||||
if: steps.status.outputs.CHANGES > 0
|
||||
with:
|
||||
files: |
|
||||
SYNTAX-REFERENCE.md
|
||||
nuclei-jsonschema.json
|
||||
message: 'docs: update syntax & JSON schema 🤖'
|
||||
- run: git push origin $GITHUB_REF
|
||||
@@ -1,27 +0,0 @@
|
||||
name: 🙏🏻 Lint Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/[email protected]
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout 5m
|
||||
@@ -0,0 +1,25 @@
|
||||
name: 🔨 Performance Test
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # Weekly
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
perf-test:
|
||||
strategy:
|
||||
matrix:
|
||||
count: [50, 100, 150]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'projectdiscovery/nuclei'
|
||||
env:
|
||||
LIST_FILE: "/tmp/targets-${{ matrix.count }}.txt"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- run: make verify
|
||||
- name: Generate list
|
||||
run: for i in {1..${{ matrix.count }}}; do echo "https://scanme.sh/?_=${i}" >> "${LIST_FILE}"; done
|
||||
- run: go run -race . -l "${LIST_FILE}"
|
||||
working-directory: cmd/nuclei/
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
name: 🔨 Performance Test
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Weekly
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
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: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- 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
|
||||
run: go run -race . -l ../functional-test/targets-150.txt
|
||||
working-directory: cmd/nuclei/
|
||||
@@ -1,48 +0,0 @@
|
||||
name: ⏰ Publish Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: "Set up Go"
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: Generate YAML Syntax Documentation
|
||||
id: generate-docs
|
||||
run: |
|
||||
if ! which dstdocgen > /dev/null; then
|
||||
echo -e "Command dstdocgen not found! Installing\c"
|
||||
go install github.com/projectdiscovery/yamldoc-go/cmd/docgen/dstdocgen@main
|
||||
fi
|
||||
go generate pkg/templates/templates.go
|
||||
go build -o "cmd/docgen/docgen" cmd/docgen/docgen.go
|
||||
./cmd/docgen/docgen SYNTAX-REFERENCE.md nuclei-jsonschema.json
|
||||
git status -s | wc -l | xargs -I {} echo CHANGES={} >> $GITHUB_OUTPUT
|
||||
|
||||
- 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
|
||||
|
||||
- name: Push changes
|
||||
if: steps.generate-docs.outputs.CHANGES > 0
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
@@ -1,28 +0,0 @@
|
||||
name: 🔨 Release Test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release-test:
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: release test
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
args: "release --clean --snapshot"
|
||||
version: latest
|
||||
@@ -1,4 +1,4 @@
|
||||
name: 🎉 Release Binary
|
||||
name: 🎉 Release
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -9,22 +9,16 @@ on:
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-go@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/goreleaser@v1
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- uses: goreleaser/goreleaser-action@v4
|
||||
with:
|
||||
args: "release --clean"
|
||||
version: latest
|
||||
release: true
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
SLACK_WEBHOOK: "${{ secrets.RELEASE_SLACK_WEBHOOK }}"
|
||||
DISCORD_WEBHOOK_ID: "${{ secrets.DISCORD_WEBHOOK_ID }}"
|
||||
DISCORD_WEBHOOK_TOKEN: "${{ secrets.DISCORD_WEBHOOK_TOKEN }}"
|
||||
DISCORD_WEBHOOK_TOKEN: "${{ secrets.DISCORD_WEBHOOK_TOKEN }}"
|
||||
@@ -1,23 +0,0 @@
|
||||
name: 🛠 Template Validate
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.go'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.21.x
|
||||
|
||||
- name: Template Validation
|
||||
run: |
|
||||
go run . -ut
|
||||
go run . -validate
|
||||
go run . -validate -w workflows
|
||||
working-directory: cmd/nuclei/
|
||||
@@ -0,0 +1,135 @@
|
||||
name: 🔨 Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["dev"]
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: "Lint"
|
||||
if: "${{ !endsWith(github.actor, '[bot]') }}"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/golangci-lint@v1
|
||||
|
||||
tests:
|
||||
name: "Tests"
|
||||
needs: ["lint"]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
runs-on: "${{ matrix.os }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- run: make vet
|
||||
- run: make build
|
||||
- run: make test
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
|
||||
- run: go run -race . -l ../functional-test/targets.txt -id tech-detect,tls-version
|
||||
if: ${{ matrix.os != 'windows-latest' }} # known issue: https://github.com/golang/go/issues/46099
|
||||
working-directory: cmd/nuclei/
|
||||
|
||||
sdk:
|
||||
name: "Run example SDK"
|
||||
needs: ["tests"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- name: "Simple"
|
||||
run: go run .
|
||||
working-directory: examples/simple/
|
||||
# - run: go run . # Temporarily disabled very flaky in github actions
|
||||
# working-directory: examples/advanced/
|
||||
- name: "with Speed Control"
|
||||
run: go run .
|
||||
working-directory: examples/with_speed_control/
|
||||
|
||||
integration:
|
||||
name: "Integration tests"
|
||||
needs: ["tests"]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
- run: bash run.sh "${{ matrix.os }}"
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
|
||||
timeout-minutes: 50
|
||||
working-directory: integration_tests/
|
||||
|
||||
functional:
|
||||
name: "Functional tests"
|
||||
needs: ["tests"]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- run: bash run.sh "${{ matrix.os }}"
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
working-directory: cmd/functional-test/
|
||||
|
||||
validate:
|
||||
name: "Template validate"
|
||||
needs: ["tests"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- run: make template-validate
|
||||
|
||||
codeql:
|
||||
name: "CodeQL analysis"
|
||||
needs: ["tests"]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: 'go'
|
||||
- uses: github/codeql-action/autobuild@v2
|
||||
- uses: github/codeql-action/analyze@v2
|
||||
|
||||
release:
|
||||
name: "Release test"
|
||||
needs: ["tests"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/goreleaser@v1
|
||||
+44
-36
@@ -1,43 +1,51 @@
|
||||
# Misc
|
||||
**/*-cache
|
||||
**/*-config
|
||||
**/.cache
|
||||
**/*.DS_Store
|
||||
**/*.exe
|
||||
.devcontainer
|
||||
.gitignore
|
||||
.idea
|
||||
.vscode
|
||||
.devcontainer
|
||||
vendor
|
||||
|
||||
# Binaries
|
||||
/bin/*
|
||||
/bindgen
|
||||
/debug-*
|
||||
/docgen
|
||||
/functional-test
|
||||
/fuzzplayground
|
||||
/integration-test
|
||||
/jsdocgen
|
||||
/main
|
||||
/memogen
|
||||
/nuclei
|
||||
/nuclei-stats*
|
||||
/nuclei_dev
|
||||
/nuclei_main
|
||||
/scan-charts
|
||||
/scrapefunc
|
||||
/scrapefuncs
|
||||
/tsgen
|
||||
|
||||
# Templates
|
||||
/*.yaml
|
||||
|
||||
# Generated docs
|
||||
/dsl.md
|
||||
|
||||
# Junk
|
||||
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
|
||||
*.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
|
||||
/**/debug-*
|
||||
vendor
|
||||
|
||||
# Headless `screenshot` action
|
||||
*.png
|
||||
|
||||
# Profiling & tracing
|
||||
*.prof
|
||||
*.pprof
|
||||
*.trace
|
||||
@@ -381,7 +381,7 @@ func (r *Request) Type() templateTypes.ProtocolType {
|
||||
}
|
||||
```
|
||||
|
||||
Almost all of these protocols have boilerplate functions for which default implementations have been provided in the `providers` package. Examples are the implementation of `Match`, `Extract`, `MakeResultEvent`, GetCompiledOperators`, etc. which are almost same throughout Nuclei protocols code. It is enough to copy-paste them unless customization is required.
|
||||
Almost all of these protocols have boilerplate functions for which default implementations have been provided in the `providers` package. Examples are the implementation of `Match`, `Extract`, `MakeResultEvent`, `GetCompiledOperators`, etc. which are almost same throughout Nuclei protocols code. It is enough to copy-paste them unless customization is required.
|
||||
|
||||
`eventcreator` package offers `CreateEventWithAdditionalOptions` function which can be used to create result events after doing request execution.
|
||||
|
||||
@@ -457,26 +457,49 @@ func (template *Template) compileProtocolRequests(options protocols.ExecuterOpti
|
||||
That's it, you've added a new protocol to Nuclei. The next good step would be to write integration tests which are described in `integration-tests` and `cmd/integration-tests` directories.
|
||||
|
||||
|
||||
## Profiling Instructions
|
||||
## Profiling and Tracing
|
||||
|
||||
To enable dumping of Memory profiling data, `-profile-mem` flag can be used along with path to a file. This writes a pprof formatted file which can be used for investigate resource usage with `pprof` tool.
|
||||
To analyze Nuclei's performance and resource usage, you can generate memory profiles and trace files using the `-profile-mem` flag:
|
||||
|
||||
```console
|
||||
$ nuclei -t nuclei-templates/ -u https://example.com -profile-mem mem.pprof
|
||||
```bash
|
||||
nuclei -t nuclei-templates/ -u https://example.com -profile-mem=nuclei-$(git describe --tags)
|
||||
```
|
||||
|
||||
To view profile data in pprof, first install pprof. Then run the below command -
|
||||
This command creates two files:
|
||||
|
||||
```console
|
||||
$ go tool pprof mem.pprof
|
||||
* `nuclei.prof`: Memory (heap) profile
|
||||
* `nuclei.trace`: Execution trace
|
||||
|
||||
### Analyzing the Memory Profile
|
||||
|
||||
1. View the profile in the terminal:
|
||||
|
||||
```bash
|
||||
go tool pprof nuclei.prof
|
||||
```
|
||||
|
||||
To open a web UI on a port to visualize debug data, the below command can be used.
|
||||
2. Display top memory consumers:
|
||||
|
||||
```console
|
||||
$ go tool pprof -http=:8081 mem.pprof
|
||||
```bash
|
||||
go tool pprof -top nuclei.prof | grep "$(go list -m)" | head -10
|
||||
```
|
||||
|
||||
3. Visualize the profile in a web browser:
|
||||
|
||||
```bash
|
||||
go tool pprof -http=:$(shuf -i 1000-99999 -n 1) nuclei.prof
|
||||
```
|
||||
|
||||
### Analyzing the Trace File
|
||||
|
||||
To examine the execution trace:
|
||||
|
||||
```bash
|
||||
go tool trace nuclei.trace
|
||||
```
|
||||
|
||||
These tools help identify performance bottlenecks and memory leaks, allowing for targeted optimizations of Nuclei's codebase.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- [pkg/reporting](./pkg/reporting) - Reporting modules for nuclei.
|
||||
|
||||
+1
-2
@@ -3,13 +3,12 @@ FROM golang:1.21-alpine AS build-env
|
||||
RUN apk add build-base
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
RUN go mod download
|
||||
RUN go build ./cmd/nuclei
|
||||
|
||||
# Release
|
||||
FROM alpine:3.18.6
|
||||
RUN apk -U upgrade --no-cache \
|
||||
RUN apk upgrade --no-cache \
|
||||
&& apk add --no-cache bind-tools chromium ca-certificates
|
||||
COPY --from=build-env /app/nuclei /usr/local/bin/
|
||||
|
||||
|
||||
@@ -1,62 +1,141 @@
|
||||
# Go parameters
|
||||
GOCMD=go
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOMOD=$(GOCMD) mod
|
||||
GOTEST=$(GOCMD) test
|
||||
GOCMD := go
|
||||
GOBUILD := $(GOCMD) build
|
||||
GOBUILD_OUTPUT :=
|
||||
GOBUILD_PACKAGES :=
|
||||
GOBUILD_ADDITIONAL_ARGS :=
|
||||
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 scan-charts docs test integration functional tidy devtools jsupdate ts fuzzplayground memogen dsl-docs
|
||||
.PHONY: all build build-stats clean devtools-all devtools-bindgen devtools-scrapefuncs
|
||||
.PHONY: devtools-tsgen docs docgen dsl-docs functional fuzzplayground go-build syntax-docs
|
||||
.PHONY: integration jsupdate-all jsupdate-bindgen jsupdate-tsgen memogen scan-charts test
|
||||
.PHONY: tidy ts verify download vet template-validate
|
||||
|
||||
all: build
|
||||
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 dstdocgen > /dev/null; then
|
||||
echo -e "Command not found! Install? (y/n) \c"
|
||||
go get -v github.com/projectdiscovery/yamldoc-go/cmd/docgen/dstdocgen
|
||||
|
||||
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 = ./bin/nuclei
|
||||
build: GOBUILD_PACKAGES = cmd/nuclei/main.go
|
||||
build: go-build
|
||||
|
||||
build-stats: GOBUILD_OUTPUT = ./bin/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 = ./bin/scan-charts
|
||||
scan-charts: GOBUILD_PACKAGES = cmd/scan-charts/main.go
|
||||
scan-charts: go-build
|
||||
|
||||
template-signer: GOBUILD_OUTPUT = ./bin/template-signer
|
||||
template-signer: GOBUILD_PACKAGES = cmd/tools/signer/main.go
|
||||
template-signer: go-build
|
||||
|
||||
docgen: GOBUILD_OUTPUT = ./bin/docgen
|
||||
docgen: GOBUILD_PACKAGES = cmd/docgen/docgen.go
|
||||
docgen: bin = dstdocgen
|
||||
docgen:
|
||||
@if ! which $(bin) >/dev/null; then \
|
||||
echo "Command $(bin) not found! Installing..."; \
|
||||
go install -v github.com/projectdiscovery/yamldoc-go/cmd/docgen/$(bin)@latest; \
|
||||
fi
|
||||
# TODO: FIX THIS PANIC
|
||||
$(GOCMD) generate pkg/templates/templates.go
|
||||
$(GOBUILD) -o "cmd/docgen/docgen" cmd/docgen/docgen.go
|
||||
./cmd/docgen/docgen docs.md nuclei-jsonschema.json
|
||||
$(GOBUILD) -o "${GOBUILD_OUTPUT}" $(GOBUILD_PACKAGES)
|
||||
|
||||
docs: docgen
|
||||
docs:
|
||||
./bin/docgen docs.md nuclei-jsonschema.json
|
||||
|
||||
syntax-docs: docgen
|
||||
syntax-docs:
|
||||
./bin/docgen SYNTAX-REFERENCE.md nuclei-jsonschema.json
|
||||
|
||||
test: GOFLAGS = -race -v
|
||||
test:
|
||||
$(GOTEST) $(GOFLAGS) ./...
|
||||
|
||||
integration:
|
||||
cd integration_tests; bash run.sh
|
||||
|
||||
functional:
|
||||
cd cmd/functional-test; bash run.sh
|
||||
|
||||
tidy:
|
||||
$(GOMOD) tidy
|
||||
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
|
||||
|
||||
download:
|
||||
$(GOMOD) download
|
||||
|
||||
verify: download
|
||||
$(GOMOD) verify
|
||||
|
||||
vet: verify
|
||||
$(GOCMD) vet ./...
|
||||
|
||||
devtools-bindgen: GOBUILD_OUTPUT = ./bin/bindgen
|
||||
devtools-bindgen: GOBUILD_PACKAGES = pkg/js/devtools/bindgen/cmd/bindgen/main.go
|
||||
devtools-bindgen: go-build
|
||||
|
||||
devtools-tsgen: GOBUILD_OUTPUT = ./bin/tsgen
|
||||
devtools-tsgen: GOBUILD_PACKAGES = pkg/js/devtools/tsgen/cmd/tsgen/main.go
|
||||
devtools-tsgen: go-build
|
||||
|
||||
devtools-scrapefuncs: GOBUILD_OUTPUT = ./bin/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 = ./bin/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 = ./bin/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 = ./bin/fuzzplayground
|
||||
fuzzplayground: GOBUILD_PACKAGES = cmd/tools/fuzzplayground/main.go
|
||||
fuzzplayground: LDFLAGS = -s -w
|
||||
fuzzplayground: go-build
|
||||
|
||||
memogen: GOBUILD_OUTPUT = ./bin/memogen
|
||||
memogen: GOBUILD_PACKAGES = cmd/memogen/memogen.go
|
||||
memogen: go-build
|
||||
memogen:
|
||||
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "memogen" cmd/memogen/memogen.go
|
||||
./memogen -src pkg/js/libs -tpl cmd/memogen/function.tpl
|
||||
./$(GOBUILD_OUTPUT) -src pkg/js/libs -tpl cmd/memogen/function.tpl
|
||||
|
||||
dsl-docs: GOBUILD_OUTPUT = ./bin/scrapefuncs
|
||||
dsl-docs: GOBUILD_PACKAGES = pkg/js/devtools/scrapefuncs/main.go
|
||||
dsl-docs:
|
||||
rm -f dsl.md scrapefuncs 2>/dev/null
|
||||
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "scrapefuncs" pkg/js/devtools/scrapefuncs/main.go
|
||||
./scrapefuncs -out dsl.md
|
||||
./$(GOBUILD_OUTPUT) -out dsl.md
|
||||
|
||||
template-validate: build
|
||||
template-validate:
|
||||
./bin/nuclei -ut
|
||||
./bin/nuclei -validate
|
||||
./bin/nuclei -validate -w workflows
|
||||
@@ -1,30 +1,4 @@
|
||||
<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">Fast and customisable vulnerability scanner based on simple YAML based 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">How</a> •
|
||||
<a href="#install-nuclei">Install</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/">Documentation</a> •
|
||||
<a href="#credits">Credits</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">FAQs</a> •
|
||||
<a href="https://discord.gg/projectdiscovery">Join Discord</a>
|
||||
</p>
|
||||

|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
|
||||
@@ -34,78 +8,103 @@
|
||||
<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>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
|
||||
<img src="https://img.shields.io/badge/go-1.21-%2300ADD8.svg?style=for-the-badge&logo=go&logoColor=white">
|
||||
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/overview?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme"><img src="https://img.shields.io/badge/Documentation-%23000000.svg?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1ib29rLW9wZW4iPjxwYXRoIGQ9Ik0xMiA3djE0Ii8+PHBhdGggZD0iTTMgMThhMSAxIDAgMCAxLTEtMVY0YTEgMSAwIDAgMSAxLTFoNWE0IDQgMCAwIDEgNCA0IDQgNCAwIDAgMSA0LTRoNWExIDEgMCAwIDEgMSAxdjEzYTEgMSAwIDAgMS0xIDFoLTZhMyAzIDAgMCAwLTMgMyAzIDMgMCAwIDAtMy0zeiIvPjwvc3ZnPg==&logoColor=white"></a>
|
||||
|
||||
<a href="https://github.com/projectdiscovery/nuclei-templates"><img src="https://img.shields.io/badge/Templates Library-%23000000.svg?style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXNoaWVsZCI+PHBhdGggZD0iTTIwIDEzYzAgNS0zLjUgNy41LTcuNjYgOC45NWExIDEgMCAwIDEtLjY3LS4wMUM3LjUgMjAuNSA0IDE4IDQgMTNWNmExIDEgMCAwIDEgMS0xYzIgMCA0LjUtMS4yIDYuMjQtMi43MmExLjE3IDEuMTcgMCAwIDEgMS41MiAwQzE0LjUxIDMuODEgMTcgNSAxOSA1YTEgMSAwIDAgMSAxIDF6Ii8+PC9zdmc+&logoColor=white"></a>
|
||||
|
||||
<a href="https://discord.gg/projectdiscovery?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme"><img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&logo=discord&logoColor=white"></a>
|
||||
|
||||
---
|
||||
|
||||
Nuclei is used to send requests across targets based on a template, leading to zero false positives and providing fast scanning on a large number of hosts. Nuclei offers scanning for a variety of protocols, including TCP, DNS, HTTP, SSL, File, Whois, Websocket, Headless, Code etc. With powerful and flexible templating, Nuclei can be used to model all kinds of security checks.
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
We have a [dedicated repository](https://github.com/projectdiscovery/nuclei-templates) that houses various type of vulnerability templates contributed by **more than 300** security researchers and engineers.
|
||||
Nuclei is a modern, high-performance vulnerability scanner that leverages simple YAML-based templates. It empowers you to design custom vulnerability detection scenarios that mimic real-world conditions, leading to zero false positives.
|
||||
|
||||
## How it works
|
||||
- Simple YAML format for creating and customizing vulnerability templates.
|
||||
- Contributed by thousands of security professionals to tackle trending vulnerabilities.
|
||||
- Reduce false positives by simulating real-world steps to verify a vulnerability.
|
||||
- Ultra-fast parallel scan processing and request clustering.
|
||||
- Integrate into CI/CD pipelines for vulnerability detection and regression testing.
|
||||
- Supports multiple protocols like TCP, DNS, HTTP, SSL, WHOIS JavaScript, Code and more.
|
||||
- Integrate with Jira, Splunk, GitHub, Elastic, GitLab.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
|
||||
</h3>
|
||||
- [Get Started](#get-started)
|
||||
- [1. Nuclei CLI](#1-nuclei-cli)
|
||||
- [2. Pro and Enterprise Editions](#2-pro-and-enterprise-editions)
|
||||
- [Documentation](#documentation)
|
||||
- [Command Line Flags](#command-line-flags)
|
||||
- [Single target scan](#single-target-scan)
|
||||
- [Scanning multiple targets](#scanning-multiple-targets)
|
||||
- [Network scan](#network-scan)
|
||||
- [Scanning with your custom template](#scanning-with-your-custom-template)
|
||||
- [Connect Nuclei to ProjectDiscovery](#connect-nuclei-to-projectdiscovery)
|
||||
- [Nuclei Templates, Community and Rewards 💎](#nuclei-templates-community-and-rewards-)
|
||||
- [Our Mission](#our-mission)
|
||||
- [Contributors ❤️](#contributors-️)
|
||||
- [License](#license)
|
||||
|
||||
---
|
||||
|
||||
| :exclamation: **Disclaimer** |
|
||||
|---------------------------------|
|
||||
| **This project is in active development**. Expect breaking changes with releases. Review the release changelog before updating. |
|
||||
| This project was primarily built to be used as a standalone CLI tool. **Running nuclei as a service may pose security risks.** It's recommended to use with caution and additional security measures. |
|
||||
| This project is primarily built to be used as a standalone CLI tool. **Running nuclei as a service may pose security risks.** It's recommended to use with caution and additional security measures. |
|
||||
|
||||
# Install Nuclei
|
||||
## Get Started
|
||||
|
||||
Nuclei requires **go1.21** to install successfully. Run the following command to install the latest version -
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
```sh
|
||||
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
|
||||
```
|
||||
Install Nuclei on your machine. Get started by following the installation guide [here](https://docs.projectdiscovery.io/tools/nuclei/install?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme). Additionally, We provide [a free cloud tier](https://cloud.projectdiscovery.io/sign-up) and comes with a generous monthly free limits:
|
||||
|
||||
<details>
|
||||
<summary>Brew</summary>
|
||||
|
||||
```sh
|
||||
brew install nuclei
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Docker</summary>
|
||||
|
||||
```sh
|
||||
docker pull projectdiscovery/nuclei:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
- Store and visualize your vulnerability findings
|
||||
- Write and manage your nuclei templates
|
||||
- Access latest nuclei templates
|
||||
- Discover and store your targets
|
||||
|
||||
**More installation [methods can be found here](https://docs.projectdiscovery.io/tools/nuclei/install).**
|
||||
### **2. Pro and Enterprise Editions**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
For security teams and enterprises, we provide a cloud-hosted service built on top of Nuclei OSS, fine-tuned to help you continuously run vulnerability scans at scale with your team and existing workflows:
|
||||
|
||||
### Nuclei Templates
|
||||
- 50x faster scans
|
||||
- Large scale scanning with high accuracy
|
||||
- Integrations with cloud services (AWS, GCP, Azure, CloudFlare, Fastly, Terraform, Kubernetes)
|
||||
- Jira, Slack, Linear, APIs and Webhooks
|
||||
- Executive and compliance reporting
|
||||
- Plus: Real-time scanning, SAML SSO, SOC 2 compliant platform (with EU and US hosting options), shared team workspaces, and more
|
||||
- We're constantly [adding new features](https://feedback.projectdiscovery.io/changelog)!
|
||||
- **Ideal for:** Pentesters, security teams, and enterprises
|
||||
|
||||
Nuclei has built-in support for automatic template download/update as default since version [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2). [**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) project provides a community-contributed list of ready-to-use templates that is constantly updated.
|
||||
## Documentation
|
||||
|
||||
You may still use the `update-templates` flag to update the nuclei templates at any time; You can write your own checks for your individual workflow and needs following Nuclei's [templating guide](https://docs.projectdiscovery.io/templates/).
|
||||
Browse the full Nuclei [documentation here](https://docs.projectdiscovery.io/tools/nuclei/running). If you’re new to Nuclei, check out our [foundational Youtube series.](https://www.youtube.com/playlist?list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl)
|
||||
|
||||
The YAML DSL reference syntax is available [here](SYNTAX-REFERENCE.md).
|
||||
<p align="center">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<a href="https://www.youtube.com/watch?v=b5qMyQvL1ZA&list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl&utm_source=github&utm_medium=web&utm_campaign=nuclei_readme" target="_blank"><img src="/static/nuclei-getting-started.png" width="350px"></a> <a href="https://www.youtube.com/watch?v=nFXygQdtjyw&utm_source=github&utm_medium=web&utm_campaign=nuclei_readme" target="_blank"><img src="/static/nuclei-write-your-first-template.png" width="350px"></a>
|
||||
|
||||
### Usage
|
||||
</p>
|
||||
|
||||
### Command Line Flags
|
||||
|
||||
To display all the flags for the tool:
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
This will display help for the tool. Here are all the switches it supports.
|
||||
|
||||
<details>
|
||||
<summary>Expand full help flags</summary>
|
||||
|
||||
```console
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
@@ -179,6 +178,7 @@ 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
|
||||
@@ -203,7 +203,6 @@ 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
|
||||
@@ -212,7 +211,6 @@ CONFIGURATIONS:
|
||||
-sip, -source-ip string source ip address to use for network scan
|
||||
-rsr, -response-size-read int max response size to read in bytes
|
||||
-rss, -response-size-save int max response size to read in bytes (default 1048576)
|
||||
-rrt, -response-read-timeout value response read timeout in seconds (default 5s)
|
||||
-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
|
||||
@@ -238,7 +236,7 @@ FUZZING:
|
||||
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) (default shodan)
|
||||
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow,google) (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)
|
||||
@@ -280,23 +278,24 @@ HEADLESS:
|
||||
-lha, -list-headless-action list available headless actions
|
||||
|
||||
DEBUG:
|
||||
-debug show all requests and responses
|
||||
-dreq, -debug-req show all sent requests
|
||||
-dresp, -debug-resp show all received responses
|
||||
-p, -proxy string[] list of http/socks5 proxy to use (comma separated or file input)
|
||||
-pi, -proxy-internal proxy all internal requests
|
||||
-ldf, -list-dsl-function list all supported DSL function signatures
|
||||
-tlog, -trace-log string file to write sent requests trace log
|
||||
-elog, -error-log string file to write sent requests error log
|
||||
-version show nuclei version
|
||||
-hm, -hang-monitor enable nuclei hang monitoring
|
||||
-v, -verbose show verbose output
|
||||
-profile-mem string optional nuclei memory profile dump file
|
||||
-vv display templates loaded for scan
|
||||
-svd, -show-var-dump show variables dump for debugging
|
||||
-ep, -enable-pprof enable pprof debugging server
|
||||
-tv, -templates-version shows the version of the installed nuclei-templates
|
||||
-hc, -health-check run diagnostic check up
|
||||
-debug show all requests and responses
|
||||
-dreq, -debug-req show all sent requests
|
||||
-dresp, -debug-resp show all received responses
|
||||
-p, -proxy string[] list of http/socks5 proxy to use (comma separated or file input)
|
||||
-pi, -proxy-internal proxy all internal requests
|
||||
-ldf, -list-dsl-function list all supported DSL function signatures
|
||||
-tlog, -trace-log string file to write sent requests trace log
|
||||
-elog, -error-log string file to write sent requests error log
|
||||
-version show nuclei version
|
||||
-hm, -hang-monitor enable nuclei hang monitoring
|
||||
-v, -verbose show verbose output
|
||||
-profile-mem string generate memory (heap) profile & trace files
|
||||
-vv display templates loaded for scan
|
||||
-svd, -show-var-dump show variables dump for debugging
|
||||
-vdl, -var-dump-limit int limit the number of characters displayed in var dump (default 255)
|
||||
-ep, -enable-pprof enable pprof debugging server
|
||||
-tv, -templates-version shows the version of the installed nuclei-templates
|
||||
-hc, -health-check run diagnostic check up
|
||||
|
||||
UPDATE:
|
||||
-up, -update update nuclei engine to the latest released version
|
||||
@@ -311,9 +310,13 @@ STATISTICS:
|
||||
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
|
||||
|
||||
CLOUD:
|
||||
-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
|
||||
-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 [DEPRECATED use -dashboard]
|
||||
-sid, -scan-id string upload scan results to existing scan id (optional)
|
||||
-sname, -scan-name string scan name to set (optional)
|
||||
-pd, -dashboard upload / view nuclei results in projectdiscovery cloud (pdcp) UI dashboard
|
||||
-pdu, -dashboard-upload string upload / view nuclei results file (jsonl) in projectdiscovery cloud (pdcp) UI dashboard
|
||||
|
||||
AUTHENTICATION:
|
||||
-sf, -secret-file string[] path to config file containing secrets for nuclei authenticated scan
|
||||
@@ -322,59 +325,189 @@ AUTHENTICATION:
|
||||
|
||||
EXAMPLES:
|
||||
Run nuclei on single host:
|
||||
$ nuclei -target example.com
|
||||
$ nuclei -target example.com
|
||||
|
||||
Run nuclei with specific template directories:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
|
||||
Run nuclei against a list of hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
$ nuclei -list hosts.txt
|
||||
|
||||
Run nuclei with a JSON output:
|
||||
$ nuclei -target example.com -json-export output.json
|
||||
$ nuclei -target example.com -json-export output.json
|
||||
|
||||
Run nuclei with sorted Markdown outputs (with environment variables):
|
||||
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
|
||||
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
|
||||
|
||||
Additional documentation is available at: https://docs.nuclei.sh/getting-started/running
|
||||
```
|
||||
|
||||
### Running Nuclei
|
||||
Additional documentation is available at: [https://docs.nuclei.sh/getting-started/running](https://docs.nuclei.sh/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
See https://docs.projectdiscovery.io/tools/nuclei/running for details on running Nuclei
|
||||
</details>
|
||||
|
||||
### Using Nuclei From Go Code
|
||||
### Single target scan
|
||||
|
||||
Complete guide of using Nuclei as Library/SDK is available at [godoc](https://pkg.go.dev/github.com/projectdiscovery/nuclei/v3/lib#section-readme)
|
||||
To perform a quick scan on web-application:
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com
|
||||
```
|
||||
|
||||
### Scanning multiple targets
|
||||
|
||||
Nuclei can handle bulk scanning by providing a list of targets. You can use a file containing multiple URLs.
|
||||
|
||||
```sh
|
||||
nuclei -targets urls.txt
|
||||
```
|
||||
|
||||
### Network scan
|
||||
|
||||
This will scan the entire subnet for network-related issues, such as open ports or misconfigured services.
|
||||
|
||||
```sh
|
||||
nuclei -target 192.168.1.0/24
|
||||
```
|
||||
|
||||
### Scanning with your custom template
|
||||
|
||||
To write and use your own template, create a `.yaml` file with specific rules, then use it as follows.
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com -t /path/to/your-template.yaml
|
||||
```
|
||||
|
||||
### Connect Nuclei to ProjectDiscovery
|
||||
|
||||
You can run the scans on your machine and upload the results to the cloud platform for further analysis and remediation.
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com -dashboard
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> This feature is absolutely free and does not require any subscription. For a detailed guide, refer to the [documentation](https://docs.projectdiscovery.io/cloud/scanning/nuclei-scan?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme).
|
||||
|
||||
## Nuclei Templates, Community and Rewards 💎
|
||||
[Nuclei templates](https://github.com/projectdiscovery/nuclei-templates) are based on the concepts of YAML based template files that define how the requests will be sent and processed. This allows easy extensibility capabilities to nuclei. The templates are written in YAML which specifies a simple human-readable format to quickly define the execution process.
|
||||
|
||||
Try it online with our free AI powered Nuclei Templates Editor by [clicking here.](https://cloud.projectdiscovery.io/templates)
|
||||
|
||||
Nuclei Templates offer a streamlined way to identify and communicate vulnerabilities, combining essential details like severity ratings and detection methods. This open-source, community-developed tool accelerates threat response and is widely recognized in the cybersecurity world. Nuclei templates are actively contributed by thousands of security researchers globally. We run two programs for our contributors: [Pioneers](https://projectdiscovery.io/pioneers) and [💎 bounties](https://github.com/projectdiscovery/nuclei-templates/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20Bounty%22).
|
||||
|
||||
|
||||
### Resources
|
||||
<p align="left">
|
||||
<a href="/static/nuclei-templates-teamcity.png" target="_blank"><img src="/static/nuclei-templates-teamcity.png" width="1200px" alt="Nuclei template example for detecting TeamCity misconfiguration" /></a>
|
||||
</p>
|
||||
|
||||
You can access the main documentation for Nuclei at https://docs.projectdiscovery.io/tools/nuclei/, and learn more about Nuclei in the cloud with [ProjectDiscovery Cloud Platform](https://cloud.projectdiscovery.io)
|
||||
#### Examples
|
||||
|
||||
See https://docs.projectdiscovery.io/tools/nuclei/resources for more resources and videos about Nuclei!
|
||||
Visit [our documentation](https://docs.projectdiscovery.io/templates/introduction) for use cases and ideas.
|
||||
|
||||
### Credits
|
||||
| Use case | Nuclei template |
|
||||
| :----------------------------------- | :------------------------------------------------- |
|
||||
| Detect known CVEs | **[CVE-2021-44228 (Log4Shell)](https://cloud.projectdiscovery.io/public/CVE-2021-45046)** |
|
||||
| Identify Out-of-Band vulnerabilities | **[Blind SQL Injection via OOB](https://cloud.projectdiscovery.io/public/CVE-2024-22120)** |
|
||||
| SQL Injection detection | **[Generic SQL Injection](https://cloud.projectdiscovery.io/public/CVE-2022-34265)** |
|
||||
| Cross-Site Scripting (XSS) | **[Reflected XSS Detection](https://cloud.projectdiscovery.io/public/CVE-2023-4173)** |
|
||||
| Default or weak passwords | **[Default Credentials Check](https://cloud.projectdiscovery.io/public/airflow-default-login)** |
|
||||
| Secret files or data exposure | **[Sensitive File Disclosure](https://cloud.projectdiscovery.io/public/airflow-configuration-exposure)** |
|
||||
| Identify open redirects | **[Open Redirect Detection](https://cloud.projectdiscovery.io/public/open-redirect)** |
|
||||
| Detect subdomain takeovers | **[Subdomain Takeover Templates](https://cloud.projectdiscovery.io/public/azure-takeover-detection)** |
|
||||
| Security misconfigurations | **[Unprotected Jenkins Console](https://cloud.projectdiscovery.io/public/unauthenticated-jenkins)** |
|
||||
| Weak SSL/TLS configurations | **[SSL Certificate Expiry](https://cloud.projectdiscovery.io/public/expired-ssl)** |
|
||||
| Misconfigured cloud services | **[Open S3 Bucket Detection](https://cloud.projectdiscovery.io/public/s3-public-read-acp)** |
|
||||
| Remote code execution vulnerabilities| **[RCE Detection Templates](https://cloud.projectdiscovery.io/public/CVE-2024-29824)** |
|
||||
| Directory traversal attacks | **[Path Traversal Detection](https://cloud.projectdiscovery.io/public/oracle-fatwire-lfi)** |
|
||||
| File inclusion vulnerabilities | **[Local/Remote File Inclusion](https://cloud.projectdiscovery.io/public/CVE-2023-6977)** |
|
||||
|
||||
|
||||
## Our Mission
|
||||
|
||||
Traditional vulnerability scanners were built decades ago. They are closed-source, incredibly slow, and vendor-driven. Today's attackers are mass exploiting newly released CVEs across the internet within days, unlike the years it used to take. This shift requires a completely different approach to tackling trending exploits on the internet.
|
||||
|
||||
We built Nuclei to solve this challenge. We made the entire scanning engine framework open and customizable—allowing the global security community to collaborate and tackle the trending attack vectors and vulnerabilities on the internet. Nuclei is now used and contributed by Fortune 500 enterprises, government agencies, universities.
|
||||
|
||||
You can participate by contributing to our code, [templates library](https://github.com/projectdiscovery/nuclei-templates), or [joining our team.](https://projectdiscovery.io/)
|
||||
|
||||
## Contributors :heart:
|
||||
|
||||
Thanks to all the amazing [community contributors for sending PRs](https://github.com/projectdiscovery/nuclei/graphs/contributors) and keeping this project updated. :heart:
|
||||
|
||||
If you have an idea or some kind of improvement, you are welcome to contribute and participate in the Project, feel free to send your 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 align="left">
|
||||
<a href="https://github.com/Ice3man543"><img src="https://avatars.githubusercontent.com/u/22318055?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/apps/dependabot"><img src="https://avatars.githubusercontent.com/in/29110?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ehsandeep"><img src="https://avatars.githubusercontent.com/u/8293321?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Mzack9999"><img src="https://avatars.githubusercontent.com/u/13421144?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/forgedhallpass"><img src="https://avatars.githubusercontent.com/u/13679401?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tarunKoyalwar"><img src="https://avatars.githubusercontent.com/u/45962551?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/manuelbua"><img src="https://avatars.githubusercontent.com/u/819314?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/actions-user"><img src="https://avatars.githubusercontent.com/u/65916846?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/dogancanbakir"><img src="https://avatars.githubusercontent.com/u/65292895?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/parrasajad"><img src="https://avatars.githubusercontent.com/u/16835787?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vzamanillo"><img src="https://avatars.githubusercontent.com/u/10209695?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ShubhamRasal"><img src="https://avatars.githubusercontent.com/u/45902122?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/RamanaReddy0M"><img src="https://avatars.githubusercontent.com/u/90540245?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/LuitelSamikshya"><img src="https://avatars.githubusercontent.com/u/85764322?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kchason"><img src="https://avatars.githubusercontent.com/u/1111099?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/pmareke"><img src="https://avatars.githubusercontent.com/u/3502075?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/dwisiswant0"><img src="https://avatars.githubusercontent.com/u/25837540?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xm1k3"><img src="https://avatars.githubusercontent.com/u/73166077?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/5amu"><img src="https://avatars.githubusercontent.com/u/39925709?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ehrishirajsharma"><img src="https://avatars.githubusercontent.com/u/35542790?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zerodivisi0n"><img src="https://avatars.githubusercontent.com/u/687694?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/geeknik"><img src="https://avatars.githubusercontent.com/u/466878?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/TerminalFi"><img src="https://avatars.githubusercontent.com/u/32599364?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/KaulSe"><img src="https://avatars.githubusercontent.com/u/45340011?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/MachadoOtto"><img src="https://avatars.githubusercontent.com/u/93268441?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jonathanwalker"><img src="https://avatars.githubusercontent.com/u/14978093?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/nHurD"><img src="https://avatars.githubusercontent.com/u/233374?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jessekelly881"><img src="https://avatars.githubusercontent.com/u/22938931?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/JaneX8"><img src="https://avatars.githubusercontent.com/u/5116641?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/eltociear"><img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/atomiczsec"><img src="https://avatars.githubusercontent.com/u/75549184?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/M-Faheem-Khan"><img src="https://avatars.githubusercontent.com/u/17150767?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/denandz"><img src="https://avatars.githubusercontent.com/u/5291556?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tibbon"><img src="https://avatars.githubusercontent.com/u/82880?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/dany74q"><img src="https://avatars.githubusercontent.com/u/2129762?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/0x123456789"><img src="https://avatars.githubusercontent.com/u/36066426?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/danigoland"><img src="https://avatars.githubusercontent.com/u/15079567?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ChrisMandich"><img src="https://avatars.githubusercontent.com/u/14286797?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/austintraver"><img src="https://avatars.githubusercontent.com/u/25112463?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/socialsister"><img src="https://avatars.githubusercontent.com/u/155628741?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Anemys"><img src="https://avatars.githubusercontent.com/u/51196227?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/andreangelucci"><img src="https://avatars.githubusercontent.com/u/18552197?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/AlexS778"><img src="https://avatars.githubusercontent.com/u/98418121?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/noraj"><img src="https://avatars.githubusercontent.com/u/16578570?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/akkuman"><img src="https://avatars.githubusercontent.com/u/7813511?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zrquan"><img src="https://avatars.githubusercontent.com/u/33086594?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/1efty"><img src="https://avatars.githubusercontent.com/u/18194777?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rsrdesarrollo"><img src="https://avatars.githubusercontent.com/u/5142014?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/razin99"><img src="https://avatars.githubusercontent.com/u/44442082?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/MetzinAround"><img src="https://avatars.githubusercontent.com/u/65838556?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vil02"><img src="https://avatars.githubusercontent.com/u/65706193?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mrschyte"><img src="https://avatars.githubusercontent.com/u/8571?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/PeterDaveHello"><img src="https://avatars.githubusercontent.com/u/3691490?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/parthmalhotra"><img src="https://avatars.githubusercontent.com/u/28601533?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/owenrumney"><img src="https://avatars.githubusercontent.com/u/3049157?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Ovi3"><img src="https://avatars.githubusercontent.com/u/29408109?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Bisstocuz"><img src="https://avatars.githubusercontent.com/u/42398278?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/daffainfo"><img src="https://avatars.githubusercontent.com/u/36522826?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mhmdiaa"><img src="https://avatars.githubusercontent.com/u/19687798?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/MiryangJung"><img src="https://avatars.githubusercontent.com/u/48237511?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/0xmin"><img src="https://avatars.githubusercontent.com/u/44919834?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/maikthulhu"><img src="https://avatars.githubusercontent.com/u/680830?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/sttlr"><img src="https://avatars.githubusercontent.com/u/40246850?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iamRjarpan"><img src="https://avatars.githubusercontent.com/u/45498226?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/leoloobeek"><img src="https://avatars.githubusercontent.com/u/8801754?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/KristinnVikar"><img src="https://avatars.githubusercontent.com/u/93918469?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kant01ne"><img src="https://avatars.githubusercontent.com/u/5072452?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/KeisukeYamashita"><img src="https://avatars.githubusercontent.com/u/23056537?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
</p>
|
||||
|
||||
## License
|
||||
|
||||
Do also check out the below similar open-source projects that may fit in your workflow:
|
||||
Nuclei is distributed under [MIT License](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md).
|
||||
|
||||
[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)
|
||||
|
||||
### License
|
||||
|
||||
Nuclei is distributed under [MIT License](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>
|
||||
<img src="https://img.shields.io/badge/license-MIT-000000.svg?style=for-the-badge">
|
||||
+142
-16
@@ -1373,6 +1373,19 @@ Fuzzing describes schema to fuzz http requests
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>analyzer</code> <i><a href="#analyzersanalyzertemplate">analyzers.AnalyzerTemplate</a></i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Analyzer is an analyzer to use for matching the response.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>self-contained</code> <i>bool</i>
|
||||
|
||||
</div>
|
||||
@@ -1404,6 +1417,19 @@ 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>
|
||||
@@ -1638,6 +1664,19 @@ FuzzPreConditionOperator is the operator between multiple PreConditions for fuzz
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>global-matchers</code> <i>bool</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
GlobalMatchers marks matchers as static and applies globally to all result events from other templates
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1999,6 +2038,59 @@ Appears in:
|
||||
|
||||
|
||||
|
||||
## analyzers.AnalyzerTemplate
|
||||
AnalyzerTemplate is the template for the analyzer
|
||||
|
||||
Appears in:
|
||||
|
||||
|
||||
- <code><a href="#httprequest">http.Request</a>.analyzer</code>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>name</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Name is the name of the analyzer to use
|
||||
|
||||
|
||||
Valid values:
|
||||
|
||||
|
||||
- <code>time_delay</code>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>parameters</code> <i>map[string]interface{}</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
Parameters is the parameters for the analyzer
|
||||
|
||||
Parameters are different for each analyzer. For example, you can customize
|
||||
time_delay analyzer with sleep_duration, time_slope_error_range, etc. Refer
|
||||
to the docs for each analyzer to get an idea about parameters.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## SignatureTypeHolder
|
||||
SignatureTypeHolder is used to hold internal type of the signature
|
||||
|
||||
@@ -3197,6 +3289,19 @@ read-all: false
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>stop-at-first-match</code> <i>bool</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
StopAtFirstMatch stops the execution of the requests and template as soon as a match is found.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3651,8 +3756,18 @@ Enum Values:
|
||||
|
||||
- <code>files</code>
|
||||
|
||||
- <code>waitdom</code>
|
||||
|
||||
- <code>waitfcp</code>
|
||||
|
||||
- <code>waitfmp</code>
|
||||
|
||||
- <code>waitidle</code>
|
||||
|
||||
- <code>waitload</code>
|
||||
|
||||
- <code>waitstable</code>
|
||||
|
||||
- <code>getresource</code>
|
||||
|
||||
- <code>extract</code>
|
||||
@@ -3669,6 +3784,8 @@ Enum Values:
|
||||
|
||||
- <code>waitevent</code>
|
||||
|
||||
- <code>dialog</code>
|
||||
|
||||
- <code>keyboard</code>
|
||||
|
||||
- <code>debug</code>
|
||||
@@ -3739,11 +3856,33 @@ Appears in:
|
||||
Part Definitions:
|
||||
|
||||
|
||||
- <code>type</code> - Type is the type of request made
|
||||
- <code>response</code> - JSON SSL protocol handshake details
|
||||
- <code>not_after</code> - Timestamp after which the remote cert expires
|
||||
- <code>template-id</code> - ID of the template executed
|
||||
- <code>template-info</code> - Info Block of the template executed
|
||||
- <code>template-path</code> - Path of the template executed
|
||||
- <code>host</code> - Host is the input to the template
|
||||
- <code>port</code> - Port is the port of the host
|
||||
- <code>matched</code> - Matched is the input which was matched upon
|
||||
- <code>type</code> - Type is the type of request made
|
||||
- <code>timestamp</code> - Timestamp is the time when the request was made
|
||||
- <code>response</code> - JSON SSL protocol handshake details
|
||||
- <code>cipher</code> - Cipher is the encryption algorithm used
|
||||
- <code>domains</code> - Domains are the list of domain names in the certificate
|
||||
- <code>fingerprint_hash</code> - Fingerprint hash is the unique identifier of the certificate
|
||||
- <code>ip</code> - IP is the IP address of the server
|
||||
- <code>issuer_cn</code> - Issuer CN is the common name of the certificate issuer
|
||||
- <code>issuer_dn</code> - Issuer DN is the distinguished name of the certificate issuer
|
||||
- <code>issuer_org</code> - Issuer organization is the organization of the certificate issuer
|
||||
- <code>not_after</code> - Timestamp after which the remote cert expires
|
||||
- <code>not_before</code> - Timestamp before which the certificate is not valid
|
||||
- <code>probe_status</code> - Probe status indicates if the probe was successful
|
||||
- <code>serial</code> - Serial is the serial number of the certificate
|
||||
- <code>sni</code> - SNI is the server name indication used in the handshake
|
||||
- <code>subject_an</code> - Subject AN is the list of subject alternative names
|
||||
- <code>subject_cn</code> - Subject CN is the common name of the certificate subject
|
||||
- <code>subject_dn</code> - Subject DN is the distinguished name of the certificate subject
|
||||
- <code>subject_org</code> - Subject organization is the organization of the certificate subject
|
||||
- <code>tls_connection</code> - TLS connection is the type of TLS connection used
|
||||
- <code>tls_version</code> - TLS version is the version of the TLS protocol used
|
||||
|
||||
<hr />
|
||||
|
||||
@@ -4339,19 +4478,6 @@ 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>
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/kitabisa/go-ci"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -15,9 +16,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
success = aurora.Green("[✓]").String()
|
||||
failed = aurora.Red("[✘]").String()
|
||||
githubAction = os.Getenv("GH_ACTION") == "true"
|
||||
success = aurora.Green("[✓]").String()
|
||||
failed = aurora.Red("[✘]").String()
|
||||
|
||||
mainNucleiBinary = flag.String("main", "", "Main Branch Nuclei Binary")
|
||||
devNucleiBinary = flag.String("dev", "", "Dev Branch Nuclei Binary")
|
||||
@@ -45,7 +45,7 @@ func runFunctionalTests(debug bool) (error, bool) {
|
||||
|
||||
errored, failedTestCases := runTestCases(file, debug)
|
||||
|
||||
if githubAction {
|
||||
if ci.IsCI() {
|
||||
fmt.Println("::group::Failed tests with debug")
|
||||
for _, failedTestCase := range failedTestCases {
|
||||
_ = runTestCase(failedTestCase, true)
|
||||
|
||||
@@ -99,7 +99,7 @@ type codePreCondition struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *codePreCondition) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiArgsWithEnvAndGetResults(debug, getEnvValues(), "-t", filePath, "-u", "input", "-code")
|
||||
results, err := testutils.RunNucleiArgsWithEnvAndGetResults(debug, getEnvValues(), "-t", filePath, "-u", "input", "-code", "-esc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type fileWithOrMatcher struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *fileWithOrMatcher) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug, "-file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -27,7 +27,7 @@ type fileWithAndMatcher struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *fileWithAndMatcher) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug, "-file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -39,7 +39,7 @@ type fileWithExtractor struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *fileWithExtractor) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "protocols/file/data/", debug, "-file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ var flowTestcases = []TestCaseInfo{
|
||||
type conditionalFlow struct{}
|
||||
|
||||
func (t *conditionalFlow) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "blog.projectdiscovery.io", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "cloud.projectdiscovery.io", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ func (h *httpInteractshRequest) Execute(filePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
return expectResultsCount(results, 1, 2)
|
||||
}
|
||||
|
||||
type httpDefaultMatcherCondition struct{}
|
||||
@@ -952,7 +952,7 @@ func (h *httpRequestSelfContained) Execute(filePath string) error {
|
||||
}()
|
||||
defer server.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -988,7 +988,7 @@ func (h *httpRequestSelfContainedWithParams) Execute(filePath string) error {
|
||||
}()
|
||||
defer server.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1031,7 +1031,7 @@ func (h *httpRequestSelfContainedFileInput) Execute(filePath string) error {
|
||||
}
|
||||
defer FileLoc.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-V", "test="+FileLoc.Name())
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-V", "test="+FileLoc.Name(), "-esc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/kitabisa/go-ci"
|
||||
"github.com/logrusorgru/aurora"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
@@ -22,10 +23,9 @@ type TestCaseInfo struct {
|
||||
}
|
||||
|
||||
var (
|
||||
debug = os.Getenv("DEBUG") == "true"
|
||||
githubAction = os.Getenv("GH_ACTION") == "true"
|
||||
customTests = os.Getenv("TESTS")
|
||||
protocol = os.Getenv("PROTO")
|
||||
debug = os.Getenv("DEBUG") == "true"
|
||||
customTests = os.Getenv("TESTS")
|
||||
protocol = os.Getenv("PROTO")
|
||||
|
||||
success = aurora.Green("[✓]").String()
|
||||
failed = aurora.Red("[✘]").String()
|
||||
@@ -55,6 +55,7 @@ var (
|
||||
"dsl": dslTestcases,
|
||||
"flow": flowTestcases,
|
||||
"javascript": jsTestcases,
|
||||
"matcher-status": matcherStatusTestcases,
|
||||
}
|
||||
// flakyTests are run with a retry count of 3
|
||||
flakyTests = map[string]bool{
|
||||
@@ -102,11 +103,19 @@ func main() {
|
||||
failedTestTemplatePaths := runTests(customTestsList)
|
||||
|
||||
if len(failedTestTemplatePaths) > 0 {
|
||||
if githubAction {
|
||||
debug = true
|
||||
fmt.Println("::group::Failed integration tests in debug mode")
|
||||
_ = runTests(failedTestTemplatePaths)
|
||||
if ci.IsCI() {
|
||||
// run failed tests again assuming they are flaky
|
||||
// if they fail as well only then we assume that there is an actual issue
|
||||
fmt.Println("::group::Running failed tests again")
|
||||
failedTestTemplatePaths = runTests(failedTestTemplatePaths)
|
||||
fmt.Println("::endgroup::")
|
||||
|
||||
if len(failedTestTemplatePaths) > 0 {
|
||||
debug = true
|
||||
fmt.Println("::group::Failed integration tests in debug mode")
|
||||
_ = runTests(failedTestTemplatePaths)
|
||||
fmt.Println("::endgroup::")
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit(1)
|
||||
|
||||
@@ -172,7 +172,14 @@ func (h *nonExistentTemplateList) Execute(nonExistingTemplateList string) error
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-template-url", ts.URL+"/404")
|
||||
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")
|
||||
if err == nil {
|
||||
return fmt.Errorf("expected error for nonexisting workflow url")
|
||||
}
|
||||
@@ -188,7 +195,14 @@ func (h *nonExistentWorkflowList) Execute(nonExistingWorkflowList string) error
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-workflow-url", ts.URL+"/404")
|
||||
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")
|
||||
if err == nil {
|
||||
return fmt.Errorf("expected error for nonexisting workflow url")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var matcherStatusTestcases = []TestCaseInfo{
|
||||
{Path: "protocols/http/get.yaml", TestCase: &httpNoAccess{}},
|
||||
{Path: "protocols/network/net-https.yaml", TestCase: &networkNoAccess{}},
|
||||
{Path: "protocols/headless/headless-basic.yaml", TestCase: &headlessNoAccess{}},
|
||||
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNoAccess{}},
|
||||
{Path: "protocols/websocket/basic.yaml", TestCase: &websocketNoAccess{}},
|
||||
{Path: "protocols/dns/a.yaml", TestCase: &dnsNoAccess{}},
|
||||
}
|
||||
|
||||
type httpNoAccess struct{}
|
||||
|
||||
func (h *httpNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
expectedError := "no address found for host"
|
||||
if !strings.Contains(event.Error, expectedError) {
|
||||
return fmt.Errorf("unexpected result: expecting \"%s\" error but got \"%s\"", expectedError, event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type networkNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error != "no address found for host" {
|
||||
return fmt.Errorf("unexpected result: expecting \"no address found for host\" error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type headlessNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *headlessNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-headless", "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type javascriptNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *javascriptNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type websocketNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *websocketNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "ws://trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type dnsNoAccess struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsNoAccess) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "trust_me_bro.real", debug, "-ms", "-j")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &output.ResultEvent{}
|
||||
_ = json.Unmarshal([]byte(results[0]), event)
|
||||
|
||||
if event.Error == "" {
|
||||
return fmt.Errorf("unexpected result: expecting an error but got \"%s\"", event.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -14,7 +14,7 @@ type multiProtoDynamicExtractor struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *multiProtoDynamicExtractor) Execute(templatePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(templatePath, "blog.projectdiscovery.io", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(templatePath, "docs.projectdiscovery.io", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ func (h *networkRequestSelContained) Execute(filePath string) error {
|
||||
_, _ = conn.Write([]byte("Authentication successful"))
|
||||
})
|
||||
defer ts.Close()
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates/signer"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
sliceutil "github.com/projectdiscovery/utils/slice"
|
||||
)
|
||||
|
||||
var workflowTestcases = []TestCaseInfo{
|
||||
@@ -25,6 +26,7 @@ var workflowTestcases = []TestCaseInfo{
|
||||
{Path: "workflow/dns-value-share-workflow.yaml", TestCase: &workflowDnsKeyValueShare{}},
|
||||
{Path: "workflow/code-value-share-workflow.yaml", TestCase: &workflowCodeKeyValueShare{}, DisableOn: isCodeDisabled}, // isCodeDisabled declared in code.go
|
||||
{Path: "workflow/multiprotocol-value-share-workflow.yaml", TestCase: &workflowMultiProtocolKeyValueShare{}},
|
||||
{Path: "workflow/multimatch-value-share-workflow.yaml", TestCase: &workflowMultiMatchKeyValueShare{}},
|
||||
{Path: "workflow/shared-cookie.yaml", TestCase: &workflowSharedCookies{}},
|
||||
}
|
||||
|
||||
@@ -229,6 +231,44 @@ func (h *workflowMultiProtocolKeyValueShare) Execute(filePath string) error {
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
type workflowMultiMatchKeyValueShare struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *workflowMultiMatchKeyValueShare) Execute(filePath string) error {
|
||||
var receivedData []string
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test matcher text")
|
||||
})
|
||||
router.GET("/path1", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "href=\"test-value-%s\"", r.URL.Query().Get("v"))
|
||||
})
|
||||
router.GET("/path2", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
receivedData = append(receivedData, string(body))
|
||||
fmt.Fprintf(w, "test-value")
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiWorkflowAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if we received the data from both request to /path1 and it is not overwritten by the later one.
|
||||
// They will appear in brackets because of another bug: https://github.com/orgs/projectdiscovery/discussions/3766
|
||||
if !sliceutil.Contains(receivedData, "[test-value-1]") || !sliceutil.Contains(receivedData, "[test-value-2]") {
|
||||
return fmt.Errorf(
|
||||
"incorrect data: did not receive both extracted data from the first request!\nReceived Data:\n\t%s\nResults:\n\t%s",
|
||||
strings.Join(receivedData, "\n\t"),
|
||||
strings.Join(results, "\n\t"),
|
||||
)
|
||||
}
|
||||
// The number of expected results is 3: the workflow's Matcher Name based condition check forwards both match, and the other branch with simple subtemplates goes with one
|
||||
return expectResultsCount(results, 3)
|
||||
}
|
||||
|
||||
type workflowSharedCookies struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
|
||||
@@ -142,4 +142,34 @@
|
||||
# # Username for the elasticsearch instance
|
||||
# username: test
|
||||
# # Password is the password for elasticsearch instance
|
||||
# password: test
|
||||
# password: test
|
||||
#linear:
|
||||
# # api-key is the API key for the linear account
|
||||
# api-key: ""
|
||||
# # allow-list sets a tracker level filter to only create issues for templates with
|
||||
# # these severity labels or tags (does not affect exporters. set those globally)
|
||||
# deny-list:
|
||||
# severity: critical
|
||||
# # deny-list sets a tracker level filter to never create issues for templates with
|
||||
# # these severity labels or tags (does not affect exporters. set those globally)
|
||||
# deny-list:
|
||||
# severity: low
|
||||
# # team-id is the ID of the team in Linear
|
||||
# team-id: ""
|
||||
# # project-id is the ID of the project in Linear
|
||||
# project-id: ""
|
||||
# # duplicate-issue-check flag to enable duplicate tracking issue check
|
||||
# duplicate-issue-check: false
|
||||
# # open-state-id is the ID of the open state in Linear
|
||||
# open-state-id: ""
|
||||
#mongodb:
|
||||
# # the connection string to the MongoDB database
|
||||
# # (e.g., mongodb://root:example@localhost:27017/nuclei?ssl=false&authSource=admin)
|
||||
# connection-string: ""
|
||||
# # the name of the collection to store the issues
|
||||
# collection-name: ""
|
||||
# # excludes the Request and Response from the results (helps with filesize)
|
||||
# omit-raw: false
|
||||
# # determines the number of results to be kept in memory before writing it to the database or 0 to
|
||||
# # persist all in memory and write all results at the end (default)
|
||||
# batch-size: 0
|
||||
+52
-13
@@ -9,9 +9,11 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"runtime/trace"
|
||||
"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"
|
||||
@@ -102,26 +104,52 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// Profiling related code
|
||||
// Profiling & tracing related code
|
||||
if memProfile != "" {
|
||||
f, err := os.Create(memProfile)
|
||||
memProfile = strings.TrimSuffix(memProfile, filepath.Ext(memProfile)) + ".prof"
|
||||
memProfileFile, err := os.Create(memProfile)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("profile: could not create memory profile %q: %v", memProfile, err)
|
||||
gologger.Fatal().Msgf("profile: could not create memory profile %q file: %v", memProfile, err)
|
||||
}
|
||||
old := runtime.MemProfileRate
|
||||
|
||||
traceFilepath := strings.TrimSuffix(memProfile, filepath.Ext(memProfile)) + ".trace"
|
||||
traceFile, err := os.Create(traceFilepath)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("profile: could not create trace %q file: %v", traceFilepath, err)
|
||||
}
|
||||
|
||||
oldMemProfileRate := runtime.MemProfileRate
|
||||
runtime.MemProfileRate = 4096
|
||||
gologger.Print().Msgf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, memProfile)
|
||||
|
||||
// Start tracing
|
||||
if err := trace.Start(traceFile); err != nil {
|
||||
gologger.Fatal().Msgf("profile: could not start trace: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = pprof.Lookup("heap").WriteTo(f, 0)
|
||||
f.Close()
|
||||
runtime.MemProfileRate = old
|
||||
gologger.Print().Msgf("profile: memory profiling disabled, %s", memProfile)
|
||||
// Start CPU profiling
|
||||
if err := pprof.WriteHeapProfile(memProfileFile); err != nil {
|
||||
gologger.Fatal().Msgf("profile: could not start CPU profile: %v", err)
|
||||
}
|
||||
memProfileFile.Close()
|
||||
traceFile.Close()
|
||||
trace.Stop()
|
||||
runtime.MemProfileRate = oldMemProfileRate
|
||||
|
||||
gologger.Info().Msgf("Memory profile saved at %q", memProfile)
|
||||
gologger.Info().Msgf("Traced at %q", traceFilepath)
|
||||
}()
|
||||
}
|
||||
|
||||
runner.ParseOptions(options)
|
||||
|
||||
if options.ScanUploadFile != "" {
|
||||
if err := runner.UploadResultsToCloud(options); err != nil {
|
||||
gologger.Fatal().Msgf("could not upload scan results to cloud dashboard: %s\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
nucleiRunner, err := runner.New(options)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not create runner: %s\n", err)
|
||||
@@ -235,6 +263,9 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.BoolVar(&options.SignTemplates, "sign", false, "signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable"),
|
||||
flagSet.BoolVar(&options.EnableCodeTemplates, "code", false, "enable loading code protocol-based templates"),
|
||||
flagSet.BoolVarP(&options.DisableUnsignedTemplates, "disable-unsigned-templates", "dut", false, "disable running unsigned templates or templates with mismatched signature"),
|
||||
flagSet.BoolVarP(&options.EnableSelfContainedTemplates, "enable-self-contained", "esc", false, "enable loading self-contained templates"),
|
||||
flagSet.BoolVarP(&options.EnableGlobalMatchersTemplates, "enable-global-matchers", "egm", false, "enable loading global matchers templates"),
|
||||
flagSet.BoolVar(&options.EnableFileTemplates, "file", false, "enable loading file templates"),
|
||||
)
|
||||
|
||||
flagSet.CreateGroup("filters", "Filtering",
|
||||
@@ -272,6 +303,7 @@ 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",
|
||||
@@ -297,7 +329,6 @@ 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"),
|
||||
@@ -306,7 +337,6 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
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.DurationVarP(&options.ResponseReadTimeout, "response-read-timeout", "rrt", time.Duration(5*time.Second), "response read timeout in seconds"),
|
||||
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"),
|
||||
@@ -395,9 +425,10 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.CallbackVar(printVersion, "version", "show nuclei version"),
|
||||
flagSet.BoolVarP(&options.HangMonitor, "hang-monitor", "hm", false, "enable nuclei hang monitoring"),
|
||||
flagSet.BoolVarP(&options.Verbose, "verbose", "v", false, "show verbose output"),
|
||||
flagSet.StringVar(&memProfile, "profile-mem", "", "optional nuclei memory profile dump file"),
|
||||
flagSet.StringVar(&memProfile, "profile-mem", "", "generate memory (heap) profile & trace files"),
|
||||
flagSet.BoolVar(&options.VerboseVerbose, "vv", false, "display templates loaded for scan"),
|
||||
flagSet.BoolVarP(&options.ShowVarDump, "show-var-dump", "svd", false, "show variables dump for debugging"),
|
||||
flagSet.IntVarP(&options.VarDumpLimit, "var-dump-limit", "vdl", 255, "limit the number of characters displayed in var dump"),
|
||||
flagSet.BoolVarP(&options.EnablePprof, "enable-pprof", "ep", false, "enable pprof debugging server"),
|
||||
flagSet.CallbackVarP(printTemplateVersion, "templates-version", "tv", "shows the version of the installed nuclei-templates"),
|
||||
flagSet.BoolVarP(&options.HealthCheck, "health-check", "hc", false, "run diagnostic check up"),
|
||||
@@ -419,9 +450,12 @@ 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.BoolVarP(&options.EnableCloudUpload, "cloud-upload", "cup", false, "upload scan results to pdcp dashboard"),
|
||||
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 [DEPRECATED use -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.BoolVarP(&options.EnableCloudUpload, "dashboard", "pd", false, "upload / view nuclei results in projectdiscovery cloud (pdcp) UI dashboard"),
|
||||
flagSet.StringVarP(&options.ScanUploadFile, "dashboard-upload", "pdu", "", "upload / view nuclei results file (jsonl) in projectdiscovery cloud (pdcp) UI dashboard"),
|
||||
)
|
||||
|
||||
flagSet.CreateGroup("Authentication", "Authentication",
|
||||
@@ -461,6 +495,11 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
|
||||
options.DAST = true
|
||||
}
|
||||
|
||||
// All cloud-based templates depend on both code and self-contained templates.
|
||||
if options.EnableCodeTemplates {
|
||||
options.EnableSelfContainedTemplates = true
|
||||
}
|
||||
|
||||
// api key hierarchy: cli flag > env var > .pdcp/credential file
|
||||
if pdcpauth == "true" {
|
||||
runner.AuthWithPDCP()
|
||||
|
||||
+6
-5
@@ -69,6 +69,7 @@ func init() {
|
||||
// need to set headless to true for headless templates
|
||||
defaultOpts.Headless = true
|
||||
defaultOpts.EnableCodeTemplates = true
|
||||
defaultOpts.EnableSelfContainedTemplates = true
|
||||
if err := protocolstate.Init(defaultOpts); err != nil {
|
||||
gologger.Fatal().Msgf("Could not initialize protocol state: %s\n", err)
|
||||
}
|
||||
@@ -162,7 +163,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").Msgf(logErrMsg(path, err, opts.debug, errFile))
|
||||
gologger.Info().Label("max-request").Msg(logErrMsg(path, err, opts.debug, errFile))
|
||||
} else {
|
||||
if updated {
|
||||
gologger.Info().Label("max-request").Msgf("✅ updated template: %s\n", path)
|
||||
@@ -255,7 +256,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(templateResp.Error.Name)
|
||||
return data, false, errorutil.New("%s", templateResp.Error.Name)
|
||||
}
|
||||
if strings.TrimSpace(templateResp.Enhanced) == "" && !templateResp.Lint {
|
||||
if templateResp.LintError.Reason != "" {
|
||||
@@ -289,7 +290,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(templateResp.Error.Name)
|
||||
return data, false, errorutil.New("%s", templateResp.Error.Name)
|
||||
}
|
||||
if strings.TrimSpace(templateResp.Updated) == "" && !templateResp.Lint {
|
||||
if templateResp.LintError.Reason != "" {
|
||||
@@ -300,7 +301,7 @@ func formatTemplate(data string) (string, bool, error) {
|
||||
return data, false, errorutil.New("template format failed")
|
||||
}
|
||||
|
||||
// lintTemplateData lints template data using templateman lint api
|
||||
// lintTemplate lints template data using templateman lint api
|
||||
func lintTemplate(data string) (bool, error) {
|
||||
resp, err := retryablehttp.DefaultClient().Post(fmt.Sprintf("%s/lint", tmBaseUrl), "application/x-yaml", strings.NewReader(data))
|
||||
if err != nil {
|
||||
@@ -345,7 +346,7 @@ func validateTemplate(data string) (bool, error) {
|
||||
return false, errorutil.New("validation failed").WithTag("validate")
|
||||
}
|
||||
if validateResp.Error.Name != "" {
|
||||
return false, errorutil.New(validateResp.Error.Name)
|
||||
return false, errorutil.New("%s", validateResp.Error.Name)
|
||||
}
|
||||
return false, errorutil.New("template validation failed")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/gologger/levels"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates/signer"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
fileutil "github.com/projectdiscovery/utils/file"
|
||||
folderutil "github.com/projectdiscovery/utils/folder"
|
||||
)
|
||||
|
||||
var (
|
||||
appConfigDir = folderutil.AppConfigDirOrDefault(".config", "nuclei")
|
||||
defaultCertFile = filepath.Join(appConfigDir, "keys", "nuclei-user.crt")
|
||||
defaultPrivKey = filepath.Join(appConfigDir, "keys", "nuclei-user-private-key.pem")
|
||||
)
|
||||
|
||||
var (
|
||||
template string
|
||||
cert string
|
||||
privKey string
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&template, "template", "", "template to sign (file only)")
|
||||
flag.StringVar(&cert, "cert", defaultCertFile, "certificate file")
|
||||
flag.StringVar(&privKey, "priv-key", defaultPrivKey, "private key file")
|
||||
flag.Parse()
|
||||
|
||||
config.DefaultConfig.LogAllEvents = true
|
||||
gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
|
||||
|
||||
if template == "" {
|
||||
gologger.Fatal().Msg("template is required")
|
||||
}
|
||||
if !fileutil.FileExists(template) {
|
||||
gologger.Fatal().Msgf("template file %s does not exist or not a file", template)
|
||||
}
|
||||
|
||||
// get signer
|
||||
tmplSigner, err := signer.NewTemplateSignerFromFiles(cert, privKey)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to create signer: %s", err)
|
||||
}
|
||||
gologger.Info().Msgf("Template Signer: %v\n", tmplSigner.Identifier())
|
||||
|
||||
// read file
|
||||
bin, err := os.ReadFile(template)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to read template file %s: %s", template, err)
|
||||
}
|
||||
|
||||
// extract signature and content
|
||||
sig, content := signer.ExtractSignatureAndContent(bin)
|
||||
hash := sha256.Sum256(content)
|
||||
|
||||
gologger.Info().Msgf("Signature Details:")
|
||||
gologger.Info().Msgf("----------------")
|
||||
gologger.Info().Msgf("Signature: %s", sig)
|
||||
gologger.Info().Msgf("Content Hash (SHA256): %s\n", hex.EncodeToString(hash[:]))
|
||||
|
||||
execOpts := defaultExecutorOpts(template)
|
||||
|
||||
tmpl, err := templates.Parse(template, nil, execOpts)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to parse template: %s", err)
|
||||
}
|
||||
gologger.Info().Msgf("Template Verified: %v\n", tmpl.Verified)
|
||||
|
||||
if !tmpl.Verified {
|
||||
gologger.Info().Msgf("------------------------")
|
||||
gologger.Info().Msg("Template is not verified, signing template")
|
||||
if err := templates.SignTemplate(tmplSigner, template); err != nil {
|
||||
gologger.Fatal().Msgf("Failed to sign template: %s", err)
|
||||
}
|
||||
// verify again by reading file what the new signature and hash is
|
||||
bin2, err := os.ReadFile(template)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to read signed template file %s: %s", template, err)
|
||||
}
|
||||
sig2, content2 := signer.ExtractSignatureAndContent(bin2)
|
||||
hash2 := sha256.Sum256(content2)
|
||||
|
||||
gologger.Info().Msgf("Updated Signature Details:")
|
||||
gologger.Info().Msgf("------------------------")
|
||||
gologger.Info().Msgf("Signature: %s", sig2)
|
||||
gologger.Info().Msgf("Content Hash (SHA256): %s\n", hex.EncodeToString(hash2[:]))
|
||||
}
|
||||
gologger.Info().Msgf("✓ Template signed & verified successfully")
|
||||
}
|
||||
|
||||
func defaultExecutorOpts(templatePath string) protocols.ExecutorOptions {
|
||||
// use parsed options when initializing signer instead of default options
|
||||
options := types.DefaultOptions()
|
||||
templates.UseOptionsForSigner(options)
|
||||
catalog := disk.NewCatalog(filepath.Dir(templatePath))
|
||||
executerOpts := protocols.ExecutorOptions{
|
||||
Catalog: catalog,
|
||||
Options: options,
|
||||
TemplatePath: templatePath,
|
||||
Parser: templates.NewParser(),
|
||||
}
|
||||
return executerOpts
|
||||
}
|
||||
@@ -1,13 +1,24 @@
|
||||
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.NewThreadSafeNucleiEngine()
|
||||
ne, err := nuclei.NewThreadSafeNucleiEngineCtx(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package main
|
||||
|
||||
import nuclei "github.com/projectdiscovery/nuclei/v3/lib"
|
||||
import (
|
||||
"context"
|
||||
|
||||
nuclei "github.com/projectdiscovery/nuclei/v3/lib"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ne, err := nuclei.NewNucleiEngine(
|
||||
ne, err := nuclei.NewNucleiEngineCtx(context.Background(),
|
||||
nuclei.WithTemplateFilters(nuclei.TemplateFilters{Tags: []string{"oast"}}),
|
||||
nuclei.EnableStatsWithOpts(nuclei.StatsOptions{MetricServerPort: 6064}), // optionally enable metrics server for better observability
|
||||
)
|
||||
|
||||
+4
-4
@@ -21,9 +21,9 @@ WORKFLOW="Build Test"
|
||||
GREP_ERROR_PATTERN='Test "http/interactsh.yaml" failed'
|
||||
|
||||
#Set fonts for Help.
|
||||
NORM=`tput sgr0`
|
||||
BOLD=`tput bold`
|
||||
REV=`tput smso`
|
||||
NORM=$(tput sgr0)
|
||||
BOLD=$(tput bold)
|
||||
REV=$(tput smso)
|
||||
|
||||
HELP()
|
||||
{
|
||||
@@ -73,7 +73,7 @@ function print_bold() {
|
||||
function retry_failed_jobs() {
|
||||
print_bold "Checking failed workflows for branch $BRANCH before $BEFORE"
|
||||
|
||||
date=`date +%Y-%m-%d'T'%H:%M'Z' -d "$BEFORE"`
|
||||
date=$(date +%Y-%m-%d'T'%H:%M'Z' -d "$BEFORE")
|
||||
|
||||
workflowIds=$(gh run list --limit "$LIMIT" --json headBranch,status,name,conclusion,databaseId,updatedAt | jq -c '.[] |
|
||||
select ( .headBranch==$branch ) |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/projectdiscovery/nuclei/v3
|
||||
|
||||
go 1.21
|
||||
go 1.21.0
|
||||
|
||||
require (
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
|
||||
@@ -19,13 +19,13 @@ require (
|
||||
github.com/miekg/dns v1.1.59
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/projectdiscovery/clistats v0.0.20
|
||||
github.com/projectdiscovery/fastdialer v0.1.5
|
||||
github.com/projectdiscovery/hmap v0.0.47
|
||||
github.com/projectdiscovery/clistats v0.1.1
|
||||
github.com/projectdiscovery/fastdialer v0.2.10
|
||||
github.com/projectdiscovery/hmap v0.0.69
|
||||
github.com/projectdiscovery/interactsh v1.2.0
|
||||
github.com/projectdiscovery/rawhttp v0.1.51
|
||||
github.com/projectdiscovery/retryabledns v1.0.65
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.66
|
||||
github.com/projectdiscovery/rawhttp v0.1.76
|
||||
github.com/projectdiscovery/retryabledns v1.0.86
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.88
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.4
|
||||
github.com/remeh/sizedwaitgroup v1.0.0
|
||||
github.com/rs/xid v1.5.0
|
||||
@@ -36,11 +36,11 @@ require (
|
||||
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.84.0
|
||||
github.com/xanzy/go-gitlab v0.107.0
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/net v0.26.0
|
||||
golang.org/x/oauth2 v0.18.0
|
||||
golang.org/x/text v0.16.0
|
||||
golang.org/x/net v0.31.0
|
||||
golang.org/x/oauth2 v0.22.0
|
||||
golang.org/x/text v0.20.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
@@ -58,50 +58,56 @@ 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/charmbracelet/glamour v0.6.0
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/charmbracelet/glamour v0.8.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.123.0
|
||||
github.com/getkin/kin-openapi v0.126.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/h2non/filetype v1.1.3
|
||||
github.com/invopop/yaml v0.3.1
|
||||
github.com/kitabisa/go-ci v1.0.3
|
||||
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/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.3
|
||||
github.com/projectdiscovery/dsl v0.3.3
|
||||
github.com/projectdiscovery/fasttemplate v0.0.2
|
||||
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
|
||||
github.com/projectdiscovery/goflags v0.1.56
|
||||
github.com/projectdiscovery/gologger v1.1.12
|
||||
github.com/projectdiscovery/goflags v0.1.65
|
||||
github.com/projectdiscovery/gologger v1.1.33
|
||||
github.com/projectdiscovery/gostruct v0.0.2
|
||||
github.com/projectdiscovery/gozero v0.0.2
|
||||
github.com/projectdiscovery/httpx v1.6.3
|
||||
github.com/projectdiscovery/gozero v0.0.3
|
||||
github.com/projectdiscovery/httpx v1.6.9
|
||||
github.com/projectdiscovery/mapcidr v1.1.34
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
|
||||
github.com/projectdiscovery/ratelimit v0.0.45
|
||||
github.com/projectdiscovery/ratelimit v0.0.64
|
||||
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917
|
||||
github.com/projectdiscovery/sarif v0.0.1
|
||||
github.com/projectdiscovery/tlsx v1.1.6
|
||||
github.com/projectdiscovery/uncover v1.0.8
|
||||
github.com/projectdiscovery/useragent v0.0.56
|
||||
github.com/projectdiscovery/utils v0.1.4
|
||||
github.com/projectdiscovery/wappalyzergo v0.1.6
|
||||
github.com/projectdiscovery/tlsx v1.1.8
|
||||
github.com/projectdiscovery/uncover v1.0.9
|
||||
github.com/projectdiscovery/useragent v0.0.78
|
||||
github.com/projectdiscovery/utils v0.3.0
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.5
|
||||
github.com/redis/go-redis/v9 v9.1.0
|
||||
github.com/seh-msft/burpxml v1.0.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9
|
||||
github.com/yassinebenaid/godump v0.10.0
|
||||
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706
|
||||
golang.org/x/term v0.21.0
|
||||
go.mongodb.org/mongo-driver v1.17.0
|
||||
golang.org/x/term v0.26.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
moul.io/http2curl v1.0.0
|
||||
)
|
||||
@@ -116,6 +122,7 @@ require (
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // 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
|
||||
@@ -129,8 +136,9 @@ require (
|
||||
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/charmbracelet/lipgloss v0.13.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.3.2 // 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
|
||||
@@ -139,11 +147,12 @@ require (
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.11.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
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/fatih/color v1.16.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/free5gc/util v1.0.5-0.20230511064842-2e120956883b // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gaissmai/bart v0.9.5 // indirect
|
||||
@@ -152,13 +161,13 @@ require (
|
||||
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.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.9 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // 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-20190719163853-cb61b32ac6fe // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // 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
|
||||
@@ -168,7 +177,6 @@ require (
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.6 // 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
|
||||
@@ -190,22 +198,23 @@ require (
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.1 // indirect
|
||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/opencontainers/runc v1.1.12 // indirect
|
||||
github.com/opencontainers/runc v1.1.14 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
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.0 // indirect
|
||||
github.com/projectdiscovery/cdncheck v1.0.9 // indirect
|
||||
github.com/projectdiscovery/freeport v0.0.5 // indirect
|
||||
github.com/projectdiscovery/asnmap v1.1.1 // indirect
|
||||
github.com/projectdiscovery/cdncheck v1.1.0 // indirect
|
||||
github.com/projectdiscovery/freeport v0.0.7 // 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.6 // indirect
|
||||
github.com/refraction-networking/utls v1.6.7 // 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
|
||||
@@ -223,18 +232,22 @@ require (
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
github.com/ysmood/fetchup v0.2.3 // indirect
|
||||
github.com/ysmood/got v0.34.1 // indirect
|
||||
github.com/yuin/goldmark v1.5.4 // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.1 // indirect
|
||||
github.com/yuin/goldmark v1.7.4 // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.3 // 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.7.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
|
||||
mellium.im/sasl v0.3.1 // indirect
|
||||
)
|
||||
@@ -260,9 +273,8 @@ require (
|
||||
github.com/goburrow/cache v0.1.4 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // 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
|
||||
@@ -277,23 +289,22 @@ require (
|
||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mholt/acmez v1.2.0 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.26 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.27 // 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/rivo/uniseg v0.4.6 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // 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/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
|
||||
@@ -303,14 +314,13 @@ require (
|
||||
go.etcd.io/bbolt v1.3.10 // indirect
|
||||
go.uber.org/zap v1.25.0 // indirect
|
||||
goftp.io/server/v2 v2.0.1 // indirect
|
||||
golang.org/x/crypto v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.29.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/time v0.6.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
|
||||
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
|
||||
)
|
||||
|
||||
@@ -40,17 +40,18 @@ 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 v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
||||
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 v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
||||
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 v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||
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/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=
|
||||
@@ -92,9 +93,15 @@ github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/akrylysov/pogreb v0.10.2 h1:e6PxmeyEhWyi2AKOBIJzAEi4HkiC+lKyCocRGlnDi78=
|
||||
github.com/akrylysov/pogreb v0.10.2/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
|
||||
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
|
||||
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
|
||||
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
|
||||
github.com/alecthomas/kingpin/v2 v2.3.1/go.mod h1:oYL5vtsvEHZGHxU7DMp32Dvx+qL+ptGn6lWaot2vCNE=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -173,9 +180,10 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.19.3 h1:e5mnydVdCVWxP+5rPAGi2PYxC7u2
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.19.3/go.mod h1:yVGZA1CPkmUhBdA039jXNJJG7/6t+G+EBWmFq23xqnY=
|
||||
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
|
||||
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
@@ -216,19 +224,31 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
|
||||
github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
|
||||
github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs=
|
||||
github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw=
|
||||
github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
|
||||
github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
|
||||
github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY=
|
||||
github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30=
|
||||
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||
github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
|
||||
github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
@@ -260,8 +280,6 @@ 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=
|
||||
@@ -272,9 +290,8 @@ github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
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/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
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=
|
||||
@@ -314,6 +331,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
|
||||
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
|
||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
|
||||
@@ -331,8 +350,8 @@ 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.123.0 h1:zIik0mRwFNLyvtXK274Q6ut+dPh6nlxBp0x7mNrPhs8=
|
||||
github.com/getkin/kin-openapi v0.123.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
|
||||
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/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=
|
||||
@@ -371,10 +390,10 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
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.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-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-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=
|
||||
@@ -416,12 +435,12 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
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/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1/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-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
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/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=
|
||||
@@ -455,8 +474,6 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||
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/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
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=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
@@ -512,7 +529,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
@@ -563,10 +579,13 @@ github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf h1:umfGUaWdFP2s6
|
||||
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=
|
||||
github.com/hdm/jarm-go v0.0.7/go.mod h1:kinGoS0+Sdn1Rr54OtanET5E5n7AlD6T6CrJAKDjJSQ=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
@@ -574,8 +593,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.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
|
||||
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||
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/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=
|
||||
@@ -629,6 +648,8 @@ github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kitabisa/go-ci v1.0.3 h1:JmIUIvcercRQc/9x/v02ydCCqU4MadSHaNaOF8T2pGA=
|
||||
github.com/kitabisa/go-ci v1.0.3/go.mod h1:e3wBSzaJbcifXrr/Gw2ZBLn44MmeqP5WySwXyHlCK/U=
|
||||
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=
|
||||
@@ -659,6 +680,7 @@ github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN
|
||||
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa h1:KQKuQDgA3DZX6C396lt3WDYB9Um1gLITLbvficVbqXk=
|
||||
@@ -697,9 +719,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@@ -710,9 +731,10 @@ github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1w
|
||||
github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
|
||||
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.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
|
||||
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
|
||||
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/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.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||
@@ -741,16 +763,16 @@ 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/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
|
||||
github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
||||
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
|
||||
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
|
||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
|
||||
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
@@ -782,8 +804,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
||||
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
|
||||
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
||||
github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w=
|
||||
github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
@@ -792,6 +814,7 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
|
||||
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
|
||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||
@@ -811,7 +834,6 @@ 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-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||
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/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -826,36 +848,36 @@ 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.0 h1:ynvbLB5cNpyQ2+k9IP0Rpla+0JmCJpd3mw6KLAW13m0=
|
||||
github.com/projectdiscovery/asnmap v1.1.0/go.mod h1:QNjBnGLxUBEZAgaYk/Av5cjKKWFY3i/FOfoIWCUApoY=
|
||||
github.com/projectdiscovery/asnmap v1.1.1 h1:ImJiKIaACOT7HPx4Pabb5dksolzaFYsD1kID2iwsDqI=
|
||||
github.com/projectdiscovery/asnmap v1.1.1/go.mod h1:QT7jt9nQanj+Ucjr9BqGr1Q2veCCKSAVyUzLXfEcQ60=
|
||||
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.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.1.3 h1:Lxlgpx8lwq/CaBjVUmwF6KmkMDnYf9IVKlMsWCF72OE=
|
||||
github.com/projectdiscovery/dsl v0.1.3/go.mod h1:WAuQLD4KQ/94RASotE7cvk7X6kY7JQG9Fcqc3lRQfpI=
|
||||
github.com/projectdiscovery/fastdialer v0.1.5 h1:5rNJ8I+GVzDsUqRSVLUqGTm7LsshfNYmCh20lLn1aaI=
|
||||
github.com/projectdiscovery/fastdialer v0.1.5/go.mod h1:oVoMl9Y6da2timhszy0okyBvhbKDSk+zqFazGV4y6pU=
|
||||
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.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB72JIg66c8wE=
|
||||
github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0=
|
||||
github.com/projectdiscovery/dsl v0.3.3 h1:4Ij5S86cHlb6xFrS7+5zAiJPeBt5h970XBTHqeTkpyU=
|
||||
github.com/projectdiscovery/dsl v0.3.3/go.mod h1:DAjSeaogLM9f0Ves2zDc/vbJrfcv+kEmS51p0dLLaPI=
|
||||
github.com/projectdiscovery/fastdialer v0.2.10 h1:5iciZXMPdynbk/9iuqkJT1gqMXwzgEpFSWdoj/5CHCo=
|
||||
github.com/projectdiscovery/fastdialer v0.2.10/go.mod h1:21rwXMecVsPVdSvON8Up761/GgxC4OSc9Rvx5LNH5fY=
|
||||
github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA=
|
||||
github.com/projectdiscovery/fasttemplate v0.0.2/go.mod h1:XYWWVMxnItd+r0GbjA1GCsUopMw1/XusuQxdyAIHMCw=
|
||||
github.com/projectdiscovery/freeport v0.0.5 h1:jnd3Oqsl4S8n0KuFkE5Hm8WGDP24ITBvmyw5pFTHS8Q=
|
||||
github.com/projectdiscovery/freeport v0.0.5/go.mod h1:PY0bxSJ34HVy67LHIeF3uIutiCSDwOqKD8ruBkdiCwE=
|
||||
github.com/projectdiscovery/freeport v0.0.7 h1:Q6uXo/j8SaV/GlAHkEYQi8WQoPXyJWxyspx+aFmz9Qk=
|
||||
github.com/projectdiscovery/freeport v0.0.7/go.mod h1:cOhWKvNBe9xM6dFJ3RrrLvJ5vXx2NQ36SecuwjenV2k=
|
||||
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb h1:rutG906Drtbpz4DwU5mhGIeOhRcktDH4cGQitGUMAsg=
|
||||
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb/go.mod h1:FLjF1DmZ+POoGEiIQdWuYVwS++C/GwpX8YaCsTSm1RY=
|
||||
github.com/projectdiscovery/goflags v0.1.56 h1:tJYiZN7s9Jk9DxfYOUiqOoybaIDlXyX4ZgT4B/06SyU=
|
||||
github.com/projectdiscovery/goflags v0.1.56/go.mod h1:DsGF0NPpM5hGg75N3MTSvWJ4MIT7HFEAOEeWZ074+Fg=
|
||||
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/goflags v0.1.65 h1:rjoj+5lP/FDzgeM0WILUTX9AOOnw0J0LXtl8P1SVeGE=
|
||||
github.com/projectdiscovery/goflags v0.1.65/go.mod h1:cg6+yrLlaekP1hnefBc/UXbH1YGWa0fuzEW9iS1aG4g=
|
||||
github.com/projectdiscovery/gologger v1.1.33 h1:wQxaQ8p/0Rx89lowBp0PnY2QSWiqf9QW1vGYAllsVJ4=
|
||||
github.com/projectdiscovery/gologger v1.1.33/go.mod h1:P/WwqKstshQATJxN39V0KJ9ZuiGLOizmSqHIYrrz1T4=
|
||||
github.com/projectdiscovery/gostruct v0.0.2 h1:s8gP8ApugGM4go1pA+sVlPDXaWqNP5BBDDSv7VEdG1M=
|
||||
github.com/projectdiscovery/gostruct v0.0.2/go.mod h1:H86peL4HKwMXcQQtEa6lmC8FuD9XFt6gkNR0B/Mu5PE=
|
||||
github.com/projectdiscovery/gozero v0.0.2 h1:8fJeaCjxL9tpm33uG/RsCQs6HGM/NE6eA3cjkilRQ+E=
|
||||
github.com/projectdiscovery/gozero v0.0.2/go.mod h1:d8bZvDWW07LWNYWrwjZ4OO1I0cpkfqaysyDfSs9ibK8=
|
||||
github.com/projectdiscovery/hmap v0.0.47 h1:NdakfvlFruevnOvehdllofg/hc0CQn2WQaLHaRcsGAk=
|
||||
github.com/projectdiscovery/hmap v0.0.47/go.mod h1:/9V6EnyTY33hAy71Quox6Ggu9ZkKp36tgepBh/NzNSg=
|
||||
github.com/projectdiscovery/httpx v1.6.3 h1:TSu3zEKOHGFfMsGeB0lZEFRl6Tq4nPuIgKDXi9NnYpg=
|
||||
github.com/projectdiscovery/httpx v1.6.3/go.mod h1:9FmsmkT71aTa4WnOyBIPzB8I9c0QAJ9PSVUqs2NkHRQ=
|
||||
github.com/projectdiscovery/gozero v0.0.3 h1:tsYkrSvWw4WdIUJyisd4MB1vRiw1X57TuVVk3p8Z3G8=
|
||||
github.com/projectdiscovery/gozero v0.0.3/go.mod h1:MpJ37Dsh94gy2EKqaemdeh+CzduGVB2SDfhr6Upsjew=
|
||||
github.com/projectdiscovery/hmap v0.0.69 h1:e30pCr6JShf/UyJmKQpx++Yceiijw4GWj3lFHGZ1yko=
|
||||
github.com/projectdiscovery/hmap v0.0.69/go.mod h1:LgZHcgcxOvA3X8tuFtfu4dofJjAHAfpMno27Jx0J34w=
|
||||
github.com/projectdiscovery/httpx v1.6.9 h1:ihyFclesLjvQpiJpRIlAYeebapyIbOI/arDAvvy1ES8=
|
||||
github.com/projectdiscovery/httpx v1.6.9/go.mod h1:zQtX5CtcDYXzIRWne1ztCVtqG0sXCnx84tFwfMHoB8Q=
|
||||
github.com/projectdiscovery/interactsh v1.2.0 h1:Al6jHiR+Usl9egYJDLJaWNHOcH8Rugk8gWMasc8Cmw8=
|
||||
github.com/projectdiscovery/interactsh v1.2.0/go.mod h1:Wxt0fnzxsfrAZQQlpVrf3xMatP4OXZaZbjuDkIQKdYY=
|
||||
github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb h1:MGtI4oE12ruWv11ZlPXXd7hl/uAaQZrFvrIDYDeVMd8=
|
||||
@@ -868,30 +890,30 @@ github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 h1:L/e8z8yw
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5/go.mod h1:pGW2ncnTxTxHtP9wzcIJAB+3/NMp6IiuQWd2NK7K+oc=
|
||||
github.com/projectdiscovery/networkpolicy v0.0.9 h1:IrlDoYZagNNO8y+7iZeHT8k5izE+nek7TdtvEBwCxqk=
|
||||
github.com/projectdiscovery/networkpolicy v0.0.9/go.mod h1:XFJ2Lnv8BE/ziQCFjBHMsH1w6VmkPiQtk+NlBpdMU7M=
|
||||
github.com/projectdiscovery/ratelimit v0.0.45 h1:h28oF+hJ0CHcdBZozT1Go7ppWmzTxSXDKNNh2G1Ot9Q=
|
||||
github.com/projectdiscovery/ratelimit v0.0.45/go.mod h1:1vSJUseDS7SjNwIBi9wNRcgsMKNTLxy/GfdlLFVbgI4=
|
||||
github.com/projectdiscovery/rawhttp v0.1.51 h1:T4sskU2fsX9zNR7nyae0tD/0fliIs73KwBzyoJwBs10=
|
||||
github.com/projectdiscovery/rawhttp v0.1.51/go.mod h1:ejBaw3dCfJSfbtFv0ib6YfFSjQzt7ZdRVpQWJASxIUs=
|
||||
github.com/projectdiscovery/ratelimit v0.0.64 h1:fDjCM+U9HqJU6+NBvJn0kY89PxD20iWvRFX1mLblRB8=
|
||||
github.com/projectdiscovery/ratelimit v0.0.64/go.mod h1:XVuisddIjhmdd9ukw+w90AkSJd3pEKBTG9fBvSjwVxs=
|
||||
github.com/projectdiscovery/rawhttp v0.1.76 h1:O2IoYSyG7unH5oW8r8j3539koCNkimyzcHFmCbx5BDU=
|
||||
github.com/projectdiscovery/rawhttp v0.1.76/go.mod h1:ZxvbdkRV2PBoCbJxHh9B0P0nC5gVG3p1Z5uiua3iC5I=
|
||||
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gBVSorSzvmm0bFa7gDV4QNSOWPL/fgZ4kTXBxk=
|
||||
github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg=
|
||||
github.com/projectdiscovery/retryabledns v1.0.65 h1:wOtMuVkrcrGkzaT8Jixb3BtUcJODXLRz+z9EjftmFsQ=
|
||||
github.com/projectdiscovery/retryabledns v1.0.65/go.mod h1:lf3xRdFhGh55fWVlzK1oAaDPrsKliqH3gGvsFNAOkCk=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.66 h1:dY+sGVf/O8CvKcSdTx0rxJoKG+HyOScz5T89TijZohU=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.66/go.mod h1:3QJt06j4hEZVpJOr31u49I3mDnqbAzhcjJX8Yvn/xnY=
|
||||
github.com/projectdiscovery/retryabledns v1.0.86 h1:8YMJGJ94lFBKKN3t7NOzJfbGsZoh9qNpi49xdfJcZVc=
|
||||
github.com/projectdiscovery/retryabledns v1.0.86/go.mod h1:5PhXvlLkEFmlYOt9i4wiKA1eONLrNiZ6DQE88Ph9rgU=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.88 h1:uR6T+i8Sy1isfG1KClhhsXnOqkOR6E8MAvuyOFq3T10=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.88/go.mod h1:ktjiIKyej+plUeK9vksqRf3wGicqY3E1rW84V/O7p0M=
|
||||
github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us=
|
||||
github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ=
|
||||
github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA=
|
||||
github.com/projectdiscovery/stringsutil v0.0.2/go.mod h1:EJ3w6bC5fBYjVou6ryzodQq37D5c6qbAYQpGmAy+DC0=
|
||||
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.8 h1:nE8bYJuwhqk0BEMRQRhNbjPGMy40A9gkiMk5xq6U4u0=
|
||||
github.com/projectdiscovery/uncover v1.0.8/go.mod h1:1SwsNqjwMkJEzJQ7lQr5AHIdYd+BQlyqhO5IwIYmIAM=
|
||||
github.com/projectdiscovery/useragent v0.0.56 h1:KpUtOgq1vUerPrgRFZAIr1hF0lDxA2RF6YkT2PLwSoQ=
|
||||
github.com/projectdiscovery/useragent v0.0.56/go.mod h1:LAh9vudxXPA5JfNN3+1g/Unqvulq0BDkjxK7IrE+e/s=
|
||||
github.com/projectdiscovery/utils v0.1.4 h1:VSULN/RBEXbkgWuhrDey84ZDnSXtYMSev9p+QHXXDeI=
|
||||
github.com/projectdiscovery/utils v0.1.4/go.mod h1:mXs6OOeG9l/dVchjB2PGvQO3+wuMiE14Y/kmHeKogoM=
|
||||
github.com/projectdiscovery/wappalyzergo v0.1.6 h1:4iZDEnytsnAqjQgD5K6lmAzVx++KSQeMCDfomDtQM1M=
|
||||
github.com/projectdiscovery/wappalyzergo v0.1.6/go.mod h1:wBYGKmA5BQp/NWsAy1q/jSH8N1LHWQ/LV26DuR+KzPM=
|
||||
github.com/projectdiscovery/tlsx v1.1.8 h1:Y+VkOp6JmUBb4tci1Fbz9U7ELEQ2irFhm+HS58tHruM=
|
||||
github.com/projectdiscovery/tlsx v1.1.8/go.mod h1:6u/dbLuMsLzmux58AWnAB24qh2+Trk0auCK2I9B17Vo=
|
||||
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.78 h1:YpgiY3qXpzygFA88SWVseAyWeV9ZKrIpDkfOY+mQ/UY=
|
||||
github.com/projectdiscovery/useragent v0.0.78/go.mod h1:SQgk2DZu1qCvYqBRYWs2sjenXqLEDnRw65wJJoolwZ4=
|
||||
github.com/projectdiscovery/utils v0.3.0 h1:JNRMUPMx2gSzdk3bOQPtXSucoz+qC1JVkibIn7+kPTk=
|
||||
github.com/projectdiscovery/utils v0.3.0/go.mod h1:k2XlmfaYO4k6T4vAyUa3Kn/0BxPTIlNiBFpM6nVCbz0=
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.5 h1:DhPEgeD+9i6yg+aGlbkT4iOAspQfB5ZzrmpEhwoiMlA=
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.5/go.mod h1:fXiqsyLHaX/ovBNUe/nX0318bWON6SHftLvgq1xaOq0=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.4 h1:eZoESapnMw6WAHiVgRwNqvbJEfNHEH148uthhFbG5jE=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.4/go.mod h1:8PIPRcUD55UbtQdcfFR1hpIGRWG0P7alClXNGt1TBik=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
@@ -929,14 +951,14 @@ github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/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.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig=
|
||||
github.com/refraction-networking/utls v1.6.6/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
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/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=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg=
|
||||
github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
@@ -966,6 +988,8 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0=
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
@@ -1008,8 +1032,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9 h1:GXIyLuIJ5Qk46lI8WJ83qHBZKUI3zhmMmuoY9HICUIQ=
|
||||
@@ -1070,10 +1094,16 @@ github.com/weppos/publicsuffix-go v0.30.2/go.mod h1:/hGscit36Yt+wammfBBwdMdxBT8b
|
||||
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.84.0 h1:PdpCaskQSgcVDsx21c6ikf8Rfyo7SNtFAJwP9PrbCFE=
|
||||
github.com/xanzy/go-gitlab v0.84.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw=
|
||||
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/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@@ -1085,8 +1115,12 @@ github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yassinebenaid/godump v0.10.0 h1:FolBA+Ix5uwUiXYBBYOsf1VkT5+0f4gtFNTkYTiIR08=
|
||||
github.com/yassinebenaid/godump v0.10.0/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44=
|
||||
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
||||
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=
|
||||
github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=
|
||||
github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
|
||||
@@ -1106,11 +1140,11 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
|
||||
github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
|
||||
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
|
||||
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4=
|
||||
github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/zcalusic/sysinfo v1.0.2 h1:nwTTo2a+WQ0NXwo0BGRojOJvJ/5XKvQih+2RrtWqfxc=
|
||||
@@ -1139,6 +1173,8 @@ 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/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||
go.mongodb.org/mongo-driver v1.17.0 h1:Hp4q2MCjvY19ViwimTs00wHi7G4yzxh4/2+nTx8r40k=
|
||||
go.mongodb.org/mongo-driver v1.17.0/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
@@ -1174,7 +1210,6 @@ 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=
|
||||
@@ -1188,8 +1223,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -1268,13 +1303,11 @@ 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=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
@@ -1284,8 +1317,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1295,8 +1328,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.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
|
||||
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
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=
|
||||
@@ -1310,8 +1343,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1374,7 +1407,6 @@ golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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=
|
||||
@@ -1387,8 +1419,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1401,8 +1433,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1419,14 +1451,14 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
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/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.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=
|
||||
@@ -1509,8 +1541,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -1573,8 +1603,9 @@ 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=
|
||||
@@ -1608,7 +1639,6 @@ 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=
|
||||
|
||||
@@ -14,7 +14,7 @@ dns:
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "ghost.io"
|
||||
- ".vercel-dns.com"
|
||||
internal: true
|
||||
|
||||
http:
|
||||
@@ -25,4 +25,4 @@ http:
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "ghost.io"
|
||||
- "html>"
|
||||
@@ -23,4 +23,4 @@ code:
|
||||
- type: dsl
|
||||
dsl:
|
||||
- true
|
||||
# digest: 490a004630440220192fb8f704b078c2885047b85ac1a0491be86485c033a976d201599683a35aab0220604b1c3781e9d97079d0e5c23c18e6a2d87493c8e2b930536e692ee7d06e9247:4a3eb6b4988d95847d4203be25ed1d46
|
||||
# digest: 490a00463044022048c083c338c0195f5012122d40c1009d2e2030c583e56558e0d6249a41e6f3f4022070656adf748f4874018d7a01fce116db10a3acd1f9b03e12a83906fb625b5c50:4a3eb6b4988d95847d4203be25ed1d46
|
||||
@@ -20,4 +20,4 @@ code:
|
||||
- type: word
|
||||
words:
|
||||
- "hello from input baz"
|
||||
# digest: 4a0a00473045022033f72f1b9d5143f58a2dc79c2597000f34080251ac3702c36c3fad00917dfeeb0221009ba05c715c9e2e36dba471be6c0106a09ae3822d8a3e9e4bcf377e9f4a395a01:4a3eb6b4988d95847d4203be25ed1d46
|
||||
# digest: 4b0a00483046022100cbbdb7214f669d111b671d271110872dc8af2ab41cf5c312b6e4f64126f55337022100a60547952a0c2bea58388f2d2effe8ad73cd6b6fc92e73eb3c8f88beab6105ec:4a3eb6b4988d95847d4203be25ed1d46
|
||||
@@ -18,4 +18,4 @@ code:
|
||||
- type: word
|
||||
words:
|
||||
- "hello from input"
|
||||
# digest: 4a0a004730450220377128cb11d9f6f0fee1f4dbd841e46783de26e90a216fa55a7609ee2bc823c60221009166ee0f85e3a1811588ab19e73ea96ab3d582dc8180dbcbbad0ea9ab7e9025d:4a3eb6b4988d95847d4203be25ed1d46
|
||||
# digest: 4a0a00473045022032b81e8bb7475abf27639b0ced71355497166d664698021f26498e7031d62a23022100e99ccde578bfc0b658f16427ae9a3d18922849d3ba3e022032ea0d2a8e77fadb:4a3eb6b4988d95847d4203be25ed1d46
|
||||
@@ -26,4 +26,4 @@ code:
|
||||
part: interactsh_protocol
|
||||
words:
|
||||
- "http"
|
||||
# digest: 4b0a00483046022100d472d50bd83117d334f5217c7a40dcdf34138e90029eaace51697d902296bf37022100a393b49420a96f60d6d89b79b5135ee2233b2468d374851890eea114b08195d1:4a3eb6b4988d95847d4203be25ed1d46
|
||||
# digest: 4a0a0047304502201a5dd0eddfab4f02588a5a8ac1947a5fa41fed80b59d698ad5cc00456296efb6022100fe6e608e38c060964800f5f863a7cdc93f686f2d0f4b52854f73948b808b4511:4a3eb6b4988d95847d4203be25ed1d46
|
||||
@@ -21,4 +21,4 @@ code:
|
||||
- type: word
|
||||
words:
|
||||
- "hello from input"
|
||||
# digest: 4b0a004830460221008886054bb5dd6345e434e30f31c8fddce3c484a4f33aa6321b5185675866029d022100d188a83d0fde029f8b586061c65ab72b43755c3fb10fdd59501bb9bbadbb1ff7:4a3eb6b4988d95847d4203be25ed1d46
|
||||
# digest: 4b0a00483046022100ced1702728cc68f906c4c7d2c4d05ed071bfabee1e36eec7ebecbeca795a170c022100d20fd41796f130a8f9c4972fee85386d67d61eb5fc1119b1afe2a851eb2f3e65:4a3eb6b4988d95847d4203be25ed1d46
|
||||
@@ -13,7 +13,7 @@ dns:
|
||||
- type: dsl
|
||||
name: blogid
|
||||
dsl:
|
||||
- trim_suffix(cname,'.ghost.io')
|
||||
- trim_suffix(cname,'.vercel-dns.com')
|
||||
internal: true
|
||||
|
||||
http:
|
||||
@@ -24,6 +24,6 @@ http:
|
||||
matchers:
|
||||
- type: dsl
|
||||
dsl:
|
||||
- contains(body,'ProjectDiscovery.io') # check for http string
|
||||
- blogid == 'projectdiscovery' # check for cname (extracted information from dns response)
|
||||
- contains(body,'introduction') # check for http string
|
||||
- blogid == 'cname' # check for cname (extracted information from dns response)
|
||||
condition: and
|
||||
@@ -7,7 +7,7 @@ info:
|
||||
|
||||
|
||||
variables:
|
||||
cname_filtered: '{{trim_suffix(dns_cname,".ghost.io")}}'
|
||||
cname_filtered: '{{trim_suffix(dns_cname,".vercel-dns.com")}}'
|
||||
|
||||
dns:
|
||||
- name: "{{FQDN}}" # DNS Request
|
||||
@@ -24,7 +24,7 @@ http:
|
||||
matchers:
|
||||
- type: dsl
|
||||
dsl:
|
||||
- contains(http_body,'ProjectDiscovery.io') # check for http string
|
||||
- cname_filtered == 'projectdiscovery' # check for cname (extracted information from dns response)
|
||||
- ssl_subject_cn == 'blog.projectdiscovery.io'
|
||||
- contains(http_body,'introduction') # check for http string
|
||||
- cname_filtered == 'cname' # check for cname (extracted information from dns response)
|
||||
- ssl_subject_cn == 'docs.projectdiscovery.io'
|
||||
condition: and
|
||||
@@ -20,7 +20,7 @@ http:
|
||||
matchers:
|
||||
- type: dsl
|
||||
dsl:
|
||||
- contains(http_body,'ProjectDiscovery.io') # check for http string
|
||||
- trim_suffix(dns_cname,'.ghost.io') == 'projectdiscovery' # check for cname (extracted information from dns response)
|
||||
- ssl_subject_cn == 'blog.projectdiscovery.io'
|
||||
- contains(http_body,'introduction') # check for http string
|
||||
- trim_suffix(dns_cname,'.vercel-dns.com') == 'cname' # check for cname (extracted information from dns response)
|
||||
- ssl_subject_cn == 'docs.projectdiscovery.io'
|
||||
condition: and
|
||||
@@ -19,4 +19,4 @@ code:
|
||||
regex:
|
||||
- 'hello from (.*)'
|
||||
group: 1
|
||||
# digest: 490a0046304402202c63d47bb0acdd40b3b852d95490d492ff5741b84071b2a8a40371be7797c13602202b6b977e157edf2ef70a402a2e57d4eb5a67c5ca91f0a2f9a10a966e8485ebaf:4a3eb6b4988d95847d4203be25ed1d46
|
||||
# digest: 490a0046304402206b3648e8d393ac4df82c7d59b1a6ee3731c66c249dbd4d9bf31f0b7f176b37ec02203184d36373e516757c7d708b5799bc16edb1cebc0a64f3442d13ded4b33c42fb:4a3eb6b4988d95847d4203be25ed1d46
|
||||
@@ -18,4 +18,4 @@ code:
|
||||
- type: word
|
||||
words:
|
||||
- "hello from first"
|
||||
# digest: 490a00463044022025661eab353b7f359c0d428a86b6287545d7f759375e8025cc8c9c77b616ca6502200bc2c019059622df3c88e7caa6dd7d1fb9b956010aa0de2ee2b9f7dd0a3c4954:4a3eb6b4988d95847d4203be25ed1d46
|
||||
# digest: 490a0046304402204cbb1bdf8370e49bb930b17460fb35e15f285a3b48b165736ac0e7ba2f9bc0fb022067c134790c4a2cf646b195aa4488e2c222266436e6bda47931908a28807bdb81:4a3eb6b4988d95847d4203be25ed1d46
|
||||
@@ -0,0 +1,23 @@
|
||||
id: multimatch-value-share-template
|
||||
|
||||
info:
|
||||
name: MultiMatch Value Share Template
|
||||
author: tovask
|
||||
severity: info
|
||||
|
||||
http:
|
||||
- path:
|
||||
- "{{BaseURL}}/path1?v=1"
|
||||
- "{{BaseURL}}/path1?v=2"
|
||||
matchers:
|
||||
- type: word
|
||||
name: test-matcher
|
||||
words:
|
||||
- "href"
|
||||
extractors:
|
||||
- type: regex
|
||||
part: body
|
||||
name: extracted
|
||||
regex:
|
||||
- 'href="(.*)"'
|
||||
group: 1
|
||||
@@ -0,0 +1,21 @@
|
||||
id: multimatch-value-share-workflow
|
||||
|
||||
info:
|
||||
name: MultiMatch Value Share Workflow
|
||||
author: tovask
|
||||
severity: info
|
||||
description: Workflow to test value sharing when multiple matches occur in the extractor template
|
||||
|
||||
workflows:
|
||||
- template: workflow/multimatch-value-share-template.yaml
|
||||
subtemplates:
|
||||
- template: workflow/match-1.yaml
|
||||
subtemplates:
|
||||
- template: workflow/http-value-share-template-2.yaml
|
||||
- template: workflow/multimatch-value-share-template.yaml
|
||||
matchers:
|
||||
- name: test-matcher
|
||||
subtemplates:
|
||||
- template: workflow/match-1.yaml
|
||||
subtemplates:
|
||||
- template: workflow/http-value-share-template-2.yaml
|
||||
@@ -5,9 +5,17 @@ import (
|
||||
urlutil "github.com/projectdiscovery/utils/url"
|
||||
)
|
||||
|
||||
func getScanDashBoardURL(id string) string {
|
||||
func getScanDashBoardURL(id string, teamID 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()
|
||||
}
|
||||
|
||||
+19
-8
@@ -32,13 +32,14 @@ const (
|
||||
MaxChunkSize = 4 * unitutils.Mega // 4 MB
|
||||
xidRe = `^[a-z0-9]{20}$`
|
||||
teamIDHeader = "X-Team-Id"
|
||||
NoneTeamID = "none"
|
||||
)
|
||||
|
||||
var (
|
||||
xidRegex = regexp.MustCompile(xidRe)
|
||||
_ output.Writer = &UploadWriter{}
|
||||
// teamID if given
|
||||
teamID = env.GetEnvOrDefault("PDCP_TEAM_ID", "")
|
||||
TeamIDEnv = env.GetEnvOrDefault("PDCP_TEAM_ID", NoneTeamID)
|
||||
)
|
||||
|
||||
// UploadWriter is a writer that uploads its output to pdcp
|
||||
@@ -53,6 +54,7 @@ type UploadWriter struct {
|
||||
scanID string
|
||||
scanName string
|
||||
counter atomic.Int32
|
||||
TeamID string
|
||||
}
|
||||
|
||||
// NewUploadWriter creates a new upload writer
|
||||
@@ -61,8 +63,9 @@ 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),
|
||||
creds: creds,
|
||||
done: make(chan struct{}, 1),
|
||||
TeamID: NoneTeamID,
|
||||
}
|
||||
var err error
|
||||
reader, writer := io.Pipe()
|
||||
@@ -110,6 +113,14 @@ 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) {
|
||||
reader := bufio.NewReader(r)
|
||||
ch := make(chan string, 4)
|
||||
@@ -136,13 +147,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))
|
||||
gologger.Info().Msgf("%v Scan results uploaded to cloud, you can view scan results at %v", u.counter.Load(), getScanDashBoardURL(u.scanID, u.TeamID))
|
||||
}
|
||||
}()
|
||||
// temporary buffer to store the results
|
||||
buff := &bytes.Buffer{}
|
||||
ticker := time.NewTicker(flushTimer)
|
||||
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@@ -189,7 +200,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))
|
||||
gologger.Warning().Msgf("Uploaded results chunk, you can view scan results at %v", getScanDashBoardURL(u.scanID, u.TeamID))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -248,8 +259,8 @@ func (u *UploadWriter) getRequest(bin []byte) (*retryablehttp.Request, error) {
|
||||
req.URL.Update()
|
||||
|
||||
req.Header.Set(pdcpauth.ApiKeyHeaderName, u.creds.APIKey)
|
||||
if teamID != "" {
|
||||
req.Header.Set(teamIDHeader, teamID)
|
||||
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")
|
||||
|
||||
@@ -3,6 +3,7 @@ package runner
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider/authx"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
|
||||
@@ -10,9 +11,12 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/helpers/writer"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/replacer"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
"github.com/projectdiscovery/utils/env"
|
||||
errorutil "github.com/projectdiscovery/utils/errors"
|
||||
)
|
||||
|
||||
@@ -51,6 +55,7 @@ func GetAuthTmplStore(opts types.Options, catalog catalog.Catalog, execOpts prot
|
||||
opts.ExcludeProtocols = nil
|
||||
opts.IncludeConditions = nil
|
||||
cfg := loader.NewConfig(&opts, catalog, execOpts)
|
||||
cfg.StoreId = loader.AuthStoreId
|
||||
store, err := loader.New(cfg)
|
||||
if err != nil {
|
||||
return nil, errorutil.NewWithErr(err).Msgf("failed to initialize dynamic auth templates store")
|
||||
@@ -74,7 +79,25 @@ func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret
|
||||
vars := map[string]interface{}{}
|
||||
mainCtx := context.Background()
|
||||
ctx := scan.NewScanContext(mainCtx, contextargs.NewWithInput(mainCtx, d.Input))
|
||||
|
||||
cliVars := map[string]interface{}{}
|
||||
if opts.ExecOpts.Options != nil {
|
||||
// gets variables passed from cli -v and -env-vars
|
||||
cliVars = generators.BuildPayloadFromOptions(opts.ExecOpts.Options)
|
||||
}
|
||||
|
||||
for _, v := range d.Variables {
|
||||
// Check if the template has any env variables and expand them
|
||||
if strings.HasPrefix(v.Value, "$") {
|
||||
env.ExpandWithEnv(&v.Value)
|
||||
}
|
||||
if strings.Contains(v.Value, "{{") {
|
||||
// if variables had value like {{username}}, then replace it with the value from cliVars
|
||||
// variables:
|
||||
// - key: username
|
||||
// value: {{username}}
|
||||
v.Value = replacer.Replace(v.Value, cliVars)
|
||||
}
|
||||
vars[v.Key] = v.Value
|
||||
ctx.Input.Add(v.Key, v.Value)
|
||||
}
|
||||
|
||||
+12
-10
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/projectdiscovery/gologger/levels"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/vardump"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/reporting"
|
||||
@@ -69,6 +68,7 @@ func ParseOptions(options *types.Options) {
|
||||
|
||||
if options.ShowVarDump {
|
||||
vardump.EnableVarDump = true
|
||||
vardump.Limit = options.VarDumpLimit
|
||||
}
|
||||
if options.ShowActions {
|
||||
gologger.Info().Msgf("Showing available headless actions: ")
|
||||
@@ -115,12 +115,7 @@ func ParseOptions(options *types.Options) {
|
||||
// Load the resolvers if user asked for them
|
||||
loadResolvers(options)
|
||||
|
||||
err := protocolstate.Init(options)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not initialize protocol state: %s\n", err)
|
||||
}
|
||||
|
||||
err = protocolinit.Init(options)
|
||||
err := protocolinit.Init(options)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not initialize protocols: %s\n", err)
|
||||
}
|
||||
@@ -309,10 +304,17 @@ func createReportingOptions(options *types.Options) (*reporting.Options, error)
|
||||
OmitRaw: options.OmitRawRequests,
|
||||
}
|
||||
}
|
||||
// Combine options.
|
||||
if options.JSONLExport != "" {
|
||||
reportingOptions.JSONLExporter = &jsonl.Options{
|
||||
File: options.JSONLExport,
|
||||
OmitRaw: options.OmitRawRequests,
|
||||
// Combine the CLI options with the config file options with the CLI options taking precedence
|
||||
if reportingOptions.JSONLExporter != nil {
|
||||
reportingOptions.JSONLExporter.File = options.JSONLExport
|
||||
reportingOptions.JSONLExporter.OmitRaw = options.OmitRawRequests
|
||||
} else {
|
||||
reportingOptions.JSONLExporter = &jsonl.Options{
|
||||
File: options.JSONLExport,
|
||||
OmitRaw: options.OmitRawRequests,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/automaticscan"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/globalmatchers"
|
||||
"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"
|
||||
@@ -391,6 +392,9 @@ func (r *Runner) Close() {
|
||||
if r.tmpDir != "" {
|
||||
_ = os.RemoveAll(r.tmpDir)
|
||||
}
|
||||
|
||||
//this is no-op unless nuclei is built with stats build tag
|
||||
events.Close()
|
||||
}
|
||||
|
||||
// setupPDCPUpload sets up the PDCP upload writer
|
||||
@@ -426,6 +430,9 @@ func (r *Runner) setupPDCPUpload(writer output.Writer) output.Writer {
|
||||
if r.options.ScanName != "" {
|
||||
uploadWriter.SetScanName(r.options.ScanName)
|
||||
}
|
||||
if r.options.TeamID != "" {
|
||||
uploadWriter.SetTeamID(r.options.TeamID)
|
||||
}
|
||||
return output.NewMultiWriter(writer, uploadWriter)
|
||||
}
|
||||
|
||||
@@ -472,6 +479,7 @@ func (r *Runner) RunEnumeration() error {
|
||||
TemporaryDirectory: r.tmpDir,
|
||||
Parser: r.parser,
|
||||
FuzzParamsFrequency: fuzzFreqCache,
|
||||
GlobalMatchers: globalmatchers.New(),
|
||||
}
|
||||
|
||||
if config.DefaultConfig.IsDebugArgEnabled(config.DebugExportURLPattern) {
|
||||
@@ -498,8 +506,17 @@ func (r *Runner) RunEnumeration() error {
|
||||
}
|
||||
|
||||
if r.options.ShouldUseHostError() {
|
||||
cache := hosterrorscache.New(r.options.MaxHostError, hosterrorscache.DefaultMaxHostsCount, r.options.TrackError)
|
||||
maxHostError := r.options.MaxHostError
|
||||
if r.options.TemplateThreads > maxHostError {
|
||||
gologger.Print().Msgf("[%v] The concurrency value is higher than max-host-error", r.colorizer.BrightYellow("WRN"))
|
||||
gologger.Info().Msgf("Adjusting max-host-error to the concurrency value: %d", r.options.TemplateThreads)
|
||||
|
||||
maxHostError = r.options.TemplateThreads
|
||||
}
|
||||
|
||||
cache := hosterrorscache.New(maxHostError, hosterrorscache.DefaultMaxHostsCount, r.options.TrackError)
|
||||
cache.SetVerbose(r.options.Verbose)
|
||||
|
||||
r.hostErrors = cache
|
||||
executorOpts.HostErrorsCache = cache
|
||||
}
|
||||
@@ -713,6 +730,8 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
|
||||
stats.ForceDisplayWarning(templates.ExcludedCodeTmplStats)
|
||||
stats.ForceDisplayWarning(templates.ExludedDastTmplStats)
|
||||
stats.ForceDisplayWarning(templates.TemplatesExcludedStats)
|
||||
stats.ForceDisplayWarning(templates.ExcludedFileStats)
|
||||
stats.ForceDisplayWarning(templates.ExcludedSelfContainedStats)
|
||||
}
|
||||
|
||||
if tmplCount == 0 && workflowCount == 0 {
|
||||
@@ -781,6 +800,52 @@ func (r *Runner) SaveResumeConfig(path string) error {
|
||||
return os.WriteFile(path, data, permissionutil.ConfigFilePermission)
|
||||
}
|
||||
|
||||
// upload existing scan results to cloud with progress
|
||||
func UploadResultsToCloud(options *types.Options) error {
|
||||
h := &pdcpauth.PDCPCredHandler{}
|
||||
creds, err := h.GetCreds()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get credentials for cloud upload")
|
||||
}
|
||||
ctx := context.TODO()
|
||||
uploadWriter, err := pdcp.NewUploadWriter(ctx, creds)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not create upload writer")
|
||||
}
|
||||
if options.ScanID != "" {
|
||||
_ = uploadWriter.SetScanID(options.ScanID)
|
||||
}
|
||||
if options.ScanName != "" {
|
||||
uploadWriter.SetScanName(options.ScanName)
|
||||
}
|
||||
if options.TeamID != "" {
|
||||
uploadWriter.SetTeamID(options.TeamID)
|
||||
}
|
||||
|
||||
// Open file to count the number of results first
|
||||
file, err := os.Open(options.ScanUploadFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not open scan upload file")
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
gologger.Info().Msgf("Uploading scan results to cloud dashboard from %s", options.ScanUploadFile)
|
||||
dec := json.NewDecoder(file)
|
||||
for dec.More() {
|
||||
var r output.ResultEvent
|
||||
err := dec.Decode(&r)
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("Could not decode jsonl: %s\n", err)
|
||||
continue
|
||||
}
|
||||
if err = uploadWriter.Write(&r); err != nil {
|
||||
gologger.Warning().Msgf("[%s] failed to upload: %s\n", r.TemplateID, err)
|
||||
}
|
||||
}
|
||||
uploadWriter.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
type WalkFunc func(reflect.Value, reflect.StructField)
|
||||
|
||||
// Walk traverses a struct and executes a callback function on each value in the struct.
|
||||
|
||||
@@ -380,6 +380,31 @@ func WithSandboxOptions(allowLocalFileAccess bool, restrictLocalNetworkAccess bo
|
||||
func EnableCodeTemplates() NucleiSDKOptions {
|
||||
return func(e *NucleiEngine) error {
|
||||
e.opts.EnableCodeTemplates = true
|
||||
e.opts.EnableSelfContainedTemplates = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableSelfContainedTemplates allows loading/executing self-contained templates
|
||||
func EnableSelfContainedTemplates() NucleiSDKOptions {
|
||||
return func(e *NucleiEngine) error {
|
||||
e.opts.EnableSelfContainedTemplates = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableGlobalMatchersTemplates allows loading/executing global-matchers templates
|
||||
func EnableGlobalMatchersTemplates() NucleiSDKOptions {
|
||||
return func(e *NucleiEngine) error {
|
||||
e.opts.EnableGlobalMatchersTemplates = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableFileTemplates allows loading/executing file protocol templates
|
||||
func EnableFileTemplates() NucleiSDKOptions {
|
||||
return func(e *NucleiEngine) error {
|
||||
e.opts.EnableFileTemplates = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -392,10 +417,30 @@ func WithHeaders(headers []string) NucleiSDKOptions {
|
||||
}
|
||||
}
|
||||
|
||||
// WithVars allows setting custom variables to use in templates/workflows context
|
||||
func WithVars(vars []string) NucleiSDKOptions {
|
||||
// Create a goflags.RuntimeMap
|
||||
runtimeVars := goflags.RuntimeMap{}
|
||||
for _, v := range vars {
|
||||
err := runtimeVars.Set(v)
|
||||
if err != nil {
|
||||
return func(e *NucleiEngine) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return func(e *NucleiEngine) error {
|
||||
e.opts.Vars = runtimeVars
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnablePassiveMode allows enabling passive HTTP response processing mode
|
||||
func EnablePassiveMode() NucleiSDKOptions {
|
||||
return func(e *NucleiEngine) error {
|
||||
e.opts.OfflineHTTP = true
|
||||
e.opts.DisableHTTPProbe = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -440,3 +485,11 @@ func WithCatalog(cat catalog.Catalog) NucleiSDKOptions {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DisableUpdateCheck disables nuclei update check
|
||||
func DisableUpdateCheck() NucleiSDKOptions {
|
||||
return func(e *NucleiEngine) error {
|
||||
DefaultConfig.DisableUpdateCheck()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/kitabisa/go-ci"
|
||||
nuclei "github.com/projectdiscovery/nuclei/v3/lib"
|
||||
"github.com/remeh/sizedwaitgroup"
|
||||
)
|
||||
@@ -78,9 +79,10 @@ func ExampleThreadSafeNucleiEngine() {
|
||||
func TestMain(m *testing.M) {
|
||||
// this file only contains testtables examples https://go.dev/blog/examples
|
||||
// and actual functionality test are in sdk_test.go
|
||||
if os.Getenv("GH_ACTION") != "" || os.Getenv("CI") != "" {
|
||||
if ci.IsCI() {
|
||||
// no need to run this test on github actions
|
||||
return
|
||||
}
|
||||
m.Run()
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
+22
-2
@@ -100,6 +100,7 @@ func (e *NucleiEngine) LoadAllTemplates() error {
|
||||
return errorutil.New("Could not create loader client: %s\n", err)
|
||||
}
|
||||
e.store.Load()
|
||||
e.templatesLoaded = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -111,6 +112,14 @@ func (e *NucleiEngine) GetTemplates() []*templates.Template {
|
||||
return e.store.Templates()
|
||||
}
|
||||
|
||||
// GetWorkflows returns all nuclei workflows that are loaded
|
||||
func (e *NucleiEngine) GetWorkflows() []*templates.Template {
|
||||
if !e.templatesLoaded {
|
||||
_ = e.LoadAllTemplates()
|
||||
}
|
||||
return e.store.Workflows()
|
||||
}
|
||||
|
||||
// LoadTargets(urls/domains/ips only) adds targets to the nuclei engine
|
||||
func (e *NucleiEngine) LoadTargets(targets []string, probeNonHttp bool) {
|
||||
for _, target := range targets {
|
||||
@@ -178,7 +187,8 @@ func (e *NucleiEngine) SignTemplate(tmplSigner *signer.TemplateSigner, data []by
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
buff := bytes.NewBuffer(signer.RemoveSignatureFromData(data))
|
||||
_, content := signer.ExtractSignatureAndContent(data)
|
||||
buff := bytes.NewBuffer(content)
|
||||
buff.WriteString("\n" + signatureData)
|
||||
return buff.Bytes(), err
|
||||
}
|
||||
@@ -243,7 +253,12 @@ func (e *NucleiEngine) ExecuteCallbackWithCtx(ctx context.Context, callback ...f
|
||||
}
|
||||
e.resultCallbacks = append(e.resultCallbacks, filtered...)
|
||||
|
||||
_ = e.engine.ExecuteScanWithOpts(ctx, e.store.Templates(), e.inputProvider, false)
|
||||
templatesAndWorkflows := append(e.store.Templates(), e.store.Workflows()...)
|
||||
if len(templatesAndWorkflows) == 0 {
|
||||
return ErrNoTemplatesAvailable
|
||||
}
|
||||
|
||||
_ = e.engine.ExecuteScanWithOpts(ctx, templatesAndWorkflows, e.inputProvider, false)
|
||||
defer e.engine.WorkPool().Wait()
|
||||
return nil
|
||||
}
|
||||
@@ -264,6 +279,11 @@ func (e *NucleiEngine) Engine() *core.Engine {
|
||||
return e.engine
|
||||
}
|
||||
|
||||
// Store returns store of nuclei
|
||||
func (e *NucleiEngine) Store() *loader.Store {
|
||||
return e.store
|
||||
}
|
||||
|
||||
// NewNucleiEngineCtx creates a new nuclei engine instance with given context
|
||||
func NewNucleiEngineCtx(ctx context.Context, options ...NucleiSDKOptions) (*NucleiEngine, error) {
|
||||
// default options
|
||||
|
||||
+6
-3
@@ -7,6 +7,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/input"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
@@ -118,9 +120,6 @@ func (e *NucleiEngine) init(ctx context.Context) error {
|
||||
_ = protocolinit.Init(e.opts)
|
||||
})
|
||||
|
||||
e.applyRequiredDefaults(ctx)
|
||||
var err error
|
||||
|
||||
if e.opts.ProxyInternal && types.ProxyURL != "" || types.ProxySocksURL != "" {
|
||||
httpclient, err := httpclientpool.Get(e.opts, &httpclientpool.Configuration{})
|
||||
if err != nil {
|
||||
@@ -129,6 +128,9 @@ func (e *NucleiEngine) init(ctx context.Context) error {
|
||||
e.httpClient = httpclient
|
||||
}
|
||||
|
||||
e.applyRequiredDefaults(ctx)
|
||||
var err error
|
||||
|
||||
// setup progressbar
|
||||
if e.enableStats {
|
||||
progressInstance, progressErr := progress.NewStatsTicker(e.opts.StatsInterval, e.enableStats, e.opts.StatsJSON, false, e.opts.MetricsPort)
|
||||
@@ -171,6 +173,7 @@ func (e *NucleiEngine) init(ctx context.Context) error {
|
||||
ResumeCfg: types.NewResumeCfg(),
|
||||
Browser: e.browserInstance,
|
||||
Parser: e.parser,
|
||||
InputHelper: input.NewHelper(),
|
||||
}
|
||||
if len(e.opts.SecretsFile) > 0 {
|
||||
authTmplStore, err := runner.GetAuthTmplStore(*e.opts, e.catalog, e.executerOpts)
|
||||
|
||||
@@ -133,3 +133,37 @@ func TestThreadSafeNuclei(t *testing.T) {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithVarsNuclei(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.EnableSelfContainedTemplates(),
|
||||
nuclei.WithTemplatesOrWorkflows(nuclei.TemplateSources{Templates: []string{"http/token-spray/api-1forge.yaml"}}),
|
||||
nuclei.WithVars([]string{"token=foobar"}),
|
||||
nuclei.WithVerbosity(nuclei.VerbosityOptions{Debug: true}),
|
||||
)
|
||||
require.Nil(t, err)
|
||||
ne.LoadTargets([]string{"scanme.sh"}, true) // probe http/https target is set to true here
|
||||
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("TestWithVarsNuclei", false) {
|
||||
cmd := exec.Command(os.Args[0], "-test.run=TestWithVarsNuclei")
|
||||
cmd.Env = append(os.Environ(), "TestWithVarsNuclei=true")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("process ran with error %s, output: %s", err, out)
|
||||
}
|
||||
} else {
|
||||
fn()
|
||||
}
|
||||
}
|
||||
+42
-5
@@ -3,6 +3,22 @@
|
||||
"$id": "https://templates.-template",
|
||||
"$ref": "#/$defs/templates.Template",
|
||||
"$defs": {
|
||||
"analyzers.AnalyzerTemplate": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"parameters": {
|
||||
"$ref": "#/$defs/map[string]interface {}"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"parameters"
|
||||
]
|
||||
},
|
||||
"code.Request": {
|
||||
"properties": {
|
||||
"matchers": {
|
||||
@@ -247,7 +263,12 @@
|
||||
"time",
|
||||
"select",
|
||||
"files",
|
||||
"waitdom",
|
||||
"waitfcp",
|
||||
"waitfmp",
|
||||
"waitidle",
|
||||
"waitload",
|
||||
"waitstable",
|
||||
"getresource",
|
||||
"extract",
|
||||
"setmethod",
|
||||
@@ -256,6 +277,7 @@
|
||||
"deleteheader",
|
||||
"setbody",
|
||||
"waitevent",
|
||||
"waitdialog",
|
||||
"keyboard",
|
||||
"debug",
|
||||
"sleep",
|
||||
@@ -779,6 +801,11 @@
|
||||
"title": "fuzzin rules for http fuzzing",
|
||||
"description": "Fuzzing describes rule schema to fuzz http requests"
|
||||
},
|
||||
"analyzer": {
|
||||
"$ref": "#/$defs/analyzers.AnalyzerTemplate",
|
||||
"title": "analyzer for http request",
|
||||
"description": "Analyzer for HTTP Request"
|
||||
},
|
||||
"self-contained": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -787,6 +814,11 @@
|
||||
"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",
|
||||
@@ -878,6 +910,11 @@
|
||||
],
|
||||
"title": "condition between the filters",
|
||||
"description": "Operator to use between multiple per-conditions"
|
||||
},
|
||||
"global-matchers": {
|
||||
"type": "boolean",
|
||||
"title": "global matchers",
|
||||
"description": "marks matchers as static and applies globally to all result events from other templates"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
@@ -941,11 +978,6 @@
|
||||
"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",
|
||||
@@ -1359,6 +1391,11 @@
|
||||
"title": "read all response stream",
|
||||
"description": "Read all response stream till the server stops sending"
|
||||
},
|
||||
"stop-at-first-match": {
|
||||
"type": "boolean",
|
||||
"title": "stop at first match",
|
||||
"description": "Stop the execution after a match is found"
|
||||
},
|
||||
"matchers": {
|
||||
"items": {
|
||||
"$ref": "#/$defs/matchers.Matcher"
|
||||
|
||||
+49
-32
@@ -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,29 +51,36 @@ func NewFileAuthProvider(path string, callback authx.LazyFetchSecret) (AuthProvi
|
||||
|
||||
// init initializes the file auth provider
|
||||
func (f *FileAuthProvider) init() {
|
||||
for _, secret := range f.store.Secrets {
|
||||
for _, _secret := range f.store.Secrets {
|
||||
secret := _secret // allocate copy of pointer
|
||||
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
|
||||
}
|
||||
f.compiled[compiled] = secret.GetStrategy()
|
||||
|
||||
if ss, ok := f.compiled[compiled]; ok {
|
||||
f.compiled[compiled] = append(ss, secret.GetStrategy())
|
||||
} else {
|
||||
f.compiled[compiled] = []authx.AuthStrategy{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)
|
||||
}
|
||||
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()
|
||||
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()}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,32 +88,38 @@ 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
|
||||
}
|
||||
f.compiled[compiled] = &authx.DynamicAuthStrategy{Dynamic: dynamic}
|
||||
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})
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, domain := range dynamic.Domains {
|
||||
if f.domains == nil {
|
||||
f.domains = make(map[string]authx.AuthStrategy)
|
||||
f.domains = make(map[string][]authx.AuthStrategy)
|
||||
}
|
||||
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}
|
||||
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})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
@@ -128,12 +141,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)
|
||||
}
|
||||
|
||||
@@ -150,17 +163,21 @@ func (f *FileAuthProvider) GetTemplatePaths() []string {
|
||||
|
||||
// PreFetchSecrets pre-fetches the secrets from the auth provider
|
||||
func (f *FileAuthProvider) PreFetchSecrets() error {
|
||||
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.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.compiled {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
CLIConfigFileName = "config.yaml"
|
||||
ReportingConfigFilename = "reporting-config.yaml"
|
||||
// Version is the current version of nuclei
|
||||
Version = `v3.2.9`
|
||||
Version = `v3.3.7`
|
||||
// Directory Names of custom templates
|
||||
CustomS3TemplatesDirName = "s3"
|
||||
CustomGitHubTemplatesDirName = "github"
|
||||
|
||||
@@ -216,12 +216,17 @@ func (c *DiskCatalog) findGlobPathMatches(absPath string, processed map[string]s
|
||||
// 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, "/")
|
||||
absPath = strings.Trim(absPath, "/")
|
||||
}
|
||||
var info fs.File
|
||||
if c.templatesFS == nil {
|
||||
info, err = os.Open(absPath)
|
||||
} else {
|
||||
// If we were given no path, then it's not a file, it's the root, and we can quietly return.
|
||||
if absPath == "" {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
info, err = c.templatesFS.Open(absPath)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -263,6 +268,12 @@ func (c *DiskCatalog) findDirectoryMatches(absPath string, processed map[string]
|
||||
},
|
||||
)
|
||||
} else {
|
||||
// For the special case of the root directory, we need to pass "." to `fs.WalkDir`.
|
||||
if absPath == "" {
|
||||
absPath = "."
|
||||
}
|
||||
absPath = strings.TrimSuffix(absPath, "/")
|
||||
|
||||
err = fs.WalkDir(
|
||||
c.templatesFS,
|
||||
absPath,
|
||||
|
||||
+25
-11
@@ -2,6 +2,7 @@ package disk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -21,6 +22,11 @@ func (c *DiskCatalog) ResolvePath(templateName, second string) (string, error) {
|
||||
if filepath.IsAbs(templateName) {
|
||||
return templateName, nil
|
||||
}
|
||||
if c.templatesFS != nil {
|
||||
if potentialPath, err := c.tryResolve(templateName); err != errNoValidCombination {
|
||||
return potentialPath, nil
|
||||
}
|
||||
}
|
||||
if second != "" {
|
||||
secondBasePath := filepath.Join(filepath.Dir(second), templateName)
|
||||
if potentialPath, err := c.tryResolve(secondBasePath); err != errNoValidCombination {
|
||||
@@ -28,17 +34,19 @@ func (c *DiskCatalog) ResolvePath(templateName, second string) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
curDirectory, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
if c.templatesFS == nil {
|
||||
curDirectory, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
templatePath := filepath.Join(curDirectory, templateName)
|
||||
if potentialPath, err := c.tryResolve(templatePath); err != errNoValidCombination {
|
||||
return potentialPath, nil
|
||||
}
|
||||
}
|
||||
|
||||
templatePath := filepath.Join(curDirectory, templateName)
|
||||
if potentialPath, err := c.tryResolve(templatePath); err != errNoValidCombination {
|
||||
return potentialPath, nil
|
||||
}
|
||||
|
||||
templatePath = filepath.Join(config.DefaultConfig.GetTemplateDir(), templateName)
|
||||
templatePath := filepath.Join(config.DefaultConfig.GetTemplateDir(), templateName)
|
||||
if potentialPath, err := c.tryResolve(templatePath); err != errNoValidCombination {
|
||||
return potentialPath, nil
|
||||
}
|
||||
@@ -50,8 +58,14 @@ var errNoValidCombination = errors.New("no valid combination found")
|
||||
|
||||
// tryResolve attempts to load locate the target by iterating across all the folders tree
|
||||
func (c *DiskCatalog) tryResolve(fullPath string) (string, error) {
|
||||
if fileutil.FileOrFolderExists(fullPath) {
|
||||
return fullPath, nil
|
||||
if c.templatesFS == nil {
|
||||
if fileutil.FileOrFolderExists(fullPath) {
|
||||
return fullPath, nil
|
||||
}
|
||||
} else {
|
||||
if _, err := fs.Stat(c.templatesFS, fullPath); err == nil {
|
||||
return fullPath, nil
|
||||
}
|
||||
}
|
||||
return "", errNoValidCombination
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader/filter"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/keys"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
const (
|
||||
httpPrefix = "http://"
|
||||
httpsPrefix = "https://"
|
||||
AuthStoreId = "auth_store"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -40,6 +42,7 @@ var (
|
||||
|
||||
// Config contains the configuration options for the loader
|
||||
type Config struct {
|
||||
StoreId string // used to set store id (optional)
|
||||
Templates []string
|
||||
TemplateURLs []string
|
||||
Workflows []string
|
||||
@@ -66,6 +69,7 @@ type Config struct {
|
||||
|
||||
// Store is a storage for loaded nuclei templates
|
||||
type Store struct {
|
||||
id string // id of the store (optional)
|
||||
tagFilter *templates.TagFilter
|
||||
pathFilter *filter.PathFilter
|
||||
config *Config
|
||||
@@ -131,6 +135,7 @@ func New(cfg *Config) (*Store, error) {
|
||||
|
||||
// Create a tag filter based on provided configuration
|
||||
store := &Store{
|
||||
id: cfg.StoreId,
|
||||
config: cfg,
|
||||
tagFilter: tagFilter,
|
||||
pathFilter: filter.NewPathFilter(&filter.PathFilterConfig{
|
||||
@@ -229,6 +234,10 @@ func (store *Store) ReadTemplateFromURI(uri string, remote bool) ([]byte, error)
|
||||
}
|
||||
}
|
||||
|
||||
func (store *Store) ID() string {
|
||||
return store.id
|
||||
}
|
||||
|
||||
// Templates returns all the templates in the store
|
||||
func (store *Store) Templates() []*templates.Template {
|
||||
return store.templates
|
||||
@@ -289,6 +298,27 @@ func (store *Store) LoadTemplatesOnlyMetadata() error {
|
||||
|
||||
for templatePath := range validPaths {
|
||||
template, _, _ := templatesCache.Has(templatePath)
|
||||
|
||||
if len(template.RequestsHeadless) > 0 && !store.config.ExecutorOptions.Options.Headless {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(template.RequestsCode) > 0 && !store.config.ExecutorOptions.Options.EnableCodeTemplates {
|
||||
continue
|
||||
}
|
||||
|
||||
if template.IsFuzzing() && !store.config.ExecutorOptions.Options.DAST {
|
||||
continue
|
||||
}
|
||||
|
||||
if template.SelfContained && !store.config.ExecutorOptions.Options.EnableSelfContainedTemplates {
|
||||
continue
|
||||
}
|
||||
|
||||
if template.HasFileProtocol() && !store.config.ExecutorOptions.Options.EnableFileTemplates {
|
||||
continue
|
||||
}
|
||||
|
||||
if template != nil {
|
||||
template.Path = templatePath
|
||||
store.templates = append(store.templates, template)
|
||||
@@ -343,7 +373,22 @@ func (store *Store) areWorkflowOrTemplatesValid(filteredTemplatePaths map[string
|
||||
if err != nil {
|
||||
if isParsingError("Error occurred parsing template %s: %s\n", templatePath, err) {
|
||||
areTemplatesValid = false
|
||||
continue
|
||||
}
|
||||
} else if template == nil {
|
||||
// NOTE(dwisiswant0): possibly global matchers template.
|
||||
// This could definitely be handled better, for example by returning an
|
||||
// `ErrGlobalMatchersTemplate` during `templates.Parse` and checking it
|
||||
// with `errors.Is`.
|
||||
//
|
||||
// However, I’m not sure if every reference to it should be handled
|
||||
// that way. Returning a `templates.Template` pointer would mean it’s
|
||||
// an active template (sending requests), and adding a specific field
|
||||
// like `isGlobalMatchers` in `templates.Template` (then checking it
|
||||
// with a `*templates.Template.IsGlobalMatchersEnabled` method) would
|
||||
// just introduce more unknown issues - like during template
|
||||
// clustering, AFAIK.
|
||||
continue
|
||||
} else {
|
||||
if existingTemplatePath, found := templateIDPathMap[template.ID]; !found {
|
||||
templateIDPathMap[template.ID] = templatePath
|
||||
@@ -434,7 +479,7 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
|
||||
// increment signed/unsigned counters
|
||||
if tmpl.Verified {
|
||||
if tmpl.TemplateVerifier == "" {
|
||||
templates.SignatureStats[templates.PDVerifier].Add(1)
|
||||
templates.SignatureStats[keys.PDVerifier].Add(1)
|
||||
} else {
|
||||
templates.SignatureStats[tmpl.TemplateVerifier].Add(1)
|
||||
}
|
||||
@@ -465,13 +510,25 @@ func (store *Store) LoadTemplatesWithTags(templatesList, tags []string) []*templ
|
||||
stats.Increment(templates.SkippedUnsignedStats)
|
||||
return
|
||||
}
|
||||
|
||||
if parsed.SelfContained && !store.config.ExecutorOptions.Options.EnableSelfContainedTemplates {
|
||||
stats.Increment(templates.ExcludedSelfContainedStats)
|
||||
return
|
||||
}
|
||||
|
||||
if parsed.HasFileProtocol() && !store.config.ExecutorOptions.Options.EnableFileTemplates {
|
||||
stats.Increment(templates.ExcludedFileStats)
|
||||
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 {
|
||||
// Skip DAST filter when loading auth templates
|
||||
if store.ID() != AuthStoreId && store.config.ExecutorOptions.Options.DAST {
|
||||
// check if the template is a DAST template
|
||||
if parsed.IsFuzzing() {
|
||||
loadTemplate(parsed)
|
||||
|
||||
@@ -27,7 +27,7 @@ func (e *Engine) executeAllSelfContained(ctx context.Context, alltemplates []*te
|
||||
var match bool
|
||||
ctx := scan.NewScanContext(ctx, contextargs.New(ctx))
|
||||
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)
|
||||
}
|
||||
@@ -107,7 +107,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(e.executerOpts.ProtocolType.String(), contextargs.NewWithMetaInput(ctx, scannedValue)) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ func (e *Engine) executeTemplateWithTargets(ctx context.Context, template *templ
|
||||
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)
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*t
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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(w.Options.ProtocolType.String(), ctx.Input, err)
|
||||
}
|
||||
if len(template.Executers) == 1 {
|
||||
mainErr = err
|
||||
@@ -139,7 +139,8 @@ 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)
|
||||
// clone the Input so that other parallel executions won't overwrite the shared variables when subsequent templates are running
|
||||
subCtx := scan.NewScanContext(ctx.Context(), ctx.Input.Clone())
|
||||
if err := e.runWorkflowStep(subtemplate, subCtx, results, swg, w); err != nil {
|
||||
gologger.Warning().Msgf(workflowStepExecutionError, subtemplate.Template, err)
|
||||
}
|
||||
|
||||
+31
-5
@@ -137,33 +137,59 @@ getRepo:
|
||||
|
||||
// download the git repo to a given path
|
||||
func (ctr *customTemplateGitHubRepo) cloneRepo(clonePath, githubToken string) error {
|
||||
r, err := git.PlainClone(clonePath, false, &git.CloneOptions{
|
||||
URL: ctr.gitCloneURL,
|
||||
Auth: getAuth(ctr.owner, githubToken),
|
||||
})
|
||||
cloneOpts := &git.CloneOptions{
|
||||
URL: ctr.gitCloneURL,
|
||||
Auth: getAuth(ctr.owner, githubToken),
|
||||
SingleBranch: true,
|
||||
Depth: 1,
|
||||
}
|
||||
|
||||
err := cloneOpts.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := git.PlainClone(clonePath, false, cloneOpts)
|
||||
if err != nil {
|
||||
return errors.Errorf("%s/%s: %s", ctr.owner, ctr.reponame, err.Error())
|
||||
}
|
||||
|
||||
// Add the user as well in the config. By default, user is not set
|
||||
config, _ := r.Storer.Config()
|
||||
config.User.Name = ctr.owner
|
||||
|
||||
return r.SetConfig(config)
|
||||
}
|
||||
|
||||
// performs the git pull on given repo
|
||||
func (ctr *customTemplateGitHubRepo) pullChanges(repoPath, githubToken string) error {
|
||||
pullOpts := &git.PullOptions{
|
||||
RemoteName: "origin",
|
||||
Auth: getAuth(ctr.owner, githubToken),
|
||||
SingleBranch: true,
|
||||
Depth: 1,
|
||||
}
|
||||
|
||||
err := pullOpts.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := git.PlainOpen(repoPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w, err := r.Worktree()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = w.Pull(&git.PullOptions{RemoteName: "origin", Auth: getAuth(ctr.owner, githubToken)})
|
||||
|
||||
err = w.Pull(pullOpts)
|
||||
if err != nil {
|
||||
return errors.Errorf("%s/%s: %s", ctr.owner, ctr.reponame, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -22,14 +22,12 @@ func TestDownloadCustomTemplatesFromGitHub(t *testing.T) {
|
||||
config.DefaultConfig.SetTemplatesDir(templatesDirectory)
|
||||
|
||||
options := testutils.DefaultOptions
|
||||
options.GitHubTemplateRepo = []string{"projectdiscovery/nuclei-templates", "ehsandeep/nuclei-templates"}
|
||||
options.GitHubToken = os.Getenv("GITHUB_TOKEN")
|
||||
options.GitHubTemplateRepo = []string{"projectdiscovery/nuclei-templates-test"}
|
||||
|
||||
ctm, err := NewCustomTemplatesManager(options)
|
||||
require.Nil(t, err, "could not create custom templates manager")
|
||||
|
||||
ctm.Download(context.Background())
|
||||
|
||||
require.DirExists(t, filepath.Join(templatesDirectory, "github", "projectdiscovery", "nuclei-templates"), "cloned directory does not exists")
|
||||
require.DirExists(t, filepath.Join(templatesDirectory, "github", "ehsandeep", "nuclei-templates"), "cloned directory does not exists")
|
||||
require.DirExists(t, filepath.Join(templatesDirectory, "github", "projectdiscovery", "nuclei-templates-test"), "cloned directory does not exists")
|
||||
}
|
||||
+3
-3
@@ -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.String(project.DefaultBranch),
|
||||
Recursive: gitlab.Bool(true),
|
||||
Ref: gitlab.Ptr(project.DefaultBranch),
|
||||
Recursive: gitlab.Ptr(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.String(project.DefaultBranch),
|
||||
Ref: gitlab.Ptr(project.DefaultBranch),
|
||||
}
|
||||
f, _, err := bk.gitLabClient.RepositoryFiles.GetFile(projectID, file.Path, gf)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package analyzers
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"
|
||||
"github.com/projectdiscovery/retryablehttp-go"
|
||||
)
|
||||
|
||||
// Analyzer is an interface for all the analyzers
|
||||
// that can be used for the fuzzer
|
||||
type Analyzer interface {
|
||||
// Name returns the name of the analyzer
|
||||
Name() string
|
||||
// ApplyTransformation applies the transformation to the initial payload.
|
||||
ApplyInitialTransformation(data string, params map[string]interface{}) string
|
||||
// Analyze is the main function for the analyzer
|
||||
Analyze(options *Options) (bool, string, error)
|
||||
}
|
||||
|
||||
// AnalyzerTemplate is the template for the analyzer
|
||||
type AnalyzerTemplate struct {
|
||||
// description: |
|
||||
// Name is the name of the analyzer to use
|
||||
// values:
|
||||
// - time_delay
|
||||
Name string `json:"name" yaml:"name"`
|
||||
// description: |
|
||||
// Parameters is the parameters for the analyzer
|
||||
//
|
||||
// Parameters are different for each analyzer. For example, you can customize
|
||||
// time_delay analyzer with sleep_duration, time_slope_error_range, etc. Refer
|
||||
// to the docs for each analyzer to get an idea about parameters.
|
||||
Parameters map[string]interface{} `json:"parameters" yaml:"parameters"`
|
||||
}
|
||||
|
||||
var (
|
||||
analyzers map[string]Analyzer
|
||||
)
|
||||
|
||||
// RegisterAnalyzer registers a new analyzer
|
||||
func RegisterAnalyzer(name string, analyzer Analyzer) {
|
||||
analyzers[name] = analyzer
|
||||
}
|
||||
|
||||
// GetAnalyzer returns the analyzer for a given name
|
||||
func GetAnalyzer(name string) Analyzer {
|
||||
return analyzers[name]
|
||||
}
|
||||
|
||||
func init() {
|
||||
analyzers = make(map[string]Analyzer)
|
||||
}
|
||||
|
||||
// Options contains the options for the analyzer
|
||||
type Options struct {
|
||||
FuzzGenerated fuzz.GeneratedRequest
|
||||
HttpClient *retryablehttp.Client
|
||||
ResponseTimeDelay time.Duration
|
||||
AnalyzerParameters map[string]interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
)
|
||||
|
||||
// ApplyPayloadTransformations applies the payload transformations to the payload
|
||||
// It supports the below payloads -
|
||||
// - [RANDNUM] => random number between 1000 and 9999
|
||||
// - [RANDSTR] => random string of 4 characters
|
||||
func ApplyPayloadTransformations(value string) string {
|
||||
randomInt := GetRandomInteger()
|
||||
randomStr := randStringBytesMask(4)
|
||||
|
||||
value = strings.ReplaceAll(value, "[RANDNUM]", strconv.Itoa(randomInt))
|
||||
value = strings.ReplaceAll(value, "[RANDSTR]", randomStr)
|
||||
return value
|
||||
}
|
||||
|
||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const (
|
||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||
)
|
||||
|
||||
func randStringBytesMask(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := 0; i < n; {
|
||||
if idx := int(random.Int63() & letterIdxMask); idx < len(letterBytes) {
|
||||
b[i] = letterBytes[idx]
|
||||
i++
|
||||
}
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// GetRandomInteger returns a random integer between 1000 and 9999
|
||||
func GetRandomInteger() int {
|
||||
return random.Intn(9000) + 1000
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package time
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http/httptrace"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers"
|
||||
"github.com/projectdiscovery/retryablehttp-go"
|
||||
)
|
||||
|
||||
// Analyzer is a time delay analyzer for the fuzzer
|
||||
type Analyzer struct{}
|
||||
|
||||
const (
|
||||
DefaultSleepDuration = int(5)
|
||||
DefaultRequestsLimit = int(4)
|
||||
DefaultTimeCorrelationErrorRange = float64(0.15)
|
||||
DefaultTimeSlopeErrorRange = float64(0.30)
|
||||
|
||||
defaultSleepTimeDuration = 5 * time.Second
|
||||
)
|
||||
|
||||
var _ analyzers.Analyzer = &Analyzer{}
|
||||
|
||||
func init() {
|
||||
analyzers.RegisterAnalyzer("time_delay", &Analyzer{})
|
||||
}
|
||||
|
||||
// Name is the name of the analyzer
|
||||
func (a *Analyzer) Name() string {
|
||||
return "time_delay"
|
||||
}
|
||||
|
||||
// ApplyInitialTransformation applies the transformation to the initial payload.
|
||||
//
|
||||
// It supports the below payloads -
|
||||
// - [SLEEPTIME] => sleep_duration
|
||||
// - [INFERENCE] => Inference payload for time delay analyzer
|
||||
//
|
||||
// It also applies the payload transformations to the payload
|
||||
// which includes [RANDNUM] and [RANDSTR]
|
||||
func (a *Analyzer) ApplyInitialTransformation(data string, params map[string]interface{}) string {
|
||||
duration := DefaultSleepDuration
|
||||
if len(params) > 0 {
|
||||
if v, ok := params["sleep_duration"]; ok {
|
||||
duration, ok = v.(int)
|
||||
if !ok {
|
||||
duration = DefaultSleepDuration
|
||||
gologger.Warning().Msgf("Invalid sleep_duration parameter type, using default value: %d", duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
data = strings.ReplaceAll(data, "[SLEEPTIME]", strconv.Itoa(duration))
|
||||
data = analyzers.ApplyPayloadTransformations(data)
|
||||
|
||||
// Also support [INFERENCE] for the time delay analyzer
|
||||
if strings.Contains(data, "[INFERENCE]") {
|
||||
randInt := analyzers.GetRandomInteger()
|
||||
data = strings.ReplaceAll(data, "[INFERENCE]", fmt.Sprintf("%d=%d", randInt, randInt))
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (a *Analyzer) parseAnalyzerParameters(params map[string]interface{}) (int, int, float64, float64, error) {
|
||||
requestsLimit := DefaultRequestsLimit
|
||||
sleepDuration := DefaultSleepDuration
|
||||
timeCorrelationErrorRange := DefaultTimeCorrelationErrorRange
|
||||
timeSlopeErrorRange := DefaultTimeSlopeErrorRange
|
||||
|
||||
if len(params) == 0 {
|
||||
return requestsLimit, sleepDuration, timeCorrelationErrorRange, timeSlopeErrorRange, nil
|
||||
}
|
||||
var ok bool
|
||||
for k, v := range params {
|
||||
switch k {
|
||||
case "sleep_duration":
|
||||
sleepDuration, ok = v.(int)
|
||||
case "requests_limit":
|
||||
requestsLimit, ok = v.(int)
|
||||
case "time_correlation_error_range":
|
||||
timeCorrelationErrorRange, ok = v.(float64)
|
||||
case "time_slope_error_range":
|
||||
timeSlopeErrorRange, ok = v.(float64)
|
||||
}
|
||||
if !ok {
|
||||
return 0, 0, 0, 0, errors.Errorf("invalid parameter type for %s", k)
|
||||
}
|
||||
}
|
||||
return requestsLimit, sleepDuration, timeCorrelationErrorRange, timeSlopeErrorRange, nil
|
||||
}
|
||||
|
||||
// Analyze is the main function for the analyzer
|
||||
func (a *Analyzer) Analyze(options *analyzers.Options) (bool, string, error) {
|
||||
if options.ResponseTimeDelay < defaultSleepTimeDuration {
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
// Parse parameters for this analyzer if any or use default values
|
||||
requestsLimit, sleepDuration, timeCorrelationErrorRange, timeSlopeErrorRange, err :=
|
||||
a.parseAnalyzerParameters(options.AnalyzerParameters)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
|
||||
reqSender := func(delay int) (float64, error) {
|
||||
gr := options.FuzzGenerated
|
||||
replaced := strings.ReplaceAll(gr.OriginalPayload, "[SLEEPTIME]", strconv.Itoa(delay))
|
||||
replaced = a.ApplyInitialTransformation(replaced, options.AnalyzerParameters)
|
||||
|
||||
if err := gr.Component.SetValue(gr.Key, replaced); err != nil {
|
||||
return 0, errors.Wrap(err, "could not set value in component")
|
||||
}
|
||||
|
||||
rebuilt, err := gr.Component.Rebuild()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not rebuild request")
|
||||
}
|
||||
gologger.Verbose().Msgf("[%s] Sending request with %d delay for: %s", a.Name(), delay, rebuilt.URL.String())
|
||||
|
||||
timeTaken, err := doHTTPRequestWithTimeTracing(rebuilt, options.HttpClient)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not do request with time tracing")
|
||||
}
|
||||
return timeTaken, nil
|
||||
}
|
||||
matched, matchReason, err := checkTimingDependency(
|
||||
requestsLimit,
|
||||
sleepDuration,
|
||||
timeCorrelationErrorRange,
|
||||
timeSlopeErrorRange,
|
||||
reqSender,
|
||||
)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if matched {
|
||||
return true, matchReason, nil
|
||||
}
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
// doHTTPRequestWithTimeTracing does a http request with time tracing
|
||||
func doHTTPRequestWithTimeTracing(req *retryablehttp.Request, httpclient *retryablehttp.Client) (float64, error) {
|
||||
var ttfb time.Duration
|
||||
var start time.Time
|
||||
|
||||
trace := &httptrace.ClientTrace{
|
||||
GotFirstResponseByte: func() { ttfb = time.Since(start) },
|
||||
}
|
||||
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
|
||||
start = time.Now()
|
||||
resp, err := httpclient.Do(req)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not do request")
|
||||
}
|
||||
|
||||
_, err = io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not read response body")
|
||||
}
|
||||
return ttfb.Seconds(), nil
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
// Package time implements a time delay analyzer using linear
|
||||
// regression heuristics inspired from ZAP to discover time
|
||||
// based issues.
|
||||
//
|
||||
// The approach is the one used in ZAP for timing based checks.
|
||||
// Advantages of this approach are many compared to the old approach of
|
||||
// heuristics of sleep time.
|
||||
//
|
||||
// As we are building a statistical model, we can predict if the delay
|
||||
// is random or not very quickly. Also, the payloads are alternated to send
|
||||
// a very high sleep and a very low sleep. This way the comparison is
|
||||
// faster to eliminate negative cases. Only legitimate cases are sent for
|
||||
// more verification.
|
||||
//
|
||||
// For more details on the algorithm, follow the links below:
|
||||
// - https://groups.google.com/g/zaproxy-develop/c/KGSkNHlLtqk
|
||||
// - https://github.com/zaproxy/zap-extensions/pull/5053
|
||||
//
|
||||
// This file has been implemented from its original version. It was originally licensed under the Apache License 2.0 (see LICENSE file for details).
|
||||
// The original algorithm is implemented in ZAP Active Scanner.
|
||||
package time
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
type timeDelayRequestSender func(delay int) (float64, error)
|
||||
|
||||
// checkTimingDependency checks the timing dependency for a given request
|
||||
//
|
||||
// It alternates and sends first a high request, then a low request. Each time
|
||||
// it checks if the delay of the application can be predictably controlled.
|
||||
func checkTimingDependency(
|
||||
requestsLimit int,
|
||||
highSleepTimeSeconds int,
|
||||
correlationErrorRange float64,
|
||||
slopeErrorRange float64,
|
||||
requestSender timeDelayRequestSender,
|
||||
) (bool, string, error) {
|
||||
if requestsLimit < 2 {
|
||||
return false, "", errors.New("requests limit should be at least 2")
|
||||
}
|
||||
|
||||
regression := newSimpleLinearRegression()
|
||||
requestsLeft := requestsLimit
|
||||
|
||||
for {
|
||||
if requestsLeft <= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
isCorrelationPossible, err := sendRequestAndTestConfidence(regression, highSleepTimeSeconds, requestSender)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if !isCorrelationPossible {
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
isCorrelationPossible, err = sendRequestAndTestConfidence(regression, 1, requestSender)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if !isCorrelationPossible {
|
||||
return false, "", nil
|
||||
}
|
||||
requestsLeft = requestsLeft - 2
|
||||
}
|
||||
|
||||
result := regression.IsWithinConfidence(correlationErrorRange, 1.0, slopeErrorRange)
|
||||
if result {
|
||||
resultReason := fmt.Sprintf(
|
||||
"[time_delay] made %d requests successfully, with a regression slope of %.2f and correlation %.2f",
|
||||
requestsLimit,
|
||||
regression.slope,
|
||||
regression.correlation,
|
||||
)
|
||||
return result, resultReason, nil
|
||||
}
|
||||
return result, "", nil
|
||||
}
|
||||
|
||||
// sendRequestAndTestConfidence sends a request and tests the confidence of delay
|
||||
func sendRequestAndTestConfidence(
|
||||
regression *simpleLinearRegression,
|
||||
delay int,
|
||||
requestSender timeDelayRequestSender,
|
||||
) (bool, error) {
|
||||
delayReceived, err := requestSender(delay)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if delayReceived < float64(delay) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
regression.AddPoint(float64(delay), delayReceived)
|
||||
|
||||
if !regression.IsWithinConfidence(0.3, 1.0, 0.5) {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// simpleLinearRegression is a simple linear regression model that can be updated at runtime.
|
||||
// It is based on the same algorithm in ZAP for doing timing checks.
|
||||
type simpleLinearRegression struct {
|
||||
count float64
|
||||
independentSum float64
|
||||
dependentSum float64
|
||||
|
||||
// Variances
|
||||
independentVarianceN float64
|
||||
dependentVarianceN float64
|
||||
sampleCovarianceN float64
|
||||
|
||||
slope float64
|
||||
intercept float64
|
||||
correlation float64
|
||||
}
|
||||
|
||||
func newSimpleLinearRegression() *simpleLinearRegression {
|
||||
return &simpleLinearRegression{
|
||||
slope: 1,
|
||||
correlation: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *simpleLinearRegression) AddPoint(x, y float64) {
|
||||
independentResidualAdjustment := x - o.independentSum/o.count
|
||||
dependentResidualAdjustment := y - o.dependentSum/o.count
|
||||
|
||||
o.count += 1
|
||||
o.independentSum += x
|
||||
o.dependentSum += y
|
||||
|
||||
if math.IsNaN(independentResidualAdjustment) {
|
||||
return
|
||||
}
|
||||
|
||||
independentResidual := x - o.independentSum/o.count
|
||||
dependentResidual := y - o.dependentSum/o.count
|
||||
|
||||
o.independentVarianceN += independentResidual * independentResidualAdjustment
|
||||
o.dependentVarianceN += dependentResidual * dependentResidualAdjustment
|
||||
o.sampleCovarianceN += independentResidual * dependentResidualAdjustment
|
||||
|
||||
o.slope = o.sampleCovarianceN / o.independentVarianceN
|
||||
o.correlation = o.slope * math.Sqrt(o.independentVarianceN/o.dependentVarianceN)
|
||||
o.correlation *= o.correlation
|
||||
|
||||
// NOTE: zap had the reverse formula, changed it to the correct one
|
||||
// for intercept. Verify if this is correct.
|
||||
o.intercept = o.dependentSum/o.count - o.slope*(o.independentSum/o.count)
|
||||
if math.IsNaN(o.correlation) {
|
||||
o.correlation = 1
|
||||
}
|
||||
}
|
||||
|
||||
func (o *simpleLinearRegression) Predict(x float64) float64 {
|
||||
return o.slope*x + o.intercept
|
||||
}
|
||||
|
||||
func (o *simpleLinearRegression) IsWithinConfidence(correlationErrorRange float64, expectedSlope float64, slopeErrorRange float64,
|
||||
) bool {
|
||||
return o.correlation > 1.0-correlationErrorRange
|
||||
//math.Abs(expectedSlope-o.slope) < slopeErrorRange
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// Tests ported from ZAP Java version of the algorithm
|
||||
|
||||
package time
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
correlationErrorRange = float64(0.1)
|
||||
slopeErrorRange = float64(0.2)
|
||||
)
|
||||
|
||||
var rng = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
func Test_should_generate_alternating_sequences(t *testing.T) {
|
||||
var generatedDelays []float64
|
||||
reqSender := func(delay int) (float64, error) {
|
||||
generatedDelays = append(generatedDelays, float64(delay))
|
||||
return float64(delay), nil
|
||||
}
|
||||
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
|
||||
require.NoError(t, err)
|
||||
require.True(t, matched)
|
||||
require.EqualValues(t, []float64{15, 1, 15, 1}, generatedDelays)
|
||||
}
|
||||
|
||||
func Test_should_giveup_non_injectable(t *testing.T) {
|
||||
var timesCalled int
|
||||
reqSender := func(delay int) (float64, error) {
|
||||
timesCalled++
|
||||
return 0.5, nil
|
||||
}
|
||||
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
|
||||
require.NoError(t, err)
|
||||
require.False(t, matched)
|
||||
require.Equal(t, 1, timesCalled)
|
||||
}
|
||||
|
||||
func Test_should_giveup_slow_non_injectable(t *testing.T) {
|
||||
var timesCalled int
|
||||
reqSender := func(delay int) (float64, error) {
|
||||
timesCalled++
|
||||
return 10 + rng.Float64()*0.5, nil
|
||||
}
|
||||
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
|
||||
require.NoError(t, err)
|
||||
require.False(t, matched)
|
||||
require.LessOrEqual(t, timesCalled, 3)
|
||||
}
|
||||
|
||||
func Test_should_giveup_slow_non_injectable_realworld(t *testing.T) {
|
||||
var timesCalled int
|
||||
var iteration = 0
|
||||
counts := []float64{21, 11, 21, 11}
|
||||
reqSender := func(delay int) (float64, error) {
|
||||
timesCalled++
|
||||
iteration++
|
||||
return counts[iteration-1], nil
|
||||
}
|
||||
matched, _, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
|
||||
require.NoError(t, err)
|
||||
require.False(t, matched)
|
||||
require.LessOrEqual(t, timesCalled, 4)
|
||||
}
|
||||
|
||||
func Test_should_detect_dependence_with_small_error(t *testing.T) {
|
||||
reqSender := func(delay int) (float64, error) {
|
||||
return float64(delay) + rng.Float64()*0.5, nil
|
||||
}
|
||||
matched, reason, err := checkTimingDependency(4, 15, correlationErrorRange, slopeErrorRange, reqSender)
|
||||
require.NoError(t, err)
|
||||
require.True(t, matched)
|
||||
require.NotEmpty(t, reason)
|
||||
}
|
||||
|
||||
func Test_LinearRegression_Numerical_stability(t *testing.T) {
|
||||
variables := [][]float64{
|
||||
{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {1, 1}, {2, 2}, {2, 2}, {2, 2},
|
||||
}
|
||||
slope := float64(1)
|
||||
correlation := float64(1)
|
||||
|
||||
regression := newSimpleLinearRegression()
|
||||
for _, v := range variables {
|
||||
regression.AddPoint(v[0], v[1])
|
||||
}
|
||||
require.True(t, almostEqual(regression.slope, slope))
|
||||
require.True(t, almostEqual(regression.correlation, correlation))
|
||||
}
|
||||
|
||||
func Test_LinearRegression_exact_verify(t *testing.T) {
|
||||
variables := [][]float64{
|
||||
{1, 1}, {2, 3},
|
||||
}
|
||||
slope := float64(2)
|
||||
correlation := float64(1)
|
||||
|
||||
regression := newSimpleLinearRegression()
|
||||
for _, v := range variables {
|
||||
regression.AddPoint(v[0], v[1])
|
||||
}
|
||||
require.True(t, almostEqual(regression.slope, slope))
|
||||
require.True(t, almostEqual(regression.correlation, correlation))
|
||||
}
|
||||
|
||||
func Test_LinearRegression_known_verify(t *testing.T) {
|
||||
variables := [][]float64{
|
||||
{1, 1.348520581}, {2, 2.524046187}, {3, 3.276944688}, {4, 4.735374498}, {5, 5.150291657},
|
||||
}
|
||||
slope := float64(0.981487046)
|
||||
correlation := float64(0.979228906)
|
||||
|
||||
regression := newSimpleLinearRegression()
|
||||
for _, v := range variables {
|
||||
regression.AddPoint(v[0], v[1])
|
||||
}
|
||||
require.True(t, almostEqual(regression.slope, slope))
|
||||
require.True(t, almostEqual(regression.correlation, correlation))
|
||||
}
|
||||
|
||||
func Test_LinearRegression_nonlinear_verify(t *testing.T) {
|
||||
variables := [][]float64{
|
||||
{1, 2}, {2, 4}, {3, 8}, {4, 16}, {5, 32},
|
||||
}
|
||||
|
||||
regression := newSimpleLinearRegression()
|
||||
for _, v := range variables {
|
||||
regression.AddPoint(v[0], v[1])
|
||||
}
|
||||
require.Less(t, regression.correlation, 0.9)
|
||||
}
|
||||
|
||||
const float64EqualityThreshold = 1e-8
|
||||
|
||||
func almostEqual(a, b float64) bool {
|
||||
return math.Abs(a-b) <= float64EqualityThreshold
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/dataformat"
|
||||
"github.com/projectdiscovery/retryablehttp-go"
|
||||
mapsutil "github.com/projectdiscovery/utils/maps"
|
||||
urlutil "github.com/projectdiscovery/utils/url"
|
||||
)
|
||||
|
||||
@@ -81,7 +82,7 @@ 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{})
|
||||
originalValues := mapsutil.Map[string, any]{}
|
||||
splitted := strings.Split(q.req.URL.Path, "/")
|
||||
for i := range splitted {
|
||||
pathTillNow := strings.Join(splitted[:i+1], "/")
|
||||
@@ -95,8 +96,22 @@ func (q *Path) Rebuild() (*retryablehttp.Request, error) {
|
||||
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)
|
||||
|
||||
original, ok := originalValues.GetOrDefault(key, "").(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
new, ok := q.value.parsed.Map.GetOrDefault(key, "").(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if new == original {
|
||||
// no need to replace
|
||||
continue
|
||||
}
|
||||
|
||||
originalPath = strings.Replace(originalPath, original, new, 1)
|
||||
}
|
||||
|
||||
|
||||
@@ -73,12 +73,22 @@ func (v *Value) SetParsed(data dataformat.KV, dataFormat string) {
|
||||
|
||||
// SetParsedValue sets the parsed value for a key
|
||||
// in the parsed map
|
||||
func (v *Value) SetParsedValue(key string, value string) bool {
|
||||
func (v *Value) SetParsedValue(key, value string) bool {
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
origValue := v.parsed.Get(key)
|
||||
if origValue == nil {
|
||||
v.parsed.Set(key, value)
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO(dwisiswant0): I'm sure that this can be simplified because
|
||||
// `dataformat.KV.*` is a type of `mapsutil.*` where the value is `any`. So,
|
||||
// it looks like we won't type conversion here or even have its own methods
|
||||
// inside `dataformat.KV`.
|
||||
|
||||
// If the value is a list, append to it
|
||||
// otherwise replace it
|
||||
switch v := origValue.(type) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
// if it's not important/significant (ex: json,xml) we use map
|
||||
// this also allows us to iteratively implement ordered map
|
||||
type KV struct {
|
||||
Map map[string]interface{}
|
||||
Map mapsutil.Map[string, any]
|
||||
OrderedMap *mapsutil.OrderedMap[string, any]
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,19 @@ import (
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net/textproto"
|
||||
|
||||
mapsutil "github.com/projectdiscovery/utils/maps"
|
||||
)
|
||||
|
||||
type MultiPartForm struct {
|
||||
boundary string
|
||||
boundary string
|
||||
filesMetadata map[string]FileMetadata
|
||||
}
|
||||
|
||||
type FileMetadata struct {
|
||||
ContentType string
|
||||
Filename string
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -41,11 +48,40 @@ func (m *MultiPartForm) Encode(data KV) (string, error) {
|
||||
data.Iterate(func(key string, value any) bool {
|
||||
var fw io.Writer
|
||||
var err error
|
||||
|
||||
if filesArray, ok := value.([]interface{}); ok {
|
||||
fileMetadata, ok := m.filesMetadata[key]
|
||||
if !ok {
|
||||
Itererr = fmt.Errorf("file metadata not found for key %s", key)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, file := range filesArray {
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition",
|
||||
fmt.Sprintf(`form-data; name=%q; filename=%q`,
|
||||
key, fileMetadata.Filename))
|
||||
h.Set("Content-Type", fileMetadata.ContentType)
|
||||
|
||||
if fw, err = w.CreatePart(h); err != nil {
|
||||
Itererr = err
|
||||
return false
|
||||
}
|
||||
|
||||
if _, err = fw.Write([]byte(file.(string))); err != nil {
|
||||
Itererr = err
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Add field
|
||||
if fw, err = w.CreateFormField(key); err != nil {
|
||||
Itererr = err
|
||||
return false
|
||||
}
|
||||
|
||||
if _, err = fw.Write([]byte(value.(string))); err != nil {
|
||||
Itererr = err
|
||||
return false
|
||||
@@ -98,6 +134,7 @@ func (m *MultiPartForm) Decode(data string) (KV, error) {
|
||||
result.Set(key, values[0])
|
||||
}
|
||||
}
|
||||
m.filesMetadata = make(map[string]FileMetadata)
|
||||
for key, files := range form.File {
|
||||
fileContents := []interface{}{}
|
||||
for _, fileHeader := range files {
|
||||
@@ -112,6 +149,11 @@ func (m *MultiPartForm) Decode(data string) (KV, error) {
|
||||
return KV{}, err
|
||||
}
|
||||
fileContents = append(fileContents, buffer.String())
|
||||
|
||||
m.filesMetadata[key] = FileMetadata{
|
||||
ContentType: fileHeader.Header.Get("Content-Type"),
|
||||
Filename: fileHeader.Filename,
|
||||
}
|
||||
}
|
||||
result.Set(key, fileContents)
|
||||
}
|
||||
|
||||
+35
-5
@@ -16,6 +16,7 @@ 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"
|
||||
)
|
||||
@@ -49,6 +50,11 @@ type ExecuteRuleInput struct {
|
||||
BaseRequest *retryablehttp.Request
|
||||
// DisplayFuzzPoints is a flag to display fuzz points
|
||||
DisplayFuzzPoints bool
|
||||
|
||||
// ApplyPayloadInitialTransformation is an optional function
|
||||
// to transform the payload initially based on analyzer rules
|
||||
ApplyPayloadInitialTransformation func(string, map[string]interface{}) string
|
||||
AnalyzerParams map[string]interface{}
|
||||
}
|
||||
|
||||
// GeneratedRequest is a single generated request for rule
|
||||
@@ -63,6 +69,15 @@ type GeneratedRequest struct {
|
||||
Component component.Component
|
||||
// Parameter being fuzzed
|
||||
Parameter string
|
||||
|
||||
// Key is the key for the request
|
||||
Key string
|
||||
// Value is the value for the request
|
||||
Value string
|
||||
// OriginalValue is the original value for the request
|
||||
OriginalValue string
|
||||
// OriginalPayload is the original payload for the request
|
||||
OriginalPayload string
|
||||
}
|
||||
|
||||
// Execute executes a fuzzing rule accepting a callback on which
|
||||
@@ -165,14 +180,27 @@ 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(fmt.Sprint(v), interactshUrls)
|
||||
|
||||
got, oastUrls := rule.options.Interactsh.Replace(value, interactshUrls)
|
||||
if got != value {
|
||||
data[k] = got
|
||||
}
|
||||
// Append new OAST URLs if any
|
||||
if len(oastUrls) > 0 {
|
||||
interactshUrls = append(interactshUrls, oastUrls...)
|
||||
for _, url := range oastUrls {
|
||||
if _, ok := interactshUrlsMap[url]; !ok {
|
||||
interactshUrlsMap[url] = struct{}{}
|
||||
interactshUrls = append(interactshUrls, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Evaluate the replaced data
|
||||
evaluatedData, err := expressions.Evaluate(got, data)
|
||||
@@ -202,7 +230,9 @@ func (rule *Rule) executeRuleValues(input *ExecuteRuleInput, ruleComponent compo
|
||||
// if we are only fuzzing values
|
||||
if len(rule.Fuzz.Value) > 0 {
|
||||
for _, value := range rule.Fuzz.Value {
|
||||
if err := rule.executePartRule(input, ValueOrKeyValue{Value: value}, ruleComponent); err != nil {
|
||||
originalPayload := value
|
||||
|
||||
if err := rule.executePartRule(input, ValueOrKeyValue{Value: value, OriginalPayload: originalPayload}, ruleComponent); err != nil {
|
||||
if component.IsErrSetValue(err) {
|
||||
// this are errors due to format restrictions
|
||||
// ex: fuzzing string value in a json int field
|
||||
@@ -243,7 +273,7 @@ func (rule *Rule) executeRuleValues(input *ExecuteRuleInput, ruleComponent compo
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if gotErr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", ""); gotErr != nil {
|
||||
if gotErr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", "", "", "", "", ""); gotErr != nil {
|
||||
return gotErr
|
||||
}
|
||||
}
|
||||
|
||||
+25
-15
@@ -42,14 +42,14 @@ func (rule *Rule) executePartComponent(input *ExecuteRuleInput, payload ValueOrK
|
||||
return rule.executePartComponentOnKV(input, payload, ruleComponent.Clone())
|
||||
} else {
|
||||
// for value only fuzzing
|
||||
return rule.executePartComponentOnValues(input, payload.Value, ruleComponent.Clone())
|
||||
return rule.executePartComponentOnValues(input, payload.Value, payload.OriginalPayload, ruleComponent.Clone())
|
||||
}
|
||||
}
|
||||
|
||||
// executePartComponentOnValues executes this rule on a given component and payload
|
||||
// this supports both single and multiple [ruleType] modes
|
||||
// i.e if component has multiple values, they can be replaced once or all depending on mode
|
||||
func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadStr string, ruleComponent component.Component) error {
|
||||
func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadStr, originalPayload string, ruleComponent component.Component) error {
|
||||
finalErr := ruleComponent.Iterate(func(key string, value interface{}) error {
|
||||
valueStr := types.ToString(value)
|
||||
if !rule.matchKeyOrValue(key, valueStr) {
|
||||
@@ -57,8 +57,13 @@ func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadS
|
||||
return nil
|
||||
}
|
||||
|
||||
var evaluated string
|
||||
var evaluated, originalEvaluated string
|
||||
evaluated, input.InteractURLs = rule.executeEvaluate(input, key, valueStr, payloadStr, input.InteractURLs)
|
||||
if input.ApplyPayloadInitialTransformation != nil {
|
||||
evaluated = input.ApplyPayloadInitialTransformation(evaluated, input.AnalyzerParams)
|
||||
originalEvaluated, _ = rule.executeEvaluate(input, key, valueStr, originalPayload, input.InteractURLs)
|
||||
}
|
||||
|
||||
if err := ruleComponent.SetValue(key, evaluated); err != nil {
|
||||
// gologger.Warning().Msgf("could not set value due to format restriction original(%s, %s[%T]) , new(%s,%s[%T])", key, valueStr, value, key, evaluated, evaluated)
|
||||
return nil
|
||||
@@ -70,7 +75,7 @@ func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadS
|
||||
return err
|
||||
}
|
||||
|
||||
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, valueStr); qerr != nil {
|
||||
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, valueStr, originalEvaluated, valueStr, key, evaluated); qerr != nil {
|
||||
return qerr
|
||||
}
|
||||
// fmt.Printf("executed with value: %s\n", evaluated)
|
||||
@@ -92,7 +97,7 @@ func (rule *Rule) executePartComponentOnValues(input *ExecuteRuleInput, payloadS
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", ""); qerr != nil {
|
||||
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, "", "", "", "", "", ""); qerr != nil {
|
||||
err = qerr
|
||||
return err
|
||||
}
|
||||
@@ -127,7 +132,7 @@ func (rule *Rule) executePartComponentOnKV(input *ExecuteRuleInput, payload Valu
|
||||
return err
|
||||
}
|
||||
|
||||
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, value); qerr != nil {
|
||||
if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, value, "", "", "", ""); qerr != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -146,12 +151,13 @@ func (rule *Rule) executePartComponentOnKV(input *ExecuteRuleInput, payload Valu
|
||||
}
|
||||
|
||||
// execWithInput executes a rule with input via callback
|
||||
func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.Request, interactURLs []string, component component.Component, parameter, parameterValue string) error {
|
||||
func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.Request, interactURLs []string, component component.Component, parameter, parameterValue, originalPayload, originalValue, key, value string) error {
|
||||
// If the parameter is a number, replace it with the parameter value
|
||||
// or if the parameter is empty and the parameter value is not empty
|
||||
// replace it with the parameter value
|
||||
actualParameter := parameter
|
||||
if _, err := strconv.Atoi(parameter); err == nil || (parameter == "" && parameterValue != "") {
|
||||
parameter = parameterValue
|
||||
actualParameter = parameterValue
|
||||
}
|
||||
// If the parameter is frequent, skip it if the option is enabled
|
||||
if rule.options.FuzzParamsFrequency != nil {
|
||||
@@ -164,11 +170,15 @@ func (rule *Rule) execWithInput(input *ExecuteRuleInput, httpReq *retryablehttp.
|
||||
}
|
||||
}
|
||||
request := GeneratedRequest{
|
||||
Request: httpReq,
|
||||
InteractURLs: interactURLs,
|
||||
DynamicValues: input.Values,
|
||||
Component: component,
|
||||
Parameter: parameter,
|
||||
Request: httpReq,
|
||||
InteractURLs: interactURLs,
|
||||
DynamicValues: input.Values,
|
||||
Component: component,
|
||||
Parameter: actualParameter,
|
||||
Key: key,
|
||||
Value: value,
|
||||
OriginalValue: originalValue,
|
||||
OriginalPayload: originalPayload,
|
||||
}
|
||||
if !input.Callback(request) {
|
||||
return types.ErrNoMoreRequests
|
||||
@@ -181,9 +191,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(input.Values, map[string]interface{}{
|
||||
values := generators.MergeMaps(rule.options.Variables.GetAll(), map[string]interface{}{
|
||||
"value": value,
|
||||
}, rule.options.Options.Vars.AsMap(), rule.options.Variables.GetAll())
|
||||
}, rule.options.Options.Vars.AsMap(), input.Values)
|
||||
firstpass, _ := expressions.Evaluate(payload, values)
|
||||
interactData, interactshURLs := rule.options.Interactsh.Replace(firstpass, interactshURLs)
|
||||
evaluated, _ := expressions.Evaluate(interactData, values)
|
||||
|
||||
@@ -19,6 +19,8 @@ var (
|
||||
type ValueOrKeyValue struct {
|
||||
Key string
|
||||
Value string
|
||||
|
||||
OriginalPayload string
|
||||
}
|
||||
|
||||
func (v *ValueOrKeyValue) IsKV() bool {
|
||||
|
||||
@@ -18,7 +18,7 @@ func getSchemaExample(schema *openapi3.Schema) (interface{}, bool) {
|
||||
return schema.Default, true
|
||||
}
|
||||
|
||||
if schema.Enum != nil && len(schema.Enum) > 0 {
|
||||
if 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 == "boolean":
|
||||
case schema.Type.Is("boolean"):
|
||||
return true, nil
|
||||
case schema.Type == "number", schema.Type == "integer":
|
||||
case schema.Type.Is("number"), schema.Type.Is("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 == "integer" {
|
||||
if schema.Type.Is("integer") {
|
||||
return int(value), nil
|
||||
}
|
||||
return value, nil
|
||||
case schema.Type == "string":
|
||||
case schema.Type.Is("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 == "array", schema.Items != nil:
|
||||
case schema.Type.Is("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 == "object", len(schema.Properties) > 0:
|
||||
case schema.Type.Is("object"), len(schema.Properties) > 0:
|
||||
example := map[string]interface{}{}
|
||||
|
||||
for k, v := range schema.Properties {
|
||||
|
||||
@@ -27,7 +27,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
globalAuth = "globalAuth"
|
||||
globalAuth = "globalAuth"
|
||||
DEFAULT_HTTP_SCHEME_HEADER = "Authorization"
|
||||
)
|
||||
|
||||
// GenerateRequestsFromSchema generates http requests from an OpenAPI 3.0 document object
|
||||
@@ -75,16 +76,26 @@ func GenerateRequestsFromSchema(schema *openapi3.T, opts formats.InputFormatOpti
|
||||
|
||||
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: pathURL,
|
||||
pathURL: baseURL,
|
||||
requestPath: requestPath,
|
||||
op: ov,
|
||||
schema: schema,
|
||||
@@ -193,7 +204,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 value.Schema.Value.Enum != nil && len(value.Schema.Value.Enum) > 0 {
|
||||
} else if len(value.Schema.Value.Enum) > 0 {
|
||||
paramValue = value.Schema.Value.Enum[0]
|
||||
} else {
|
||||
if !opts.opts.SkipFormatValidation {
|
||||
@@ -406,7 +417,7 @@ schemaLabel:
|
||||
return globalParams, nil
|
||||
}
|
||||
|
||||
// generateExampleFromSchema generates an example from a schema object
|
||||
// GenerateParameterFromSecurityScheme generates an example from a schema object
|
||||
func GenerateParameterFromSecurityScheme(scheme *openapi3.SecuritySchemeRef) (*openapi3.Parameter, error) {
|
||||
if !generic.EqualsAny(scheme.Value.Type, "http", "apiKey") {
|
||||
return nil, errorutil.NewWithTag("openapi", "unsupported security scheme type (%s) found in openapi file", scheme.Value.Type)
|
||||
@@ -416,18 +427,20 @@ func GenerateParameterFromSecurityScheme(scheme *openapi3.SecuritySchemeRef) (*o
|
||||
if !generic.EqualsAny(scheme.Value.Scheme, "basic", "bearer") {
|
||||
return nil, errorutil.NewWithTag("openapi", "unsupported security scheme (%s) found in openapi file", scheme.Value.Scheme)
|
||||
}
|
||||
if scheme.Value.Name == "" {
|
||||
return nil, errorutil.NewWithTag("openapi", "security scheme (%s) name is empty", scheme.Value.Scheme)
|
||||
// HTTP authentication schemes basic or bearer use the Authorization header
|
||||
headerName := scheme.Value.Name
|
||||
if headerName == "" {
|
||||
headerName = DEFAULT_HTTP_SCHEME_HEADER
|
||||
}
|
||||
// create parameters using the scheme
|
||||
switch scheme.Value.Scheme {
|
||||
case "basic":
|
||||
h := openapi3.NewHeaderParameter(scheme.Value.Name)
|
||||
h := openapi3.NewHeaderParameter(headerName)
|
||||
h.Required = true
|
||||
h.Description = globalAuth // differentiator for normal variables and global auth
|
||||
return h, nil
|
||||
case "bearer":
|
||||
h := openapi3.NewHeaderParameter(scheme.Value.Name)
|
||||
h := openapi3.NewHeaderParameter(headerName)
|
||||
h.Required = true
|
||||
h.Description = globalAuth // differentiator for normal variables and global auth
|
||||
return h, nil
|
||||
|
||||
@@ -2,6 +2,7 @@ package swagger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
@@ -10,7 +11,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats/openapi"
|
||||
"gopkg.in/yaml.v2"
|
||||
"github.com/invopop/yaml"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi2conv"
|
||||
)
|
||||
@@ -49,7 +50,11 @@ func (j *SwaggerFormat) Parse(input string, resultsCb formats.ParseReqRespCallba
|
||||
ext := path.Ext(input)
|
||||
|
||||
if ext == ".yaml" || ext == ".yml" {
|
||||
err = yaml.NewDecoder(file).Decode(schemav2)
|
||||
data, err_data := io.ReadAll(file)
|
||||
if err_data != nil {
|
||||
return errors.Wrap(err, "could not read data file")
|
||||
}
|
||||
err = yaml.Unmarshal(data, schemav2)
|
||||
} else {
|
||||
err = json.NewDecoder(file).Decode(schemav2)
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ func TestSwaggerAPIParser(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedURLs := []string{
|
||||
"https://localhost/users",
|
||||
"https://localhost/users/1?test=asc",
|
||||
"https://localhost/v1/users",
|
||||
"https://localhost/v1/users/1?test=asc",
|
||||
}
|
||||
require.ElementsMatch(t, gotMethodsToURLs, expectedURLs, "could not get swagger urls")
|
||||
}
|
||||
@@ -66,9 +66,10 @@ 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 {
|
||||
return callback(&contextargs.MetaInput{
|
||||
ReqResp: request,
|
||||
})
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.ReqResp = request
|
||||
metaInput.Input = request.URL.String()
|
||||
return callback(metaInput)
|
||||
})
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("Could not parse input file while iterating: %s\n", err)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"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 (
|
||||
@@ -32,7 +33,7 @@ func IsErrNotImplemented(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(err.Error(), "provider") && strings.Contains(err.Error(), "does not implement") {
|
||||
if stringsutil.ContainsAll(err.Error(), "provider", "does not implement") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -120,7 +121,7 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// SupportedFormats returns all supported input formats of nuclei
|
||||
// SupportedInputFormats returns all supported input formats of nuclei
|
||||
func SupportedInputFormats() string {
|
||||
return "list, " + http.SupportedFormats()
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func (i *ListInputProvider) Iterate(callback func(value *contextargs.MetaInput)
|
||||
})
|
||||
}
|
||||
callbackFunc := func(k, _ []byte) error {
|
||||
metaInput := &contextargs.MetaInput{}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
if err := metaInput.Unmarshal(string(k)); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -153,14 +153,16 @@ func (i *ListInputProvider) Set(value string) {
|
||||
}
|
||||
return fmt.Sprintf("got empty hostname for %v skipping ip selection", URL)
|
||||
})
|
||||
metaInput := &contextargs.MetaInput{Input: URL}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = URL
|
||||
i.setItem(metaInput)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if input is ip or hostname
|
||||
if iputil.IsIP(urlx.Hostname()) {
|
||||
metaInput := &contextargs.MetaInput{Input: URL}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = URL
|
||||
i.setItem(metaInput)
|
||||
return
|
||||
}
|
||||
@@ -181,7 +183,9 @@ func (i *ListInputProvider) Set(value string) {
|
||||
if ip == "" {
|
||||
continue
|
||||
}
|
||||
metaInput := &contextargs.MetaInput{Input: value, CustomIP: ip}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = value
|
||||
metaInput.CustomIP = ip
|
||||
i.setItem(metaInput)
|
||||
}
|
||||
return
|
||||
@@ -211,11 +215,13 @@ func (i *ListInputProvider) Set(value string) {
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
if ip != "" {
|
||||
metaInput := &contextargs.MetaInput{Input: URL, CustomIP: ip}
|
||||
metaInput.Input = URL
|
||||
metaInput.CustomIP = ip
|
||||
i.setItem(metaInput)
|
||||
} else {
|
||||
metaInput := &contextargs.MetaInput{Input: URL}
|
||||
metaInput.Input = URL
|
||||
i.setItem(metaInput)
|
||||
}
|
||||
}
|
||||
@@ -353,7 +359,8 @@ 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.MetaInput{Input: URL}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = URL
|
||||
key, err := metaInput.MarshalString()
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("%s\n", err)
|
||||
@@ -378,14 +385,16 @@ func (i *ListInputProvider) Del(value string) {
|
||||
}
|
||||
return fmt.Sprintf("got empty hostname for %v skipping ip selection", URL)
|
||||
})
|
||||
metaInput := &contextargs.MetaInput{Input: URL}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = URL
|
||||
i.delItem(metaInput)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if input is ip or hostname
|
||||
if iputil.IsIP(urlx.Hostname()) {
|
||||
metaInput := &contextargs.MetaInput{Input: URL}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = URL
|
||||
i.delItem(metaInput)
|
||||
return
|
||||
}
|
||||
@@ -406,7 +415,9 @@ func (i *ListInputProvider) Del(value string) {
|
||||
if ip == "" {
|
||||
continue
|
||||
}
|
||||
metaInput := &contextargs.MetaInput{Input: value, CustomIP: ip}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = value
|
||||
metaInput.CustomIP = ip
|
||||
i.delItem(metaInput)
|
||||
}
|
||||
return
|
||||
@@ -436,11 +447,13 @@ func (i *ListInputProvider) Del(value string) {
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
if ip != "" {
|
||||
metaInput := &contextargs.MetaInput{Input: URL, CustomIP: ip}
|
||||
metaInput.Input = URL
|
||||
metaInput.CustomIP = ip
|
||||
i.delItem(metaInput)
|
||||
} else {
|
||||
metaInput := &contextargs.MetaInput{Input: URL}
|
||||
metaInput.Input = URL
|
||||
i.delItem(metaInput)
|
||||
}
|
||||
}
|
||||
@@ -514,7 +527,8 @@ func (i *ListInputProvider) addTargets(targets []string) {
|
||||
|
||||
func (i *ListInputProvider) removeTargets(targets []string) {
|
||||
for _, target := range targets {
|
||||
metaInput := &contextargs.MetaInput{Input: target}
|
||||
metaInput := contextargs.NewMetaInput()
|
||||
metaInput.Input = target
|
||||
i.delItem(metaInput)
|
||||
}
|
||||
}
|
||||
Loaded 100 of 232 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user