mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2026-11-10 17:37:57 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe6b1e4671 | ||
|
|
60a723ffab | ||
|
|
e4d17bff67 | ||
|
|
bf7a9aa708 | ||
|
|
fb5a34de57 | ||
|
|
010bab5aaf | ||
|
|
ddb62ee3ff | ||
|
|
97fd1f7ab3 | ||
|
|
793db8a614 | ||
|
|
1c0689ad7e | ||
|
|
1d11a8e40c | ||
|
|
95f330d7e8 | ||
|
|
6ea16bab61 | ||
|
|
bae7e2810f | ||
|
|
cedb1f45f7 | ||
|
|
9498692046 | ||
|
|
63fff7c294 | ||
|
|
af9472fb07 | ||
|
|
35e91a771d | ||
|
|
94d8c1d8e8 | ||
|
|
981e777b58 | ||
|
|
ed600871ae | ||
|
|
685c91adbd | ||
|
|
9d811dd7ba | ||
|
|
33cec3e506 | ||
|
|
4050ac3a9f | ||
|
|
cf68e6ec6b | ||
|
|
d7d896b75a | ||
|
|
7d83d3f8c9 | ||
|
|
ab1da1aa8e | ||
|
|
0732406a68 | ||
|
|
73dec71628 | ||
|
|
ece56ea39d | ||
|
|
26a1f86b93 | ||
|
|
8fd97dd7ed | ||
|
|
dfdb780c6f | ||
|
|
0536645704 | ||
|
|
72af50155d | ||
|
|
d877f62f8d | ||
|
|
de170f9c91 | ||
|
|
938928ad9f | ||
|
|
e77105b402 | ||
|
|
e383449fb3 | ||
|
|
26de1c0995 | ||
|
|
2d1c96a338 | ||
|
|
149edf12d5 | ||
|
|
7c8137cfff | ||
|
|
845bae5c32 | ||
|
|
145faeef8d | ||
|
|
a06e1c59ab | ||
|
|
a48e2adb69 | ||
|
|
fa6b21e9be | ||
|
|
8694af971e | ||
|
|
76fe8b682c | ||
|
|
54d8f9fdb5 | ||
|
|
993b5e7e77 | ||
|
|
9c578d4c71 | ||
|
|
377bc21f09 | ||
|
|
acfe35eda9 | ||
|
|
996357b49a | ||
|
|
325f5d4e37 | ||
|
|
249937ca72 | ||
|
|
d20f557ec4 | ||
|
|
b3dbdbd3ae | ||
|
|
62fc7a8110 | ||
|
|
ae45519551 | ||
|
|
ddd652c3ed | ||
|
|
04f8f84c9d | ||
|
|
7c47395780 | ||
|
|
85cf580dce | ||
|
|
e502d61550 | ||
|
|
2875be8031 | ||
|
|
a03fa4e0ce | ||
|
|
9233056238 | ||
|
|
4d6a8a71a7 | ||
|
|
2e6476eac2 | ||
|
|
5889a39fb4 | ||
|
|
766a3eefb6 | ||
|
|
4370abf89b | ||
|
|
b3c61ee157 | ||
|
|
3807e648c7 | ||
|
|
c701e2ad4a | ||
|
|
1bbcdd30dc | ||
|
|
4ff22a50d9 | ||
|
|
2ba8e10050 | ||
|
|
d67d8232c2 | ||
|
|
b6fd4ebbcc | ||
|
|
672d21cce7 | ||
|
|
19d2b80a1c | ||
|
|
9eff05b99f | ||
|
|
cd3dba5a56 | ||
|
|
8566bc0374 | ||
|
|
30850ced50 | ||
|
|
a47d4f8b8f | ||
|
|
8dfa9cee39 | ||
|
|
88fa050044 | ||
|
|
0605de707a | ||
|
|
7cfa39f34e | ||
|
|
64550e420e | ||
|
|
695404477e | ||
|
|
01aa0388b9 | ||
|
|
670421a79d | ||
|
|
e7655f1df0 | ||
|
|
a6798f37ad | ||
|
|
449e4fa431 | ||
|
|
a57d25fab8 | ||
|
|
6107559c8d | ||
|
|
c6de2ca406 | ||
|
|
49ed4d2b93 | ||
|
|
4d4d72229b | ||
|
|
aa695c4197 | ||
|
|
ba33622073 | ||
|
|
3091e7075f | ||
|
|
4f7148248b | ||
|
|
956442ff06 | ||
|
|
487bebe4c8 | ||
|
|
e04aaf6ce9 | ||
|
|
8559cfabca | ||
|
|
adf4721833 | ||
|
|
369255a4fe | ||
|
|
93616a9e80 | ||
|
|
6a5b9a4337 | ||
|
|
67106ff592 | ||
|
|
59762ae266 | ||
|
|
3afc2f4202 | ||
|
|
eb6a1b263d | ||
|
|
ed8f154c0a | ||
|
|
f51d8cb4fe | ||
|
|
aec007e1b4 | ||
|
|
f552b07a5f | ||
|
|
994bc9e789 | ||
|
|
aea7825f30 | ||
|
|
bc84fb1109 | ||
|
|
7af556c36c | ||
|
|
693796789b | ||
|
|
8019fb8f08 | ||
|
|
286e27510d | ||
|
|
d4a015fb47 | ||
|
|
bff1952268 | ||
|
|
ae07dce014 | ||
|
|
7f6c72853f | ||
|
|
2ee74b483b | ||
|
|
6e71313d2b | ||
|
|
9865b14c70 | ||
|
|
abba498192 | ||
|
|
918e09d84d | ||
|
|
bd7f32d92f | ||
|
|
4421202bc1 | ||
|
|
562c89c1d4 | ||
|
|
72e842885d | ||
|
|
2ee27c87cf | ||
|
|
a4c3a5c106 | ||
|
|
fa6ec8a7e6 | ||
|
|
d7f7d9d1fc | ||
|
|
33f6f510b1 | ||
|
|
09893539d2 | ||
|
|
11df6da209 | ||
|
|
7ff2335935 | ||
|
|
41f7a31640 | ||
|
|
9494bfdb53 | ||
|
|
92882bb83b | ||
|
|
77946771eb | ||
|
|
df4d97dca1 | ||
|
|
436d7b40f0 | ||
|
|
7b60b31750 | ||
|
|
3281b727d2 | ||
|
|
04cd7a9699 | ||
|
|
73a6701647 | ||
|
|
c3f27caa64 | ||
|
|
1956dab53b | ||
|
|
eb498577b5 | ||
|
|
25f3a9740d | ||
|
|
2be05110db | ||
|
|
3bed9b76cb | ||
|
|
57d947f08e | ||
|
|
6550453ed1 | ||
|
|
2221700b5b | ||
|
|
a6c4c7c9b6 | ||
|
|
24326389a4 | ||
|
|
d1303797c0 | ||
|
|
3748eae5fb | ||
|
|
b77723941d | ||
|
|
0635b9e54f | ||
|
|
7582e8fd72 | ||
|
|
c26a1ac21c | ||
|
|
1faddf4723 | ||
|
|
0e8270c7b5 | ||
|
|
39519c01a6 | ||
|
|
ccef8afbe7 | ||
|
|
cf8bf50c9f | ||
|
|
6ae650f755 | ||
|
|
53f3e53b16 | ||
|
|
256c1f411e | ||
|
|
8414ee18c0 | ||
|
|
88bb6cb046 | ||
|
|
810f25f52e | ||
|
|
9154dc11bf | ||
|
|
357916a6e2 | ||
|
|
faae9672ab | ||
|
|
ae2a485b1f | ||
|
|
3d21d9e1ec | ||
|
|
35532fd813 | ||
|
|
c8e4c829e4 | ||
|
|
b0f16b724c | ||
|
|
657e1f4d71 | ||
|
|
1670bf874b | ||
|
|
7251a2ef60 | ||
|
|
8799379e50 | ||
|
|
d0040e440f | ||
|
|
d252c3d6ea | ||
|
|
0a6b84639b | ||
|
|
5d699cdde0 | ||
|
|
5115c8b58c | ||
|
|
e2b39e403c | ||
|
|
9b8344c391 | ||
|
|
f5817a1d9e | ||
|
|
e364b3ab31 | ||
|
|
3414f7a31e | ||
|
|
8fbe451d54 | ||
|
|
e02322a396 | ||
|
|
da2f6dd6cc | ||
|
|
1f878192ec | ||
|
|
0edb4274b1 | ||
|
|
6ce846971b | ||
|
|
c39b696559 | ||
|
|
e6aabffc22 | ||
|
|
50bad75cb4 | ||
|
|
0682b485d0 | ||
|
|
d1944c76b9 | ||
|
|
c0f9c1da70 | ||
|
|
911045ae9a | ||
|
|
200ea05927 | ||
|
|
75946f7c0f | ||
|
|
c1b55d06a6 | ||
|
|
0a9f890fdd | ||
|
|
d27239e953 | ||
|
|
8e62abe6e7 | ||
|
|
fdc29180a0 | ||
|
|
2dc877a99f | ||
|
|
33e98386c9 | ||
|
|
6cde5843b5 | ||
|
|
fa27e16683 | ||
|
|
0a82669163 | ||
|
|
e59da29371 | ||
|
|
2f00e27bd1 | ||
|
|
c682b48a7c | ||
|
|
b2f20c9879 | ||
|
|
1297c883a6 | ||
|
|
6a408fd6a8 | ||
|
|
860a40717c | ||
|
|
e9034a459d | ||
|
|
714f0c82a9 | ||
|
|
63b194c10a | ||
|
|
4c70e4976b | ||
|
|
5200bcd94f | ||
|
|
d152986485 | ||
|
|
8b20f384a7 | ||
|
|
07e7d0795b | ||
|
|
1fbbce4e41 | ||
|
|
fea3fabdf2 | ||
|
|
3f86bc7d62 | ||
|
|
71040577ce | ||
|
|
85e0b96d51 | ||
|
|
974cbfb35e | ||
|
|
fbb80610a8 | ||
|
|
d6a3e30233 | ||
|
|
ed309e446a | ||
|
|
aae06e61bd | ||
|
|
78c7dc5e4f | ||
|
|
a781720060 | ||
|
|
db530c851a | ||
|
|
8334829e54 | ||
|
|
4c565679b5 | ||
|
|
e279e0437d | ||
|
|
2f4b131f26 | ||
|
|
28b197d79f | ||
|
|
599b7bdc71 | ||
|
|
10cf1053f8 | ||
|
|
abb78658c6 | ||
|
|
2a932d43d2 | ||
|
|
17ad60d528 | ||
|
|
22ce4e65bc | ||
|
|
e244768f32 | ||
|
|
6655521e91 | ||
|
|
2d5784d992 | ||
|
|
d05c4dc122 | ||
|
|
79aed22d46 | ||
|
|
aeab730dc2 | ||
|
|
197971e6fa | ||
|
|
8bb3b173f2 | ||
|
|
72ec69e37d | ||
|
|
edc6e5f9b3 | ||
|
|
f2f77b4e75 | ||
|
|
9e41064b4e | ||
|
|
b6274ddd77 | ||
|
|
40d01412cb | ||
|
|
da205efdff | ||
|
|
9ab674adbc | ||
|
|
a72425289b | ||
|
|
c47196bcc8 | ||
|
|
eebc1b90df | ||
|
|
e0e48837c6 | ||
|
|
df55f7a2eb | ||
|
|
fb3b4fc510 | ||
|
|
3c88afac0c | ||
|
|
8336421179 | ||
|
|
0ca39bb6d2 | ||
|
|
eac6ea1bfe | ||
|
|
5eb17833e4 | ||
|
|
982d3c3e61 | ||
|
|
9a6d3d87f0 | ||
|
|
c9b9725474 | ||
|
|
46a2a4440d | ||
|
|
1959aa5013 | ||
|
|
40baa302b2 | ||
|
|
d0deef72f5 | ||
|
|
a0da7452e3 | ||
|
|
0de5688618 | ||
|
|
18f57130ca | ||
|
|
7a96a7c931 | ||
|
|
9a0ce60a4f | ||
|
|
3b68c29f48 | ||
|
|
c807438ecd | ||
|
|
0a8122571b | ||
|
|
62679f37e2 | ||
|
|
6d5146e540 | ||
|
|
1150d832b1 | ||
|
|
a9f6f04394 | ||
|
|
0df717ca48 | ||
|
|
c17aba8646 | ||
|
|
5b99921d75 | ||
|
|
10e5595980 | ||
|
|
de236379a1 | ||
|
|
72a387c40a | ||
|
|
847e9d7c44 | ||
|
|
eb7c704d36 | ||
|
|
be66166b9d | ||
|
|
684f332599 | ||
|
|
edad82ad98 | ||
|
|
d6cfa556b8 | ||
|
|
65a1858f94 | ||
|
|
2140ffa382 | ||
|
|
a7ecadf189 | ||
|
|
f60e93aae1 | ||
|
|
c9943c0b2a | ||
|
|
a631262d91 | ||
|
|
d97aee01c3 | ||
|
|
5deb454a81 | ||
|
|
345a5a3de5 | ||
|
|
95f31090dc | ||
|
|
b1a0da290a | ||
|
|
75333dae3b | ||
|
|
5a1c7a62b2 | ||
|
|
670f0d6775 | ||
|
|
b3805999f3 | ||
|
|
b59582bde7 | ||
|
|
c61ec5f673 | ||
|
|
cd651ddf6f | ||
|
|
dfe284664c | ||
|
|
a3319930c0 | ||
|
|
c720354be2 | ||
|
|
5eca474c5e | ||
|
|
7e22d70ded | ||
|
|
ec6889931d | ||
|
|
fdaa8e4539 | ||
|
|
47340f06b0 | ||
|
|
3fd1f57b96 | ||
|
|
c8d009654c | ||
|
|
db0d2b0039 | ||
|
|
bebe5cbcfd | ||
|
|
fdd22ab668 | ||
|
|
f9c214a66f | ||
|
|
caaa5c6594 | ||
|
|
4bccb6cf8a | ||
|
|
7e9272776d | ||
|
|
f6072e9a95 | ||
|
|
393babe3c3 | ||
|
|
273233bb81 | ||
|
|
ef5b476c6d | ||
|
|
a908a1515a | ||
|
|
44e304179a | ||
|
|
831114bdbd | ||
|
|
1851e37aef | ||
|
|
6c819d7917 | ||
|
|
1581c96e4e | ||
|
|
ba67f8c8fe | ||
|
|
ca9676f52e | ||
|
|
3d0b67e9f7 | ||
|
|
bdf1c2010b | ||
|
|
925fb18855 | ||
|
|
66dacccfb4 | ||
|
|
f74ff3fc49 | ||
|
|
ed55de71d9 | ||
|
|
b8246ab8e5 | ||
|
|
4b8ec29d8d | ||
|
|
09eba6c0cf | ||
|
|
883cb22c39 | ||
|
|
71d4e5318a | ||
|
|
359eb7c3d2 | ||
|
|
bdffa373cf | ||
|
|
b42f0d32ea | ||
|
|
ddb07ebb75 | ||
|
|
5a0f483cd3 | ||
|
|
2856e7e247 | ||
|
|
ccb588f383 | ||
|
|
7f5f791e23 | ||
|
|
bef7bfc393 | ||
|
|
d078b72381 | ||
|
|
25189c3ae7 | ||
|
|
64a93a4570 | ||
|
|
4ff90c1373 | ||
|
|
38ff8f75b1 | ||
|
|
0379afc748 | ||
|
|
eaa0d37065 | ||
|
|
f73b20e415 | ||
|
|
50a816fce9 | ||
|
|
cc33366acb | ||
|
|
eb61c519c3 | ||
|
|
e517797cfa | ||
|
|
34889d50f8 | ||
|
|
882a156b63 | ||
|
|
041361c45e | ||
|
|
7af5121de8 | ||
|
|
dc0c568cb8 | ||
|
|
304b63907e | ||
|
|
cdb08e0879 | ||
|
|
90a0502b60 | ||
|
|
c1a35b3ff9 | ||
|
|
1d74f6ada2 | ||
|
|
ac75d9aa9b | ||
|
|
09b5fb11e8 | ||
|
|
e09265a3d0 | ||
|
|
56b7d78fed | ||
|
|
0e46d3e041 | ||
|
|
66074a1842 | ||
|
|
4b169fcae1 | ||
|
|
f78ff42dbe | ||
|
|
be3e8eecfb | ||
|
|
2c486acb32 | ||
|
|
9b364080ea | ||
|
|
f2c81ee9a2 | ||
|
|
93060ec0e3 | ||
|
|
a9f586369a | ||
|
|
3e2875267c | ||
|
|
8396413f9d | ||
|
|
155b8cfed9 | ||
|
|
10e1b09bf3 | ||
|
|
9675efa680 | ||
|
|
952a821c6c | ||
|
|
5e6b6c6b14 | ||
|
|
7d0529aaf7 | ||
|
|
88a296c9a7 | ||
|
|
d442c51c1a | ||
|
|
ce7534112a | ||
|
|
d772dedef1 | ||
|
|
213853c45d | ||
|
|
af68a30c5c | ||
|
|
3c53e262e3 | ||
|
|
37865e493a | ||
|
|
9a55fcd0ae | ||
|
|
348d86d330 | ||
|
|
89c6e76772 | ||
|
|
6d0d3e1c35 | ||
|
|
c125df4ef6 | ||
|
|
e8197f127f | ||
|
|
1c360e0344 | ||
|
|
0a09b9e451 | ||
|
|
4d8eaad0a3 | ||
|
|
8ad3ebcd05 | ||
|
|
41393fc09d | ||
|
|
f3675d547a | ||
|
|
12321c23af | ||
|
|
53164c3f3e | ||
|
|
a60b10afca | ||
|
|
a7c8d0473c | ||
|
|
91a7b4df6a | ||
|
|
645ae30a47 | ||
|
|
390ca8b3c6 | ||
|
|
0f897a3977 | ||
|
|
4a0229c13d | ||
|
|
956fb9296c | ||
|
|
47949c0b52 | ||
|
|
cf7628c450 | ||
|
|
b3162decff | ||
|
|
bdb415b0c7 | ||
|
|
2224880d89 | ||
|
|
c2df13ea22 | ||
|
|
09cad2557c | ||
|
|
87c3071ba7 | ||
|
|
191797380e | ||
|
|
8f6280dc9d | ||
|
|
b477508521 | ||
|
|
23d670181c | ||
|
|
f8c6f0ba64 | ||
|
|
a274cc5722 | ||
|
|
bb05be7b95 | ||
|
|
b91166a034 | ||
|
|
e1c39f255c | ||
|
|
1863e8f76a | ||
|
|
331ae0f03b | ||
|
|
c1cd04f1e6 | ||
|
|
38f2cf245e | ||
|
|
bccc8e921b | ||
|
|
b8ebbc27f5 | ||
|
|
cd2db280bf | ||
|
|
1eb0378952 | ||
|
|
463c1c0142 | ||
|
|
933ed2429d | ||
|
|
3f1186da2b | ||
|
|
04e3c0165a | ||
|
|
392ea23f1d | ||
|
|
897f11213c | ||
|
|
bfb69b2ff2 | ||
|
|
3a47413cd4 | ||
|
|
75f18f169c | ||
|
|
a10b79d7a8 | ||
|
|
15d467f9ff | ||
|
|
5393cc4cd5 | ||
|
|
8ce192c62a | ||
|
|
1ca2cf3bea | ||
|
|
533fb3f108 | ||
|
|
0abc7202b1 | ||
|
|
d124dbacc7 | ||
|
|
c3503922c9 | ||
|
|
4a1440a17b | ||
|
|
a539184ffd | ||
|
|
df78ea72c5 | ||
|
|
c16c93fe7c | ||
|
|
97645dde52 | ||
|
|
2a84b9eb44 | ||
|
|
a0318ffc8f | ||
|
|
1dce8af045 | ||
|
|
86cf09fa3f | ||
|
|
808ed4edd2 | ||
|
|
e0afa2cee4 | ||
|
|
e6aa73aa9d | ||
|
|
f058029841 | ||
|
|
2777211351 | ||
|
|
6541b04f4c | ||
|
|
a4bea4f954 | ||
|
|
cf2348fb13 | ||
|
|
ba108580c6 | ||
|
|
09a2d88364 | ||
|
|
bfaea5b89d | ||
|
|
4a29443752 | ||
|
|
c6445519ec | ||
|
|
ca6cc51302 | ||
|
|
ef3397b84d | ||
|
|
4a59c3dd84 | ||
|
|
1deedf5463 | ||
|
|
1f8a9474cf | ||
|
|
29e764961e | ||
|
|
aa8b15c1f4 | ||
|
|
542aba861f | ||
|
|
a911245d26 | ||
|
|
99492911a3 | ||
|
|
18deddb07a | ||
|
|
4b70560cc9 | ||
|
|
f5b9eb32a1 | ||
|
|
0a57a1aa4d | ||
|
|
450af73eee | ||
|
|
fdb7c0d6cd | ||
|
|
efbef301bf | ||
|
|
f260ed6da7 | ||
|
|
dd311897fc | ||
|
|
fa79a16a9d | ||
|
|
ff7a5997a2 | ||
|
|
5d0f6b2622 | ||
|
|
f1cd0a5d28 | ||
|
|
f25c7c3a1d | ||
|
|
9c77f15012 | ||
|
|
379233c632 | ||
|
|
52382df350 | ||
|
|
a6c5dbf7fb | ||
|
|
bb6486910f | ||
|
|
36edde2241 | ||
|
|
b8628a6e5b | ||
|
|
51f3ea5c88 | ||
|
|
e2052dedc1 | ||
|
|
e6728e8ff9 | ||
|
|
8e8249e6a5 | ||
|
|
df12b0d2e6 | ||
|
|
9e0144b6ae | ||
|
|
cbc5192e9a | ||
|
|
a1e099493d | ||
|
|
53e2c1fd7c | ||
|
|
bdcdd37ad8 | ||
|
|
ae99a88f52 | ||
|
|
002f3de5c4 | ||
|
|
5383040a83 | ||
|
|
ec424e01e4 | ||
|
|
c4e5fa49dd | ||
|
|
ba6e9a064d | ||
|
|
bf659701b6 | ||
|
|
de01158556 | ||
|
|
55eab08faa | ||
|
|
612ab61df4 | ||
|
|
2aade725b7 | ||
|
|
8df46e1774 | ||
|
|
488c6901b5 | ||
|
|
f498f165c2 | ||
|
|
28f068f505 | ||
|
|
1a7b6aa139 | ||
|
|
0ba3b19f1f | ||
|
|
cdfafa3013 | ||
|
|
5584fc285d | ||
|
|
194d90e2c2 | ||
|
|
d022804d61 | ||
|
|
dbbaf8da1a | ||
|
|
2b9bd7e9c3 | ||
|
|
17ce2848e6 | ||
|
|
5a03acb2ef | ||
|
|
12cf051271 | ||
|
|
befb79decb | ||
|
|
9734297d2d | ||
|
|
2e26b0fa49 | ||
|
|
6e7318bcba | ||
|
|
6741cfb4f4 | ||
|
|
b01dd81d84 | ||
|
|
0385241732 | ||
|
|
75609a9323 | ||
|
|
4c996a68ea | ||
|
|
eac57fb229 | ||
|
|
a48e5f52e2 | ||
|
|
fbea7535ca | ||
|
|
83924e203d | ||
|
|
c8edd4ce4a | ||
|
|
9073075451 | ||
|
|
e3644cf0d8 | ||
|
|
8c9d9a77bf | ||
|
|
9300c73252 | ||
|
|
5f9b2b3df3 | ||
|
|
ba6170e925 | ||
|
|
e1457a18cb | ||
|
|
904a833feb | ||
|
|
a820594506 | ||
|
|
fc905ccccc | ||
|
|
ae55147cfa | ||
|
|
680a2ad76b | ||
|
|
0d8b74932e | ||
|
|
f7759766f7 | ||
|
|
b6104527e1 | ||
|
|
662fb63156 | ||
|
|
dcc5a2840b | ||
|
|
e7d632a726 | ||
|
|
61ca557faf | ||
|
|
5baecfcec2 | ||
|
|
54b3140194 | ||
|
|
0e3c656103 | ||
|
|
81102750a1 | ||
|
|
14bb1b7b21 | ||
|
|
736a530bde | ||
|
|
9b7a105766 | ||
|
|
7d6386449d | ||
|
|
4d14063cbe | ||
|
|
84fb341c7d | ||
|
|
c4cc0ad0bf | ||
|
|
88dc16c910 | ||
|
|
53281660be | ||
|
|
8ee4ed2c17 | ||
|
|
101a1973a4 | ||
|
|
46d0058470 | ||
|
|
c0ef419048 | ||
|
|
88ee74d68a | ||
|
|
fe03cd8e59 | ||
|
|
a9cb83ff27 | ||
|
|
f8d5d02570 | ||
|
|
d88ed67d2c | ||
|
|
435ec5cd5d | ||
|
|
30558eabf4 | ||
|
|
cefb4094d3 | ||
|
|
8392143944 | ||
|
|
8014066154 | ||
|
|
322a6213c6 | ||
|
|
8502785a92 | ||
|
|
62bfdf30b4 | ||
|
|
3cd1b70bc0 | ||
|
|
e53f54b53f | ||
|
|
2b1ab54a6d | ||
|
|
6d88f26b1f | ||
|
|
05c8f2580e | ||
|
|
4383d8557f | ||
|
|
7e12774543 | ||
|
|
d7eec37052 | ||
|
|
cb32a7b5e2 | ||
|
|
1b8ad856d6 | ||
|
|
e79c6262b9 | ||
|
|
7de4cc902e | ||
|
|
9c422ecdca | ||
|
|
df1c133f68 | ||
|
|
3584a4b12a | ||
|
|
aacbb28052 | ||
|
|
e5d021c766 | ||
|
|
aa873be8f4 | ||
|
|
d78841631e | ||
|
|
2c88370b35 | ||
|
|
6ebeaf84a3 | ||
|
|
bd14b0f2ac | ||
|
|
d06cd671e2 | ||
|
|
3386c1c5bd | ||
|
|
4e54a61b65 | ||
|
|
a86c843be5 | ||
|
|
61a8ba80b4 | ||
|
|
3e8a0af36f | ||
|
|
fc66195b28 | ||
|
|
f96168fc2c | ||
|
|
52b599ab5d | ||
|
|
0a9704ebd8 | ||
|
|
bdc38a49a6 | ||
|
|
100cd41548 | ||
|
|
7e81989901 | ||
|
|
30ac8e814a | ||
|
|
c4b69f5991 | ||
|
|
40390550da | ||
|
|
5b3b5b8280 | ||
|
|
63ac86e60b | ||
|
|
8d6193ef1f | ||
|
|
92e410fdb5 | ||
|
|
7651edfa62 | ||
|
|
fc31688f69 | ||
|
|
571f6b8c4c | ||
|
|
e89e233543 | ||
|
|
12b6b2ca89 | ||
|
|
2ef034721f | ||
|
|
514d6f94ec | ||
|
|
4669ee22ce | ||
|
|
0541040e6b | ||
|
|
247ede7170 | ||
|
|
92857497f3 | ||
|
|
ce13bf34d0 | ||
|
|
b5c161d267 | ||
|
|
76e952ebd2 | ||
|
|
49291cc937 | ||
|
|
85447ca49d | ||
|
|
ed3b80b5d7 | ||
|
|
404f8ebb27 | ||
|
|
4d34513881 | ||
|
|
79de2d82cb | ||
|
|
742a5c44fc | ||
|
|
eb2dee22f1 | ||
|
|
d0476e8e9e | ||
|
|
407e5cbfeb | ||
|
|
7d05446f29 | ||
|
|
5feed3fdca | ||
|
|
7fce0bce51 | ||
|
|
27cc0d61bc | ||
|
|
71153c3c39 | ||
|
|
f346fb6f7c | ||
|
|
e2349b1d2d | ||
|
|
0c2b79bbf5 | ||
|
|
d08d9d2dc0 | ||
|
|
68f3fb51e5 | ||
|
|
b55f59ec26 | ||
|
|
a7367d256d | ||
|
|
08cd7a4ba7 | ||
|
|
b8a2b2a1c4 | ||
|
|
898c9431b5 | ||
|
|
a00083e221 | ||
|
|
4f8fb0e516 | ||
|
|
291660dda5 | ||
|
|
aa78b58866 | ||
|
|
dccd47ed19 | ||
|
|
73cd806dbf | ||
|
|
3abffe1f5d | ||
|
|
d10dfb550e | ||
|
|
8fdc9a7164 | ||
|
|
4be6b3cc96 | ||
|
|
7405254c72 | ||
|
|
8a8d61996f | ||
|
|
b76c1f99cc | ||
|
|
396f17484e | ||
|
|
fc868aba4a | ||
|
|
71e4396bd4 | ||
|
|
b984f7d63c | ||
|
|
1853d9ad48 | ||
|
|
74253459a8 | ||
|
|
9490146db9 | ||
|
|
5cd9ce03df | ||
|
|
91fa16c067 | ||
|
|
c77805aef3 | ||
|
|
30fb8aacaa | ||
|
|
50fa95747a | ||
|
|
df0c4e2361 | ||
|
|
ce205ae8a0 | ||
|
|
0397068dd0 | ||
|
|
1bf023abc2 | ||
|
|
818d55e4b4 | ||
|
|
cedc391485 | ||
|
|
1a3e071fc2 | ||
|
|
b34d9507e3 | ||
|
|
0b11b80d8a | ||
|
|
f6e9acf06f | ||
|
|
5c31b75ac7 | ||
|
|
aff4197ea9 | ||
|
|
76b86ba2a0 | ||
|
|
f5fb8aa305 | ||
|
|
8b96c14ffe | ||
|
|
712e3aeb72 | ||
|
|
54214eb400 | ||
|
|
ea8a709bea | ||
|
|
4e7f1eef37 | ||
|
|
8db02e8191 | ||
|
|
a4be346e4d | ||
|
|
10cc08c758 | ||
|
|
383c61c930 | ||
|
|
301c263dc8 | ||
|
|
dd3f84c60d | ||
|
|
e314a062df | ||
|
|
a08d90e9df | ||
|
|
13ade32f0f | ||
|
|
ef39802555 | ||
|
|
c5a1753548 | ||
|
|
818838ade6 | ||
|
|
261279d4c2 | ||
|
|
ba587b14bd | ||
|
|
2af11f489d | ||
|
|
2baf695709 | ||
|
|
0d31e965ef | ||
|
|
4fdda86a0b | ||
|
|
67d3bd6052 | ||
|
|
c8307b2c83 | ||
|
|
3b8ec873eb | ||
|
|
20a1a5c9da | ||
|
|
eb566416fc | ||
|
|
05d1f8aac8 | ||
|
|
e79fcb0db3 | ||
|
|
115f6d1b52 | ||
|
|
2aee208050 | ||
|
|
d95f723639 | ||
|
|
78cfb07214 | ||
|
|
fc950a02e6 | ||
|
|
deaa86f5cc | ||
|
|
4845b85328 | ||
|
|
bfb0a994d8 | ||
|
|
d40755ef65 | ||
|
|
38268d485b | ||
|
|
9b45c31db8 | ||
|
|
cefbd376ef | ||
|
|
9bbcb57be0 | ||
|
|
7aa8cc54f1 | ||
|
|
19e0f39f2b | ||
|
|
259ccb118f | ||
|
|
f1ad6f6bc5 | ||
|
|
14ecfedf24 | ||
|
|
2b99561b5d | ||
|
|
2521d5333e | ||
|
|
4d52fb45e4 | ||
|
|
744c739aa1 | ||
|
|
6667f285d3 | ||
|
|
c73c6a9f62 | ||
|
|
518ba1ab39 | ||
|
|
ad9755dd83 | ||
|
|
01d0fb485c | ||
|
|
474987ee4a | ||
|
|
0f232bce25 | ||
|
|
04a4159fa5 | ||
|
|
be46cb2b32 | ||
|
|
d7c6d1d0f5 | ||
|
|
c1e4a613c8 | ||
|
|
638c7633cb | ||
|
|
8a1a739355 | ||
|
|
5cda839152 | ||
|
|
5bd1d6b201 | ||
|
|
b69d98be3e | ||
|
|
cb39fd9d13 | ||
|
|
dfff092caf | ||
|
|
7f058dbad0 | ||
|
|
e07123e6ca | ||
|
|
d9cb531e45 | ||
|
|
9a5392e091 | ||
|
|
29b4faec4d | ||
|
|
81b3d225df | ||
|
|
ca85186d9a | ||
|
|
9643a7a462 | ||
|
|
5b0b59e04c | ||
|
|
e8cadd86f1 | ||
|
|
1976651890 | ||
|
|
ec814ca0e2 | ||
|
|
f3c285b66d | ||
|
|
5661a21148 | ||
|
|
404021811b | ||
|
|
f44d122db0 | ||
|
|
2ac8df6ccf | ||
|
|
e64d31deb1 | ||
|
|
eae6df9360 | ||
|
|
c762cc88aa | ||
|
|
3b7f7aaca2 | ||
|
|
b25188ab4f | ||
|
|
39eb141f10 | ||
|
|
d3e2d32c54 | ||
|
|
8f62da84c0 | ||
|
|
a9cf7e5a09 | ||
|
|
1637d0d13e | ||
|
|
c5f478962b | ||
|
|
c2c77de6f3 | ||
|
|
e10c4d68ff | ||
|
|
ae511cb82f | ||
|
|
11636f5bfc | ||
|
|
ab34aa991e | ||
|
|
6012994405 | ||
|
|
ee74561bbf | ||
|
|
d75a85a68f | ||
|
|
2e923f683a | ||
|
|
7f2b0da53c | ||
|
|
e683212bb8 | ||
|
|
c45dfb1e7c | ||
|
|
dd422e18d3 | ||
|
|
6192c97d40 | ||
|
|
ca066367f4 | ||
|
|
7d42967139 | ||
|
|
99fe86da8f | ||
|
|
4c4d8ef28f | ||
|
|
c891d113db | ||
|
|
555e609173 | ||
|
|
0ce33927c7 | ||
|
|
802b6b4f65 | ||
|
|
1ea89d7560 | ||
|
|
cfd3079739 | ||
|
|
d45fbdbad5 | ||
|
|
f089c44111 | ||
|
|
79421aa088 | ||
|
|
297a73c145 | ||
|
|
0acec5e039 | ||
|
|
d96c911a4b | ||
|
|
c256bef362 | ||
|
|
16a54e3b98 | ||
|
|
5e50d469e7 | ||
|
|
d261061fda | ||
|
|
a648838f29 | ||
|
|
8011b9f721 | ||
|
|
e8411bc99f | ||
|
|
2af996de68 | ||
|
|
5e78dedce6 | ||
|
|
1ccc4b2823 | ||
|
|
2988e9554b | ||
|
|
0cabce518f | ||
|
|
693aec37d8 | ||
|
|
f9afd27605 | ||
|
|
7e80dec5e7 | ||
|
|
b623ca8ace | ||
|
|
3fb9972114 | ||
|
|
8b8c16dd8e | ||
|
|
f9eb8ba8ac | ||
|
|
761d62f3de | ||
|
|
c6f9aa69f8 | ||
|
|
04e636075e | ||
|
|
698390f7d0 | ||
|
|
d7f8ad8a62 | ||
|
|
7d630aac98 | ||
|
|
9d0856e3c8 | ||
|
|
f3ed61b4c7 | ||
|
|
3fce3ae632 | ||
|
|
87b0796501 | ||
|
|
16d7dbeb66 | ||
|
|
8300486bec | ||
|
|
791c6eaf36 | ||
|
|
ec10852a68 | ||
|
|
8fcfa28fbb | ||
|
|
a8c474dbe9 | ||
|
|
1691e02d80 | ||
|
|
426b95bdf4 | ||
|
|
99c772a340 | ||
|
|
cb5c0cde1d | ||
|
|
37bf6b8d7e | ||
|
|
5c81e5a640 | ||
|
|
88ed8a64cd | ||
|
|
cdca47fbe5 | ||
|
|
443775fc5b | ||
|
|
2e33d47e86 | ||
|
|
605393d1a8 | ||
|
|
e0a2e5d292 | ||
|
|
f0dcfa78fa | ||
|
|
7bdb826c43 | ||
|
|
60904cadd4 | ||
|
|
7b4803132d | ||
|
|
5525b0f404 | ||
|
|
19770d186f | ||
|
|
2c8f5bc2e5 | ||
|
|
44700e6c60 | ||
|
|
96adaf5257 | ||
|
|
c3e32f5e15 | ||
|
|
f36ed8df64 | ||
|
|
40d88d2304 | ||
|
|
cfbd628b55 | ||
|
|
d33f6eb502 | ||
|
|
1946d2ec52 | ||
|
|
085fa7b726 | ||
|
|
482fea58a8 | ||
|
|
996a1aa973 | ||
|
|
10afcff6c1 | ||
|
|
484df4b9ce | ||
|
|
dd46d97920 | ||
|
|
3430ca2567 | ||
|
|
a0872989ab | ||
|
|
de9d8fff50 | ||
|
|
f3de44c9b8 | ||
|
|
a4264f9b82 | ||
|
|
9c5ef85909 | ||
|
|
78554252ed | ||
|
|
30f6498fe2 | ||
|
|
f5ea35d45c | ||
|
|
08fdc3bdcc | ||
|
|
ec9c16d5c7 | ||
|
|
b83de5fb88 | ||
|
|
52b26fd601 | ||
|
|
9375094a48 | ||
|
|
36b1c08edc | ||
|
|
095e78e431 | ||
|
|
b7e3eec8db | ||
|
|
18d0aa74c2 | ||
|
|
b38d8cdc5a | ||
|
|
4b4f7005fd | ||
|
|
1b2c1b8732 | ||
|
|
004ed31fdc | ||
|
|
a5d818a2e6 | ||
|
|
7060e6125e | ||
|
|
30f9764511 | ||
|
|
72ad860f6d | ||
|
|
e7a0417bc2 | ||
|
|
bd722c2474 | ||
|
|
18d0858f31 | ||
|
|
fb2ec8f5d2 | ||
|
|
0088893310 | ||
|
|
63bc417398 | ||
|
|
d8b9172559 | ||
|
|
d4e6aac3be | ||
|
|
071ff1ded9 | ||
|
|
b65c5f589e | ||
|
|
f712c7442d | ||
|
|
535001f937 | ||
|
|
9408515927 | ||
|
|
20aa291709 | ||
|
|
5e21cd6566 | ||
|
|
3476e5b7c1 | ||
|
|
e48c8bef23 | ||
|
|
6a673053c2 | ||
|
|
07ca97fdaf | ||
|
|
448388a825 | ||
|
|
350d347388 | ||
|
|
986a4981fb | ||
|
|
71c0d217e2 | ||
|
|
7f46ad0a35 | ||
|
|
b8b5cb8b1c | ||
|
|
1d8176ccfc | ||
|
|
646c07ea2d | ||
|
|
f2812804cb | ||
|
|
33bb3d5c64 | ||
|
|
ac904174a1 | ||
|
|
f3fced5bad | ||
|
|
354c82defe | ||
|
|
2e0552411f | ||
|
|
39fff4102f | ||
|
|
34e873c655 | ||
|
|
9f5f32d477 | ||
|
|
d0c5e9baf7 | ||
|
|
049670fe66 | ||
|
|
ba4d5a8d21 | ||
|
|
b8b45a323c | ||
|
|
12446c8bca | ||
|
|
adc37acfca | ||
|
|
e92c9bc7bc | ||
|
|
3f5db14a75 | ||
|
|
07d0b1997c | ||
|
|
7377dd6c54 | ||
|
|
3c0936fc86 | ||
|
|
919d726762 | ||
|
|
2bf3652593 | ||
|
|
e34e784756 | ||
|
|
232c0d9e0e | ||
|
|
bc66ef34df | ||
|
|
d7fc8cd99c | ||
|
|
795b77851e | ||
|
|
6bea033d53 | ||
|
|
b9d4f3021c | ||
|
|
6bfd6bd28f | ||
|
|
4cc770f102 | ||
|
|
66af0297c0 | ||
|
|
01b902f119 | ||
|
|
df8d3bec47 | ||
|
|
836740a81f | ||
|
|
7b807cbe88 | ||
|
|
e7c74f0c65 | ||
|
|
297ce0fc83 | ||
|
|
46347c599d | ||
|
|
37eaadefea | ||
|
|
3f73e1561d | ||
|
|
03d2405c3d | ||
|
|
a41d52c35d | ||
|
|
ea9b700bf0 | ||
|
|
2e816bf514 | ||
|
|
dcf780f7c8 | ||
|
|
456544d5be | ||
|
|
0ab66782e0 | ||
|
|
e9f77d7046 | ||
|
|
213b8be0f7 | ||
|
|
df3090c0b4 | ||
|
|
f56ff199d6 | ||
|
|
a9b4cb076b | ||
|
|
586b4c0f8e | ||
|
|
1106262a4b | ||
|
|
3177aea6f9 | ||
|
|
b800e2cce2 | ||
|
|
dd6f9bbc61 | ||
|
|
8452adfa73 | ||
|
|
737bf28b8b | ||
|
|
f216c6f6b3 | ||
|
|
af3fd12128 | ||
|
|
6e45e29995 | ||
|
|
34ea557b97 | ||
|
|
dd6874edde | ||
|
|
d3c1f4ba49 | ||
|
|
1dec3727bc | ||
|
|
cef6459b7e | ||
|
|
09d56f4b67 | ||
|
|
3c9c43ee24 | ||
|
|
2ffffbcc04 | ||
|
|
b4ba7ca144 | ||
|
|
46e1528cf6 | ||
|
|
da1630fc21 | ||
|
|
5aad51045c | ||
|
|
335b38028c | ||
|
|
9588d47986 | ||
|
|
f00be3cd26 | ||
|
|
fd948b6f96 | ||
|
|
fb18feea76 | ||
|
|
a038889c21 | ||
|
|
701c999f8a | ||
|
|
3d49094d07 | ||
|
|
af6a720e21 | ||
|
|
004472a180 | ||
|
|
08b467e3ca | ||
|
|
3ed04dd9ad | ||
|
|
b7ceb7887c | ||
|
|
9b7c13fe28 | ||
|
|
fbe9d3d0a4 | ||
|
|
4d81aead0f | ||
|
|
f016a9c4ce | ||
|
|
a8509b873f | ||
|
|
22f912e20e | ||
|
|
2a12b2917f | ||
|
|
a1f78eaa68 | ||
|
|
b4c602c4c7 | ||
|
|
b5338a5281 | ||
|
|
5be59c8bea | ||
|
|
12d004233a | ||
|
|
403e335005 | ||
|
|
7a8244e9e5 | ||
|
|
e17117c281 | ||
|
|
fbd362c34c | ||
|
|
aa0ea8123a | ||
|
|
24a171ecad | ||
|
|
4904bbf494 | ||
|
|
e999229952 | ||
|
|
ccf65ab1d3 | ||
|
|
75b21282ab | ||
|
|
8449a5e73f | ||
|
|
ef7591d3c8 | ||
|
|
68ab370c32 | ||
|
|
cc55e26446 | ||
|
|
01dcb01867 | ||
|
|
70c0c57507 | ||
|
|
825f417b53 | ||
|
|
334243d160 | ||
|
|
c9ad9cdff4 | ||
|
|
8130a76ff1 | ||
|
|
2d0c711638 | ||
|
|
2ea47fe386 | ||
|
|
c743d5d299 | ||
|
|
138745a6b1 | ||
|
|
d3154648d2 | ||
|
|
fd95b282a1 | ||
|
|
a0f7e622b1 | ||
|
|
2f162e859e | ||
|
|
f516136bd7 | ||
|
|
688d9e466b | ||
|
|
11e5520166 | ||
|
|
aae26f37a6 | ||
|
|
e59fd80b02 | ||
|
|
2e95ba3fb7 | ||
|
|
e8d30486e4 | ||
|
|
2c69426f8d | ||
|
|
d0251192be | ||
|
|
637713cb68 | ||
|
|
ebd165dd22 | ||
|
|
2c8730690b | ||
|
|
250b87aa01 | ||
|
|
d2e7cca17b | ||
|
|
cc12babf58 | ||
|
|
c76504f0d6 | ||
|
|
25235523da | ||
|
|
3df9be0fa7 | ||
|
|
d61c7578c1 | ||
|
|
da71945f97 | ||
|
|
166344d793 | ||
|
|
3529cfa1d6 | ||
|
|
eb080223d8 | ||
|
|
0eea45fb60 | ||
|
|
a9ecc1fbca | ||
|
|
8d0b5d6203 | ||
|
|
640a9f4a17 | ||
|
|
2fb9c19871 | ||
|
|
68a6d394e7 | ||
|
|
61428b0c9b | ||
|
|
0295555c70 | ||
|
|
571a4c3c33 | ||
|
|
985a7c0f66 | ||
|
|
5b03d25743 | ||
|
|
774bb0145f | ||
|
|
fba3d1e6a6 | ||
|
|
3c475e2d21 | ||
|
|
53de8d77f2 | ||
|
|
80d0def963 | ||
|
|
2594b282fe | ||
|
|
34fb629138 | ||
|
|
119f7380fb | ||
|
|
808efc3dac | ||
|
|
d7d2258827 | ||
|
|
fec36dcc02 | ||
|
|
870f9be64b | ||
|
|
7448869f29 | ||
|
|
d04511494d | ||
|
|
543cfdd309 | ||
|
|
d181179597 | ||
|
|
8cf388b5a9 | ||
|
|
c227e6ca8e | ||
|
|
ca70aef78c | ||
|
|
cc2e141a5e | ||
|
|
1c0b60417e | ||
|
|
acf6a9d5b6 | ||
|
|
25be233e34 | ||
|
|
ae25d1d108 | ||
|
|
54efe77225 | ||
|
|
68cd86838d | ||
|
|
be5c78c34e | ||
|
|
b6fe520694 | ||
|
|
b9e7772af6 | ||
|
|
b5a1935b64 | ||
|
|
3e16929f68 | ||
|
|
20e519ec04 | ||
|
|
8650fdbe5a | ||
|
|
2dc3b0aecf | ||
|
|
e9fa301e4f | ||
|
|
62a957d812 | ||
|
|
97460f37f9 | ||
|
|
274dc490a4 | ||
|
|
1b00efc8e3 | ||
|
|
76de3a1378 | ||
|
|
d5b19c6723 | ||
|
|
d53c903517 | ||
|
|
ecf122c465 | ||
|
|
04667f6069 | ||
|
|
4eecec4c94 | ||
|
|
2f05a8c42d | ||
|
|
b78780cd96 | ||
|
|
2b735c2e1e | ||
|
|
3143d5aea9 | ||
|
|
37626627ef | ||
|
|
7ebab7875b | ||
|
|
a7f3da3983 | ||
|
|
013311b6b2 | ||
|
|
9aa783459d | ||
|
|
40f2c562dc | ||
|
|
2bea3f4b14 | ||
|
|
a431d6d6a8 | ||
|
|
48307e3286 | ||
|
|
d29d7f8b56 | ||
|
|
5d89bb8056 | ||
|
|
795978c78f | ||
|
|
c9217d2775 | ||
|
|
e1104d838b | ||
|
|
64cb4bd1f3 | ||
|
|
0fd65e2bf2 | ||
|
|
5af0f55ef8 | ||
|
|
f903187df3 | ||
|
|
4b850662d3 | ||
|
|
2635c65ce2 | ||
|
|
6588e8b7ac | ||
|
|
b1424313e9 | ||
|
|
5a495e1e99 | ||
|
|
2c7d8befcb | ||
|
|
84244b5e79 | ||
|
|
d3f1d1d111 | ||
|
|
1215832549 | ||
|
|
ed1dc103fe | ||
|
|
b2cec62b87 | ||
|
|
71634aa039 | ||
|
|
0c2964da0a | ||
|
|
784dd1090b | ||
|
|
39b6888b6c | ||
|
|
03046a83b9 | ||
|
|
2790f2c3b5 | ||
|
|
c2fde993ff | ||
|
|
76fe4c67a3 | ||
|
|
58fc6b8180 | ||
|
|
86707c3094 | ||
|
|
732cd46d4b | ||
|
|
4988ef76b5 | ||
|
|
1b8f4b3f25 | ||
|
|
e015ab6bf4 | ||
|
|
f7750f7d80 | ||
|
|
6a4b541de1 | ||
|
|
99b28fe872 | ||
|
|
e6aad9a9a7 | ||
|
|
017b171169 | ||
|
|
b51294df15 | ||
|
|
41cf65978c | ||
|
|
2c331b2a87 | ||
|
|
c41672802b | ||
|
|
262cb74b45 | ||
|
|
18abd4866e | ||
|
|
b2b6e4243b | ||
|
|
8f74415cc5 | ||
|
|
53cfeb1d58 | ||
|
|
8de221f137 | ||
|
|
8a80d11467 | ||
|
|
da37020939 | ||
|
|
94365a58dc | ||
|
|
063fede82c | ||
|
|
3a1c7eb317 | ||
|
|
2153459a51 | ||
|
|
cdb7faaa0b | ||
|
|
900c2da89c | ||
|
|
d9d4f8eb53 | ||
|
|
0910d526af | ||
|
|
93ab540b54 | ||
|
|
cfb912b099 | ||
|
|
b7d1d5e69e | ||
|
|
4db5e92cee | ||
|
|
142e3709c7 | ||
|
|
b7a5287370 | ||
|
|
c90d2eb4c8 | ||
|
|
1037dace47 | ||
|
|
d05453effe | ||
|
|
aaf38a531e | ||
|
|
39af527234 | ||
|
|
0726acc3d1 | ||
|
|
53a84f7e93 | ||
|
|
d45d1c9b64 | ||
|
|
56ff3a0554 | ||
|
|
6c4753afb5 | ||
|
|
cc7e55b8dd | ||
|
|
57f29c8136 | ||
|
|
c731e7f927 | ||
|
|
3dbf51f1a3 | ||
|
|
714aec1219 | ||
|
|
ffa733b8ff | ||
|
|
cddb0cb8af | ||
|
|
6c77d891cd | ||
|
|
d57d1ecae2 | ||
|
|
12deece54b | ||
|
|
98e82c5f11 | ||
|
|
d58180d588 | ||
|
|
e440ab5cba | ||
|
|
6bc0b34354 | ||
|
|
ba3804107e | ||
|
|
dff76e9cd2 | ||
|
|
f61d420093 | ||
|
|
84ff74cb5d | ||
|
|
7669e9781a | ||
|
|
48aa2f2b95 | ||
|
|
19bb65a73e | ||
|
|
1fc4fcb7c9 | ||
|
|
dc177a45db | ||
|
|
9a777dd1b5 | ||
|
|
7da6034f01 | ||
|
|
930fa094d5 | ||
|
|
6defa450b8 | ||
|
|
829a25d988 | ||
|
|
f8ae8aa86f | ||
|
|
1687bdd7c3 | ||
|
|
c1aca6b231 | ||
|
|
428bb9b0b6 | ||
|
|
713433026d | ||
|
|
1ef8f82488 | ||
|
|
4764a34224 | ||
|
|
a6b15f948d | ||
|
|
a2127e0062 | ||
|
|
118ddcdd79 | ||
|
|
4c2e1ef5e4 | ||
|
|
b9bcebdcee | ||
|
|
3a2d73018a | ||
|
|
25b671c6fb | ||
|
|
5acde94015 | ||
|
|
6a84656e72 | ||
|
|
3359a3cc8c | ||
|
|
ba01a1c4ed | ||
|
|
cd712c4589 | ||
|
|
fbe75de23f | ||
|
|
4e857cb951 | ||
|
|
1e3c5ba90d | ||
|
|
6623351578 | ||
|
|
ff4a855bc8 | ||
|
|
ed4e935951 | ||
|
|
b06be45894 | ||
|
|
7798fbc21d | ||
|
|
8ea3f5d0c8 | ||
|
|
dbb70c5acc | ||
|
|
f5b9bed40a | ||
|
|
fa9195eacb | ||
|
|
ae4cfd094e | ||
|
|
32800f54a0 | ||
|
|
75b3520879 | ||
|
|
79c2843d76 | ||
|
|
3a1f73c7d0 | ||
|
|
1d74ef74ca | ||
|
|
b756bcf65a | ||
|
|
10bf14a88a | ||
|
|
08bfdaface | ||
|
|
d3b0a15284 | ||
|
|
d22d823e9c | ||
|
|
f6a680897c | ||
|
|
29e2ee7a0e | ||
|
|
b2e416b0dd | ||
|
|
2ec27d4466 | ||
|
|
673c98c3f4 | ||
|
|
bd38c16e0a | ||
|
|
63b274ecb0 | ||
|
|
3ce48f3799 | ||
|
|
8b52645905 | ||
|
|
c913612fd3 | ||
|
|
31a74a3390 | ||
|
|
7a962c8436 | ||
|
|
b99f028a66 | ||
|
|
2c0cea1a3f | ||
|
|
5d744c7c20 | ||
|
|
eb96e701b5 | ||
|
|
e6db12848f | ||
|
|
1dc1b9ee73 | ||
|
|
d9bb1393d3 | ||
|
|
1977d41a1e | ||
|
|
e09f16b68c | ||
|
|
d3b2c8fee0 | ||
|
|
abc7063339 | ||
|
|
3700cd8c0b | ||
|
|
6882993358 | ||
|
|
84ebee3d4b | ||
|
|
19157597a0 | ||
|
|
471f5c6b6b | ||
|
|
38abe40db8 | ||
|
|
5a6303265d | ||
|
|
be776fb5dd | ||
|
|
849c7a45fc | ||
|
|
791b025309 | ||
|
|
cb5688ba51 | ||
|
|
6f51e2a4d1 | ||
|
|
ec939fdaaf | ||
|
|
72ddf04321 | ||
|
|
68dd65fd38 | ||
|
|
871dbe7352 | ||
|
|
cf41a3cfac | ||
|
|
41f52492f9 | ||
|
|
137dc19735 | ||
|
|
a3ad9999b0 | ||
|
|
1dcb3c0aca | ||
|
|
6c4495c0d1 | ||
|
|
f85a421550 | ||
|
|
ccafe5ce68 | ||
|
|
ecae98b8a0 | ||
|
|
b949aa2fa3 | ||
|
|
c19438ce84 | ||
|
|
31fc50d2a5 | ||
|
|
9012db5f79 | ||
|
|
e3e766c641 | ||
|
|
f064104bde | ||
|
|
849e526f33 | ||
|
|
8394e696ca | ||
|
|
6a4f3e1336 | ||
|
|
79dd0549cd | ||
|
|
9c3b0b69a5 | ||
|
|
563c7ab045 | ||
|
|
33f1e23e87 | ||
|
|
d3641bfe12 | ||
|
|
34b9e1f22a | ||
|
|
4e390dbccf | ||
|
|
f30f524b36 | ||
|
|
627e418287 | ||
|
|
d9145b1c8a | ||
|
|
2b602ebe50 | ||
|
|
5e0ae41c37 | ||
|
|
4a9949d399 | ||
|
|
e6825d5960 | ||
|
|
959f8935e7 | ||
|
|
993416d77c | ||
|
|
e8747fc2da | ||
|
|
33bf306f28 | ||
|
|
54540f3a22 | ||
|
|
4c594627a9 | ||
|
|
27f15a9c93 | ||
|
|
851d1c2605 | ||
|
|
e229a3eccc | ||
|
|
7f82270ea7 | ||
|
|
781a71e3d5 | ||
|
|
157d6634d1 | ||
|
|
954aec0907 | ||
|
|
dbaa573b97 | ||
|
|
459fe31e0b | ||
|
|
8da933af53 | ||
|
|
0d0e3f5523 | ||
|
|
6804bd79e8 | ||
|
|
5ea05b385a | ||
|
|
8233efe921 | ||
|
|
973e0be3e1 | ||
|
|
8d3163a842 | ||
|
|
64c8c33a4f | ||
|
|
718e4505a6 | ||
|
|
12b03f34bb | ||
|
|
76a14e91ed | ||
|
|
385b4558cb | ||
|
|
5cd493680e |
No files matched your search
@@ -0,0 +1,15 @@
|
||||
blank_issues_enabled: false
|
||||
|
||||
contact_links:
|
||||
|
||||
- name: Ask an question / advise on using nuclei
|
||||
url: https://github.com/projectdiscovery/nuclei/discussions/categories/q-a
|
||||
about: Ask a question or request support for using nuclei
|
||||
|
||||
- name: Share idea / feature to discuss for nuclei
|
||||
url: https://github.com/projectdiscovery/nuclei/discussions/categories/ideas
|
||||
about: Share idea / feature to discuss for nuclei
|
||||
|
||||
- name: Connect with PD Team (Discord)
|
||||
url: https://discord.gg/projectdiscovery
|
||||
about: Connect with PD Team for direct communication
|
||||
@@ -1,14 +1,21 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[feature]"
|
||||
labels: ''
|
||||
about: Request feature to implement in this project
|
||||
title: ""
|
||||
labels: 'Type: Enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
<!--
|
||||
1. Please make sure to provide a detailed description with all the relevant information that might be required to start working on this feature.
|
||||
2. In case you are not sure about your request or whether the particular feature is already supported or not, please start a discussion instead.
|
||||
3. GitHub Discussion: https://github.com/projectdiscovery/nuclei/discussions/categories/ideas
|
||||
4. Join our discord server at https://discord.gg/projectdiscovery to discuss the idea on the #nuclei channel.
|
||||
-->
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
### Please describe your feature request:
|
||||
<!-- A clear and concise description of feature to implement -->
|
||||
|
||||
### Describe the use case of this feature:
|
||||
<!-- A clear and concise description of the feature request's motivation and the use-cases in which it could be useful. -->
|
||||
@@ -1,18 +1,36 @@
|
||||
---
|
||||
name: Issue report
|
||||
about: Create a report to help us improve
|
||||
title: "[issue]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
about: Create a report to help us to improve the project
|
||||
labels: 'Type: Bug'
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
<!--
|
||||
1. Please search to see if an issue already exists for the bug you encountered.
|
||||
2. For support requests, FAQs or "How to" questions, please use the GitHub Discussions section instead - https://github.com/projectdiscovery/nuclei/discussions or
|
||||
3. Join our discord server at https://discord.gg/projectdiscovery and post the question on the #nuclei channel.
|
||||
-->
|
||||
|
||||
**Nuclei version**
|
||||
Please share the version of the nuclei you are running with `nuclei -version`
|
||||
<!-- ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION. -->
|
||||
|
||||
### Nuclei version:
|
||||
<!-- You can find current version of nuclei with "nuclei -version" -->
|
||||
<!-- We only accept issues that are reproducible on the latest version of nuclei. -->
|
||||
<!-- You can find the latest version of project at https://github.com/projectdiscovery/nuclei/releases/ -->
|
||||
|
||||
### Current Behavior:
|
||||
<!-- A concise description of what you're experiencing. -->
|
||||
|
||||
### Expected Behavior:
|
||||
<!-- A concise description of what you expected to happen. -->
|
||||
|
||||
### Steps To Reproduce:
|
||||
<!--
|
||||
Example: steps to reproduce the behavior:
|
||||
1. Run 'nuclei -t ... -u ..'
|
||||
2. See error...
|
||||
-->
|
||||
|
||||
|
||||
**Screenshot of the error or bug**
|
||||
please add the screenshot showing bug or issue you are facing.
|
||||
### Anything else:
|
||||
<!-- Links? References? Screenshots? Anything that will give us more context about the issue that you are encountering! -->
|
||||
@@ -0,0 +1,13 @@
|
||||
## Proposed changes
|
||||
|
||||
<!-- 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. -->
|
||||
|
||||
|
||||
## Checklist
|
||||
|
||||
<!-- Put an "x" in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code. -->
|
||||
|
||||
- [ ] Pull request is created against the [dev](https://github.com/projectdiscovery/nuclei/tree/dev) branch
|
||||
- [ ] All checks passed (lint, unit/integration/regression tests etc.) with my changes
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] I have added necessary documentation (if appropriate)
|
||||
+11
-2
@@ -11,24 +11,33 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: "dev"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
include: "scope"
|
||||
labels:
|
||||
- "Type: Maintenance"
|
||||
|
||||
# Maintain dependencies for go modules
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
directory: "v2/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
interval: "daily"
|
||||
target-branch: "dev"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
include: "scope"
|
||||
labels:
|
||||
- "Type: Maintenance"
|
||||
|
||||
# Maintain dependencies for docker
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: "dev"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
include: "scope"
|
||||
labels:
|
||||
- "Type: Maintenance"
|
||||
@@ -0,0 +1,40 @@
|
||||
name: 🔨 Build Test
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Test Builds
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build
|
||||
run: go build .
|
||||
working-directory: v2/cmd/nuclei/
|
||||
|
||||
- name: Test
|
||||
run: go test ./...
|
||||
working-directory: v2/
|
||||
|
||||
- name: Integration Tests
|
||||
env:
|
||||
GH_ACTION: true
|
||||
run: bash run.sh
|
||||
working-directory: integration_tests/
|
||||
|
||||
# At the bottom for known issue on OSX - https://github.com/projectdiscovery/nuclei/issues/1309
|
||||
- name: Race Condition Tests
|
||||
run: go build -race .
|
||||
working-directory: v2/cmd/nuclei/
|
||||
@@ -1,45 +0,0 @@
|
||||
name: Build
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: golangci-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||
version: v1.33
|
||||
args: --timeout 5m
|
||||
working-directory: v2/
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Test
|
||||
run: go test ./...
|
||||
working-directory: v2/
|
||||
|
||||
- name: Integration Tests
|
||||
run: bash run.sh
|
||||
working-directory: integration_tests/
|
||||
|
||||
- name: Build
|
||||
run: go build .
|
||||
working-directory: v2/cmd/nuclei/
|
||||
@@ -0,0 +1,39 @@
|
||||
name: 🚨 CodeQL Analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -1,19 +1,40 @@
|
||||
# dockerhub-push pushes docker build to dockerhub automatically
|
||||
# on the creation of a new release
|
||||
name: Publish to Dockerhub on creation of a new release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
name: 🌥 Docker Push
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["🎉 Release Binary"]
|
||||
types:
|
||||
- completed
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Publish to Dockerhub Registry
|
||||
#pre: echo ::save-state name=RELEASE_VERSION::$(echo ${GITHUB_REF:10})
|
||||
uses: elgohr/Publish-Docker-Github-Action@master
|
||||
with:
|
||||
name: projectdiscovery/nuclei
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
tags: "latest" #"latest,${{ env.STATE_RELEASE_VERSION }}"
|
||||
- name: Git Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get Github tag
|
||||
id: meta
|
||||
run: |
|
||||
echo "::set-output name=tag::$(curl --silent "https://api.github.com/repos/projectdiscovery/nuclei/releases/latest" | jq -r .tag_name)"
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: projectdiscovery/nuclei:latest,projectdiscovery/nuclei:${{ steps.meta.outputs.tag }}
|
||||
@@ -0,0 +1,30 @@
|
||||
name: 🧪 Functional Test
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
jobs:
|
||||
functional:
|
||||
name: Functional Test
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Functional Tests
|
||||
env:
|
||||
GH_ACTION: true
|
||||
run: |
|
||||
chmod +x run.sh
|
||||
bash run.sh ${{ matrix.os }}
|
||||
working-directory: v2/cmd/functional-test
|
||||
@@ -0,0 +1,19 @@
|
||||
name: 🙏🏻 Lint Test
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout 5m
|
||||
working-directory: v2/
|
||||
@@ -0,0 +1,51 @@
|
||||
name: ⏰ Publish Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: "Set up Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: Generate YAML Syntax Documentation
|
||||
id: generate-docs
|
||||
run: |
|
||||
if ! which dstdocgen > /dev/null; then
|
||||
echo -e "Command dstdocgen not found! Installing\c"
|
||||
go install github.com/projectdiscovery/yamldoc-go/cmd/docgen/dstdocgen@main
|
||||
fi
|
||||
go generate pkg/templates/templates.go
|
||||
go build -o "cmd/docgen/docgen" cmd/docgen/docgen.go
|
||||
./cmd/docgen/docgen ../SYNTAX-REFERENCE.md ../nuclei-jsonschema.json
|
||||
echo "::set-output name=changes::$(git status -s | wc -l)"
|
||||
working-directory: v2
|
||||
|
||||
- name: Commit files
|
||||
if: steps.generate-docs.outputs.changes > 0
|
||||
run: |
|
||||
git config --local user.email "[email protected]"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add SYNTAX-REFERENCE.md nuclei-jsonschema.json
|
||||
git commit -m "Auto Generate Syntax Docs + JSONSchema [$(date)] :robot:" -a
|
||||
|
||||
- name: Push changes
|
||||
if: steps.generate-docs.outputs.changes > 0
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
@@ -0,0 +1,27 @@
|
||||
name: 🎉 Release Binary
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
args: "release --rm-dist"
|
||||
version: latest
|
||||
workdir: v2/
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
@@ -1,30 +0,0 @@
|
||||
name: Release
|
||||
on:
|
||||
create:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: "Check out code"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
-
|
||||
name: "Set up Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
-
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||
name: "Create release on GitHub"
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
args: "release --rm-dist"
|
||||
version: latest
|
||||
workdir: v2/
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
name: 👮🏼♂️ Sonarcloud
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- dev
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
sonarcloud:
|
||||
name: SonarCloud
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
|
||||
- name: "Set up Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: Run unit Tests
|
||||
working-directory: v2/
|
||||
run: |
|
||||
go test -coverprofile=cov.out ./...
|
||||
|
||||
- name: Run Gosec Security Scanner
|
||||
working-directory: v2/
|
||||
run: |
|
||||
go install github.com/securego/gosec/cmd/gosec@latest
|
||||
gosec -no-fail -fmt=sonarqube -out report.json ./...
|
||||
|
||||
- name: SonarCloud Scan
|
||||
uses: SonarSource/sonarcloud-github-action@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
@@ -0,0 +1,28 @@
|
||||
name: 🛠 Template Validate
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
|
||||
- name: Cache Go
|
||||
id: cache-go
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /home/runner/go
|
||||
key: ${{ runner.os }}-go
|
||||
|
||||
- name: Installing Nuclei
|
||||
# if: steps.cache-go.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
go install github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
|
||||
- name: Template Validation
|
||||
run: |
|
||||
nuclei -validate
|
||||
nuclei -validate -w ./workflows
|
||||
+11
-4
@@ -1,6 +1,13 @@
|
||||
cmd/nuclei/nuclei*
|
||||
v2/cmd/nuclei/nuclei
|
||||
.idea
|
||||
integration_tests/integration-test
|
||||
integration_tests/nuclei
|
||||
v2/cmd/integration-test/integration-test
|
||||
integration_tests/integration-test
|
||||
v2/cmd/nuclei/main
|
||||
v2/cmd/nuclei/nuclei
|
||||
v2/cmd/integration-test/nuclei
|
||||
v2/cmd/functional-test/nuclei_dev
|
||||
v2/cmd/functional-test/nuclei_main
|
||||
v2/cmd/functional-test/functional-test
|
||||
v2/cmd/docgen/docgen
|
||||
v2/pkg/protocols/common/helpers/deserialization/testdata/Deserialize.class
|
||||
v2/pkg/protocols/common/helpers/deserialization/testdata/ValueObject.class
|
||||
v2/pkg/protocols/common/helpers/deserialization/testdata/ValueObject2.ser
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 100
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: false
|
||||
# funlen:
|
||||
# lines: 100
|
||||
# statements: 50
|
||||
#goconst:
|
||||
# min-len: 2
|
||||
# min-occurrences: 2
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- diagnostic
|
||||
- experimental
|
||||
- opinionated
|
||||
- performance
|
||||
- style
|
||||
disabled-checks:
|
||||
- dupImport # https://github.com/go-critic/go-critic/issues/845
|
||||
- ifElseChain
|
||||
# gocyclo:
|
||||
# min-complexity: 15
|
||||
goimports:
|
||||
local-prefixes: github.com/golangci/golangci-lint
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gomnd:
|
||||
settings:
|
||||
mnd:
|
||||
# don't include the "operation" and "assign"
|
||||
checks: argument,case,condition,return
|
||||
govet:
|
||||
check-shadowing: true
|
||||
settings:
|
||||
printf:
|
||||
funcs:
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
|
||||
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
|
||||
# lll:
|
||||
# line-length: 140
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
nolintlint:
|
||||
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
|
||||
allow-unused: false # report any unused nolint directives
|
||||
require-explanation: false # don't require an explanation for nolint directives
|
||||
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
|
||||
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
disable-all: true
|
||||
enable:
|
||||
#- bodyclose
|
||||
- deadcode
|
||||
- dogsled
|
||||
- errcheck
|
||||
- exhaustive
|
||||
- gochecknoinits
|
||||
#- goconst
|
||||
- gocritic
|
||||
- gofmt
|
||||
- goimports
|
||||
- golint
|
||||
#- gomnd
|
||||
- goprintffuncname
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- maligned
|
||||
- misspell
|
||||
- nakedret
|
||||
- noctx
|
||||
- nolintlint
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- whitespace
|
||||
|
||||
# don't enable:
|
||||
# - depguard
|
||||
# - asciicheck
|
||||
# - funlen
|
||||
# - gochecknoglobals
|
||||
# - gocognit
|
||||
# - gocyclo
|
||||
# - godot
|
||||
# - godox
|
||||
# - goerr113
|
||||
# - gosec
|
||||
# - lll
|
||||
# - nestif
|
||||
# - prealloc
|
||||
# - testpackage
|
||||
# - wsl
|
||||
|
||||
# golangci.com configuration
|
||||
# https://github.com/golangci/golangci/wiki/Configuration
|
||||
service:
|
||||
golangci-lint-version: 1.33.x # use the fixed version to not introduce new linters unexpectedly
|
||||
prepare:
|
||||
- echo "here I can run custom commands, but no preparation needed for this repo"
|
||||
@@ -0,0 +1,19 @@
|
||||
<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>
|
||||
@@ -0,0 +1,19 @@
|
||||
<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$/v2/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$/v2/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>
|
||||
@@ -0,0 +1,12 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="UnitTests" type="GoTestRunConfiguration" factoryName="Go Test">
|
||||
<module name="nuclei" />
|
||||
<working_directory value="$PROJECT_DIR$/v2" />
|
||||
<go_parameters value="-i" />
|
||||
<kind value="DIRECTORY" />
|
||||
<directory value="$PROJECT_DIR$/v2/" />
|
||||
<filePath value="$PROJECT_DIR$" />
|
||||
<framework value="gotest" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,604 @@
|
||||
# Nuclei Architecture Document
|
||||
|
||||
A brief overview of Nuclei Engine architecture. This document will be kept updated as the engine progresses.
|
||||
|
||||
## pkg/templates
|
||||
|
||||
### Template
|
||||
|
||||
Template is the basic unit of input to the engine which describes the requests to be made, matching to be done, data to extract, etc.
|
||||
|
||||
The template structure is described here. Template level attributes are defined here as well as convenience methods to validate, parse and compile templates creating executers.
|
||||
|
||||
Any attributes etc. required for the template, engine or requests to function are also set here.
|
||||
|
||||
Workflows are also compiled, their templates are loaded and compiled as well. Any validations etc. on the paths provided are also done here.
|
||||
|
||||
`Parse` function is the main entry point which returns a template for a `filePath` and `executorOptions`. It compiles all the requests for the templates, all the workflows, as well as any self-contained request etc. It also caches the templates in an in-memory cache.
|
||||
|
||||
### Preprocessors
|
||||
|
||||
Preprocessors are also applied here which can do things at template level. They get data of the template which they can alter at will on runtime. This is used in the engine to do random string generation.
|
||||
|
||||
Custom processor can be used if they satisfy the following interface.
|
||||
|
||||
```go
|
||||
type Preprocessor interface {
|
||||
Process(data []byte) []byte
|
||||
}
|
||||
```
|
||||
|
||||
## pkg/model
|
||||
|
||||
Model package implements Information structure for Nuclei Templates. `Info` contains all major metadata information for the template. `Classification` structure can also be used to provide additional context to vulnerability data.
|
||||
|
||||
It also specifies a `WorkflowLoader` interface that is used during workflow loading in template compilation stage.
|
||||
|
||||
```go
|
||||
type WorkflowLoader interface {
|
||||
GetTemplatePathsByTags(tags []string) []string
|
||||
GetTemplatePaths(templatesList []string, noValidate bool) []string
|
||||
}
|
||||
```
|
||||
|
||||
## pkg/protocols
|
||||
|
||||
Protocols package implements all the request protocols supported by Nuclei. This includes http, dns, network, headless and file requests as of now.
|
||||
|
||||
### Request
|
||||
|
||||
It exposes a `Request` interface that is implemented by all the request protocols supported.
|
||||
|
||||
```go
|
||||
// Request is an interface implemented any protocol based request generator.
|
||||
type Request interface {
|
||||
Compile(options *ExecuterOptions) error
|
||||
Requests() int
|
||||
GetID() string
|
||||
Match(data map[string]interface{}, matcher *matchers.Matcher) (bool, []string)
|
||||
Extract(data map[string]interface{}, matcher *extractors.Extractor) map[string]struct{}
|
||||
ExecuteWithResults(input string, dynamicValues, previous output.InternalEvent, callback OutputEventCallback) error
|
||||
MakeResultEventItem(wrapped *output.InternalWrappedEvent) *output.ResultEvent
|
||||
MakeResultEvent(wrapped *output.InternalWrappedEvent) []*output.ResultEvent
|
||||
GetCompiledOperators() []*operators.Operators
|
||||
}
|
||||
```
|
||||
|
||||
Many of these methods are similar across protocols while some are very protocol specific.
|
||||
|
||||
A brief overview of the methods is provided below -
|
||||
|
||||
- **Compile** - Compiles the request with provided options.
|
||||
- **Requests** - Returns total requests made.
|
||||
- **GetID** - Returns any ID for the request
|
||||
- **Match** - Used to perform matching for patterns using matchers
|
||||
- **Extract** - Used to perform extraction for patterns using extractors
|
||||
- **ExecuteWithResults** - Request execution function for input.
|
||||
- **MakeResultEventItem** - Creates a single result event for the intermediate `InternalWrappedEvent` output structure.
|
||||
- **MakeResultEvent** - Returns a slice of results based on an `InternalWrappedEvent` internal output event.
|
||||
- **GetCompiledOperators** - Returns the compiled operators for the request.
|
||||
|
||||
`MakeDefaultResultEvent` function can be used as a default for `MakeResultEvent` function when no protocol-specific features need to be implemented for result generation.
|
||||
|
||||
For reference protocol requests implementations, one can look at the below packages -
|
||||
|
||||
1. [pkg/protocols/http](./v2/pkg/protocols/http)
|
||||
2. [pkg/protocols/dns](./v2/pkg/protocols/dns)
|
||||
3. [pkg/protocols/network](./v2/pkg/protocols/network)
|
||||
|
||||
### Executer
|
||||
|
||||
All these different requests interfaces are converted to an Executer which is also an interface defined in `pkg/protocols` which is used during final execution of the template.
|
||||
|
||||
```go
|
||||
// Executer is an interface implemented any protocol based request executer.
|
||||
type Executer interface {
|
||||
Compile() error
|
||||
Requests() int
|
||||
Execute(input string) (bool, error)
|
||||
ExecuteWithResults(input string, callback OutputEventCallback) error
|
||||
}
|
||||
```
|
||||
|
||||
The `ExecuteWithResults` function accepts a callback, which gets provided with results during execution in form of `*output.InternalWrappedEvent` structure.
|
||||
|
||||
The default executer is provided in `pkg/protocols/common/executer` . It takes a list of Requests and relevant `ExecuterOptions` and implements the Executer interface required for template execution. The executer during Template compilation process is created from this package and used as-is.
|
||||
|
||||
A different executer is the Clustered Requests executer which implements the Nuclei Request clustering functionality in `pkg/templates` We have a single HTTP request in cases where multiple templates can be clustered and multiple operator lists to match/extract. The first HTTP request is executed while all the template matcher/extractor are evaluated separately.
|
||||
|
||||
For Workflow execution, a separate RunWorkflow function is used which executes the workflow independently of the template execution.
|
||||
|
||||
With this basic premise set, we can now start exploring the current runner implementation which will also walk us through the architecture of nuclei.
|
||||
|
||||
## internal/runner
|
||||
|
||||
### Template loading
|
||||
|
||||
The first process after all CLI specific initialisation is the loading of template/workflow paths that the user wants to run. This is done by the packages described below.
|
||||
|
||||
#### pkg/catalog
|
||||
|
||||
This package is used to get paths using mixed syntax. It takes a template directory and performs resolving for template paths both from provided template and current user directory.
|
||||
|
||||
The syntax is very versatile and can include filenames, glob patterns, directories, absolute paths, and relative-paths.
|
||||
|
||||
|
||||
|
||||
Next step is the initialisation of the reporting modules which is handled in `pkg/reporting`.
|
||||
|
||||
#### pkg/reporting
|
||||
|
||||
Reporting module contains exporters and trackers as well as a module for deduplication and a module for result formatting.
|
||||
|
||||
Exporters and Trackers are interfaces defined in pkg/reporting.
|
||||
|
||||
```go
|
||||
// Tracker is an interface implemented by an issue tracker
|
||||
type Tracker interface {
|
||||
CreateIssue(event *output.ResultEvent) error
|
||||
}
|
||||
|
||||
// Exporter is an interface implemented by an issue exporter
|
||||
type Exporter interface {
|
||||
Close() error
|
||||
Export(event *output.ResultEvent) error
|
||||
}
|
||||
```
|
||||
|
||||
Exporters include `Elasticsearch`, `markdown`, `sarif` . Trackers include `GitHub` , `Gitlab` and `Jira`.
|
||||
|
||||
Each exporter and trackers implement their own configuration in YAML format and are very modular in nature, so adding new ones is easy.
|
||||
|
||||
|
||||
|
||||
After reading all the inputs from various sources and initialisation other miscellaneous options, the next bit is the output writing which is done using `pkg/output` module.
|
||||
|
||||
#### pkg/output
|
||||
|
||||
Output package implements the output writing functionality for Nuclei.
|
||||
|
||||
Output Writer implements the Writer interface which is called each time a result is found for nuclei.
|
||||
|
||||
```go
|
||||
// Writer is an interface which writes output to somewhere for nuclei events.
|
||||
type Writer interface {
|
||||
Close()
|
||||
Colorizer() aurora.Aurora
|
||||
Write(*ResultEvent) error
|
||||
Request(templateID, url, requestType string, err error)
|
||||
}
|
||||
```
|
||||
|
||||
ResultEvent structure is passed to the Nuclei Output Writer which contains the entire detail of a found result. Various intermediary types like `InternalWrappedEvent` and `InternalEvent` are used throughout nuclei protocols and matchers to describe results in various stages of execution.
|
||||
|
||||
|
||||
|
||||
Interactsh is also initialised if it is not explicitly disabled.
|
||||
|
||||
#### pkg/protocols/common/interactsh
|
||||
|
||||
Interactsh module is used to provide automatic Out-of-Band vulnerability identification in Nuclei.
|
||||
|
||||
It uses two LRU caches, one for storing interactions for request URLs and one for storing requests for interaction URL. These both caches are used to correlated requests received to the Interactsh OOB server and Nuclei Instance. [Interactsh Client](https://github.com/projectdiscovery/interactsh/pkg/client) package does most of the heavy lifting of this module.
|
||||
|
||||
Polling for interactions and server registration only starts when a template uses the interactsh module and is executed by nuclei. After that no registration is required for the entire run.
|
||||
|
||||
|
||||
|
||||
### RunEnumeration
|
||||
|
||||
Next we arrive in the `RunEnumeration` function of the runner.
|
||||
|
||||
`HostErrorsCache` is initialised which is used throughout the run of Nuclei enumeration to keep track of errors per host and skip further requests if the errors are greater than the provided threshold. The functionality for the error tracking cache is defined in [hosterrorscache.go](https://github.com/projectdiscovery/nuclei/blob/master/v2/pkg/protocols/common/hosterrorscache/hosterrorscache.go) and is pretty simplistic in nature.
|
||||
|
||||
Next the `WorkflowLoader` is initialised which used to load workflows. It exists in `v2/pkg/parsers/workflow_loader.go`
|
||||
|
||||
The loader is initialised moving forward which is responsible for Using Catalog, Passed Tags, Filters, Paths, etc. to return compiled `Templates` and `Workflows`.
|
||||
|
||||
#### pkg/catalog/loader
|
||||
|
||||
First the input passed by the user as paths is normalised to absolute paths which is done by the `pkg/catalog` module. Next the path filter module is used to remove the excluded template/workflows paths.
|
||||
|
||||
`pkg/parsers` module's `LoadTemplate`,`LoadWorkflow` functions are used to check if the templates pass the validation + are not excluded via tags/severity/etc. filters. If all checks are passed, then the template/workflow is parsed and returned in a compiled form by the `pkg/templates`'s `Parse` function.
|
||||
|
||||
`Parse` function performs compilation of all the requests in a template + creates Executers from them returning a runnable Template/Workflow structure.
|
||||
|
||||
Clustering module comes in next whose job is to cluster identical HTTP GET requests together (as a lot of the templates perform the same get requests many times, it's a good way to save many requests on large scans with lots of templates).
|
||||
|
||||
### pkg/operators
|
||||
|
||||
Operators package implements all the matching and extracting logic of Nuclei.
|
||||
|
||||
```go
|
||||
// Operators contain the operators that can be applied on protocols
|
||||
type Operators struct {
|
||||
Matchers []*matchers.Matcher
|
||||
Extractors []*extractors.Extractor
|
||||
MatchersCondition string
|
||||
}
|
||||
```
|
||||
|
||||
A protocol only needs to embed the `operators.Operators` type shown above, and it can utilise all the matching/extracting functionality of nuclei.
|
||||
|
||||
```go
|
||||
// MatchFunc performs matching operation for a matcher on model and returns true or false.
|
||||
type MatchFunc func(data map[string]interface{}, matcher *matchers.Matcher) (bool, []string)
|
||||
|
||||
// ExtractFunc performs extracting operation for an extractor on model and returns true or false.
|
||||
type ExtractFunc func(data map[string]interface{}, matcher *extractors.Extractor) map[string]struct{}
|
||||
|
||||
// Execute executes the operators on data and returns a result structure
|
||||
func (operators *Operators) Execute(data map[string]interface{}, match MatchFunc, extract ExtractFunc, isDebug bool) (*Result, bool)
|
||||
```
|
||||
|
||||
The core of this process is the Execute function which takes an input dictionary as well as a Match and Extract function and return a `Result` structure which is used later during nuclei execution to check for results.
|
||||
|
||||
```go
|
||||
// Result is a result structure created from operators running on data.
|
||||
type Result struct {
|
||||
Matched bool
|
||||
Extracted bool
|
||||
Matches map[string][]string
|
||||
Extracts map[string][]string
|
||||
OutputExtracts []string
|
||||
DynamicValues map[string]interface{}
|
||||
PayloadValues map[string]interface{}
|
||||
}
|
||||
```
|
||||
|
||||
The internal logics for matching and extracting for things like words, regexes, jq, paths, etc. is specified in `pkg/operators/matchers`, `pkg/operators/extractors`. Those packages should be investigated for further look into the topic.
|
||||
|
||||
|
||||
### Template Execution
|
||||
|
||||
`pkg/core` provides the engine mechanism which runs the templates/workflows on inputs. It exposes an `Execute` function which does the task of execution while also doing template clustering. The clustering can also be disabled optionally by the user.
|
||||
|
||||
An example of using the core engine is provided below.
|
||||
|
||||
```go
|
||||
engine := core.New(r.options)
|
||||
engine.SetExecuterOptions(executerOpts)
|
||||
results := engine.ExecuteWithOpts(finalTemplates, r.hmapInputProvider, true)
|
||||
```
|
||||
|
||||
### Using Nuclei From Go Code
|
||||
|
||||
An example of using Nuclei From Go Code to run templates on targets is provided below.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"go.uber.org/ratelimit"
|
||||
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/core"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/core/inputs"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/hosterrorscache"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolstate"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/reporting"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cache := hosterrorscache.New(30, hosterrorscache.DefaultMaxHostsCount)
|
||||
defer cache.Close()
|
||||
|
||||
mockProgress := &testutils.MockProgressClient{}
|
||||
reportingClient, _ := reporting.New(&reporting.Options{}, "")
|
||||
defer reportingClient.Close()
|
||||
|
||||
outputWriter := testutils.NewMockOutputWriter()
|
||||
outputWriter.WriteCallback = func(event *output.ResultEvent) {
|
||||
fmt.Printf("Got Result: %v\n", event)
|
||||
}
|
||||
|
||||
defaultOpts := types.DefaultOptions()
|
||||
protocolstate.Init(defaultOpts)
|
||||
protocolinit.Init(defaultOpts)
|
||||
|
||||
defaultOpts.Templates = goflags.StringSlice{"dns/cname-service-detection.yaml"}
|
||||
defaultOpts.ExcludeTags = config.ReadIgnoreFile().Tags
|
||||
|
||||
interactOpts := interactsh.NewDefaultOptions(outputWriter, reportingClient, mockProgress)
|
||||
interactClient, err := interactsh.New(interactOpts)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create interact client: %s\n", err)
|
||||
}
|
||||
defer interactClient.Close()
|
||||
|
||||
home, _ := os.UserHomeDir()
|
||||
catalog := catalog.New(path.Join(home, "nuclei-templates"))
|
||||
executerOpts := protocols.ExecuterOptions{
|
||||
Output: outputWriter,
|
||||
Options: defaultOpts,
|
||||
Progress: mockProgress,
|
||||
Catalog: catalog,
|
||||
IssuesClient: reportingClient,
|
||||
RateLimiter: ratelimit.New(150),
|
||||
Interactsh: interactClient,
|
||||
HostErrorsCache: cache,
|
||||
Colorizer: aurora.NewAurora(true),
|
||||
}
|
||||
engine := core.New(defaultOpts)
|
||||
engine.SetExecuterOptions(executerOpts)
|
||||
|
||||
workflowLoader, err := parsers.NewLoader(&executerOpts)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create workflow loader: %s\n", err)
|
||||
}
|
||||
executerOpts.WorkflowLoader = workflowLoader
|
||||
|
||||
store, err := loader.New(loader.NewConfig(defaultOpts, catalog, executerOpts))
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create loader client: %s\n", err)
|
||||
}
|
||||
store.Load()
|
||||
|
||||
input := &inputs.SimpleInputProvider{Inputs: []string{"docs.hackerone.com"}}
|
||||
_ = engine.Execute(store.Templates(), input)
|
||||
}
|
||||
```
|
||||
|
||||
### Adding a New Protocol
|
||||
|
||||
Protocols form the core of Nuclei Engine. All the request types like `http`, `dns`, etc. are implemented in form of protocol requests.
|
||||
|
||||
A protocol must implement the `Protocol` and `Request` interfaces described above in `pkg/protocols`. We'll take the example of an existing protocol implementation - websocket for this short reference around Nuclei internals.
|
||||
|
||||
The code for the websocket protocol is contained in `pkg/protocols/others/websocket`.
|
||||
|
||||
Below a high level skeleton of the websocket implementation is provided with all the important parts present.
|
||||
|
||||
```go
|
||||
package websocket
|
||||
|
||||
// Request is a request for the Websocket protocol
|
||||
type Request struct {
|
||||
// Operators for the current request go here.
|
||||
operators.Operators `yaml:",inline,omitempty"`
|
||||
CompiledOperators *operators.Operators `yaml:"-"`
|
||||
|
||||
// description: |
|
||||
// Address contains address for the request
|
||||
Address string `yaml:"address,omitempty" jsonschema:"title=address for the websocket request,description=Address contains address for the request"`
|
||||
|
||||
// declarations here
|
||||
}
|
||||
|
||||
// Compile compiles the request generators preparing any requests possible.
|
||||
func (r *Request) Compile(options *protocols.ExecuterOptions) error {
|
||||
r.options = options
|
||||
|
||||
// request compilation here as well as client creation
|
||||
|
||||
if len(r.Matchers) > 0 || len(r.Extractors) > 0 {
|
||||
compiled := &r.Operators
|
||||
if err := compiled.Compile(); err != nil {
|
||||
return errors.Wrap(err, "could not compile operators")
|
||||
}
|
||||
r.CompiledOperators = compiled
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Requests returns the total number of requests the rule will perform
|
||||
func (r *Request) Requests() int {
|
||||
if r.generator != nil {
|
||||
return r.generator.NewIterator().Total()
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// GetID returns the ID for the request if any.
|
||||
func (r *Request) GetID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
|
||||
func (r *Request) ExecuteWithResults(input string, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
|
||||
// payloads init here
|
||||
if err := r.executeRequestWithPayloads(input, hostname, value, previous, callback); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
|
||||
func (r *Request) executeRequestWithPayloads(input, hostname string, dynamicValues, previous output.InternalEvent, callback protocols.OutputEventCallback) error {
|
||||
header := http.Header{}
|
||||
|
||||
// make the actual request here after setting all options
|
||||
|
||||
event := eventcreator.CreateEventWithAdditionalOptions(r, data, r.options.Options.Debug || r.options.Options.DebugResponse, func(internalWrappedEvent *output.InternalWrappedEvent) {
|
||||
internalWrappedEvent.OperatorsResult.PayloadValues = payloadValues
|
||||
})
|
||||
if r.options.Options.Debug || r.options.Options.DebugResponse {
|
||||
responseOutput := responseBuilder.String()
|
||||
gologger.Debug().Msgf("[%s] Dumped Websocket response for %s", r.options.TemplateID, input)
|
||||
gologger.Print().Msgf("%s", responsehighlighter.Highlight(event.OperatorsResult, responseOutput, r.options.Options.NoColor))
|
||||
}
|
||||
|
||||
callback(event)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent) *output.ResultEvent {
|
||||
data := &output.ResultEvent{
|
||||
TemplateID: types.ToString(r.options.TemplateID),
|
||||
TemplatePath: types.ToString(r.options.TemplatePath),
|
||||
// ... setting more values for result event
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// Match performs matching operation for a matcher on model and returns:
|
||||
// true and a list of matched snippets if the matcher type is supports it
|
||||
// otherwise false and an empty string slice
|
||||
func (r *Request) Match(data map[string]interface{}, matcher *matchers.Matcher) (bool, []string) {
|
||||
return protocols.MakeDefaultMatchFunc(data, matcher)
|
||||
}
|
||||
|
||||
// Extract performs extracting operation for an extractor on model and returns true or false.
|
||||
func (r *Request) Extract(data map[string]interface{}, matcher *extractors.Extractor) map[string]struct{} {
|
||||
return protocols.MakeDefaultExtractFunc(data, matcher)
|
||||
}
|
||||
|
||||
// MakeResultEvent creates a result event from internal wrapped event
|
||||
func (r *Request) MakeResultEvent(wrapped *output.InternalWrappedEvent) []*output.ResultEvent {
|
||||
return protocols.MakeDefaultResultEvent(r, wrapped)
|
||||
}
|
||||
|
||||
// GetCompiledOperators returns a list of the compiled operators
|
||||
func (r *Request) GetCompiledOperators() []*operators.Operators {
|
||||
return []*operators.Operators{r.CompiledOperators}
|
||||
}
|
||||
|
||||
// Type returns the type of the protocol request
|
||||
func (r *Request) Type() templateTypes.ProtocolType {
|
||||
return templateTypes.WebsocketProtocol
|
||||
}
|
||||
```
|
||||
|
||||
Almost all of these protocols have boilerplate functions for which default implementations have been provided in the `providers` package. Examples are the implementation of `Match`, `Extract`, `MakeResultEvent`, GetCompiledOperators`, etc. which are almost same throughout Nuclei protocols code. It is enough to copy-paste them unless customization is required.
|
||||
|
||||
`eventcreator` package offers `CreateEventWithAdditionalOptions` function which can be used to create result events after doing request execution.
|
||||
|
||||
Step by step description of how to add a new protocol to Nuclei -
|
||||
|
||||
1. Add the protocol implementation in `pkg/protocols` directory. If it's a small protocol with fewer options, considering adding it to the `pkg/protocols/others` directory. Add the enum for the new protocol to `v2/pkg/templates/types/types.go`.
|
||||
|
||||
2. Add the protocol request structure to the `Template` structure fields. This is done in `pkg/templates/templates.go` with the corresponding import line.
|
||||
|
||||
```go
|
||||
|
||||
import (
|
||||
...
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/others/websocket"
|
||||
)
|
||||
|
||||
// Template is a YAML input file which defines all the requests and
|
||||
// other metadata for a template.
|
||||
type Template struct {
|
||||
...
|
||||
// description: |
|
||||
// Websocket contains the Websocket request to make in the template.
|
||||
RequestsWebsocket []*websocket.Request `yaml:"websocket,omitempty" json:"websocket,omitempty" jsonschema:"title=websocket requests to make,description=Websocket requests to make for the template"`
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Also add the protocol case to the `Type` function as well as the `TemplateTypes` array in the same `templates.go` file.
|
||||
|
||||
```go
|
||||
// TemplateTypes is a list of accepted template types
|
||||
var TemplateTypes = []string{
|
||||
...
|
||||
"websocket",
|
||||
}
|
||||
|
||||
// Type returns the type of the template
|
||||
func (t *Template) Type() templateTypes.ProtocolType {
|
||||
...
|
||||
case len(t.RequestsWebsocket) > 0:
|
||||
return templateTypes.WebsocketProtocol
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Add the protocol request to the `Requests` function and `compileProtocolRequests` function in the `compile.go` file in same directory.
|
||||
|
||||
```go
|
||||
|
||||
// Requests return the total request count for the template
|
||||
func (template *Template) Requests() int {
|
||||
return len(template.RequestsDNS) +
|
||||
...
|
||||
len(template.RequestsSSL) +
|
||||
len(template.RequestsWebsocket)
|
||||
}
|
||||
|
||||
|
||||
// compileProtocolRequests compiles all the protocol requests for the template
|
||||
func (template *Template) compileProtocolRequests(options protocols.ExecuterOptions) error {
|
||||
...
|
||||
|
||||
case len(template.RequestsWebsocket) > 0:
|
||||
requests = template.convertRequestToProtocolsRequest(template.RequestsWebsocket)
|
||||
}
|
||||
template.Executer = executer.NewExecuter(requests, &options)
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- [v2/pkg/reporting](./v2/pkg/reporting) - Reporting modules for nuclei.
|
||||
- [v2/pkg/reporting/exporters/sarif](./v2/pkg/reporting/exporters/sarif) - Sarif Result Exporter
|
||||
- [v2/pkg/reporting/exporters/markdown](./v2/pkg/reporting/exporters/markdown) - Markdown Result Exporter
|
||||
- [v2/pkg/reporting/exporters/es](./v2/pkg/reporting/exporters/es) - Elasticsearch Result Exporter
|
||||
- [v2/pkg/reporting/dedupe](./v2/pkg/reporting/dedupe) - Dedupe module for Results
|
||||
- [v2/pkg/reporting/trackers/gitlab](./v2/pkg/reporting/trackers/gitlab) - Gitlab Issue Tracker Exporter
|
||||
- [v2/pkg/reporting/trackers/jira](./v2/pkg/reporting/trackers/jira) - Jira Issue Tracker Exporter
|
||||
- [v2/pkg/reporting/trackers/github](./v2/pkg/reporting/trackers/github) - GitHub Issue Tracker Exporter
|
||||
- [v2/pkg/reporting/format](./v2/pkg/reporting/format) - Result Formatting Functions
|
||||
- [v2/pkg/parsers](./v2/pkg/parsers) - Implements template as well as workflow loader for initial template discovery, validation and - loading.
|
||||
- [v2/pkg/types](./v2/pkg/types) - Contains CLI options as well as misc helper functions.
|
||||
- [v2/pkg/progress](./v2/pkg/progress) - Progress tracking
|
||||
- [v2/pkg/operators](./v2/pkg/operators) - Operators for Nuclei
|
||||
- [v2/pkg/operators/common/dsl](./v2/pkg/operators/common/dsl) - DSL functions for Nuclei YAML Syntax
|
||||
- [v2/pkg/operators/matchers](./v2/pkg/operators/matchers) - Matchers implementation
|
||||
- [v2/pkg/operators/extractors](./v2/pkg/operators/extractors) - Extractors implementation
|
||||
- [v2/pkg/catalog](./v2/pkg/catalog) - Template loading from disk helpers
|
||||
- [v2/pkg/catalog/config](./v2/pkg/catalog/config) - Internal configuration management
|
||||
- [v2/pkg/catalog/loader](./v2/pkg/catalog/loader) - Implements loading and validation of templates and workflows.
|
||||
- [v2/pkg/catalog/loader/filter](./v2/pkg/catalog/loader/filter) - Filter filters templates based on tags and paths
|
||||
- [v2/pkg/output](./v2/pkg/output) - Output module for nuclei
|
||||
- [v2/pkg/workflows](./v2/pkg/workflows) - Workflow execution logic + declarations
|
||||
- [v2/pkg/utils](./v2/pkg/utils) - Utility functions
|
||||
- [v2/pkg/model](./v2/pkg/model) - Template Info + misc
|
||||
- [v2/pkg/templates](./v2/pkg/templates) - Templates core starting point
|
||||
- [v2/pkg/templates/cache](./v2/pkg/templates/cache) - Templates cache
|
||||
- [v2/pkg/protocols](./v2/pkg/protocols) - Protocol Specification
|
||||
- [v2/pkg/protocols/file](./v2/pkg/protocols/file) - File protocol
|
||||
- [v2/pkg/protocols/network](./v2/pkg/protocols/network) - Network protocol
|
||||
- [v2/pkg/protocols/common/expressions](./v2/pkg/protocols/common/expressions) - Expression evaluation + Templating Support
|
||||
- [v2/pkg/protocols/common/interactsh](./v2/pkg/protocols/common/interactsh) - Interactsh integration
|
||||
- [v2/pkg/protocols/common/generators](./v2/pkg/protocols/common/generators) - Payload support for Requests (Sniper, etc.)
|
||||
- [v2/pkg/protocols/common/executer](./v2/pkg/protocols/common/executer) - Default Template Executer
|
||||
- [v2/pkg/protocols/common/replacer](./v2/pkg/protocols/common/replacer) - Template replacement helpers
|
||||
- [v2/pkg/protocols/common/helpers/eventcreator](./v2/pkg/protocols/common/helpers/eventcreator) - Result event creator
|
||||
- [v2/pkg/protocols/common/helpers/responsehighlighter](./v2/pkg/protocols/common/helpers/responsehighlighter) - Debug response highlighter
|
||||
- [v2/pkg/protocols/common/helpers/deserialization](./v2/pkg/protocols/common/helpers/deserialization) - Deserialization helper functions
|
||||
- [v2/pkg/protocols/common/hosterrorscache](./v2/pkg/protocols/common/hosterrorscache) - Host errors cache for tracking erroring hosts
|
||||
- [v2/pkg/protocols/offlinehttp](./v2/pkg/protocols/offlinehttp) - Offline http protocol
|
||||
- [v2/pkg/protocols/http](./v2/pkg/protocols/http) - HTTP protocol
|
||||
- [v2/pkg/protocols/http/race](./v2/pkg/protocols/http/race) - HTTP Race Module
|
||||
- [v2/pkg/protocols/http/raw](./v2/pkg/protocols/http/raw) - HTTP Raw Request Support
|
||||
- [v2/pkg/protocols/headless](./v2/pkg/protocols/headless) - Headless Module
|
||||
- [v2/pkg/protocols/headless/engine](./v2/pkg/protocols/headless/engine) - Internal Headless implementation
|
||||
- [v2/pkg/protocols/dns](./v2/pkg/protocols/dns) - DNS protocol
|
||||
- [v2/pkg/projectfile](./v2/pkg/projectfile) - Project File Implementation
|
||||
|
||||
### Notes
|
||||
|
||||
1. The matching as well as interim output functionality is a bit complex, we should simplify it a bit as well.
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
FROM golang:1.15-alpine as build-env
|
||||
RUN GO111MODULE=on go get -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei
|
||||
FROM golang:1.17.7-alpine as build-env
|
||||
RUN go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk add --no-cache bind-tools ca-certificates
|
||||
FROM alpine:3.15.0
|
||||
RUN apk add --no-cache bind-tools ca-certificates chromium
|
||||
COPY --from=build-env /go/bin/nuclei /usr/local/bin/nuclei
|
||||
ENTRYPOINT ["nuclei"]
|
||||
@@ -7,12 +7,14 @@
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://goreportcard.com/report/github.com/projectdiscovery/nuclei"><img src="https://goreportcard.com/badge/github.com/projectdiscovery/nuclei"></a>
|
||||
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat"></a>
|
||||
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei"></a>
|
||||
<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>
|
||||
<a href="https://discord.gg/KECAGdH"><img src="https://img.shields.io/discord/695645237418131507.svg?logo=discord"></a>
|
||||
<a href="https://github.com/projectdiscovery/nuclei/actions/workflows/build.yaml"><img src="https://github.com/projectdiscovery/nuclei/actions/workflows/build.yaml/badge.svg?branch=master"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -22,15 +24,20 @@
|
||||
<a href="#for-developers-and-organisations">For Developers</a> •
|
||||
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/">Documentation</a> •
|
||||
<a href="#credits">Credits</a> •
|
||||
<a href="#license">License</a> •
|
||||
<a href="https://discord.gg/KECAGdH">Join Discord</a>
|
||||
<a href="https://nuclei.projectdiscovery.io/faq/nuclei/">FAQs</a> •
|
||||
<a href="https://discord.gg/projectdiscovery">Join Discord</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README.md">English</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_CN.md">中文</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
Nuclei is used to send requests across targets based on a template leading to zero false positives and providing fast scanning on large number of hosts. Nuclei offers scanning for a variety of protocols including TCP, DNS, HTTP, File, etc. With powerful and flexible templating, all kinds of security checks can be modelled with Nuclei.
|
||||
Nuclei is used to send requests across targets based on a template, leading to zero false positives and providing fast scanning on a large number of hosts. Nuclei offers scanning for a variety of protocols, including TCP, DNS, HTTP, SSL, File, Whois, Websocket, Headless etc. With powerful and flexible templating, Nuclei can be used to model all kinds of security checks.
|
||||
|
||||
We have a [dedicated repository](https://github.com/projectdiscovery/nuclei-templates) that houses various type of vulnerability templates contributed by **more than 100** security researchers and engineers. It is preloaded with ready to use templates using `-update-templates` flag.
|
||||
We have a [dedicated repository](https://github.com/projectdiscovery/nuclei-templates) that houses various type of vulnerability templates contributed by **more than 300** security researchers and engineers.
|
||||
|
||||
|
||||
|
||||
@@ -44,34 +51,182 @@ We have a [dedicated repository](https://github.com/projectdiscovery/nuclei-temp
|
||||
|
||||
# Install Nuclei
|
||||
|
||||
Nuclei requires **go1.17** to install successfully. Run the following command to install the latest version -
|
||||
|
||||
```sh
|
||||
▶ GO111MODULE=on go get -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei
|
||||
go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
**More installation [methods can be found here](https://nuclei.projectdiscovery.io/nuclei/get-started/#nuclei-installation).**
|
||||
**More installation [methods can be found here](https://nuclei.projectdiscovery.io/nuclei/get-started/).**
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
### Download Templates
|
||||
### Nuclei Templates
|
||||
|
||||
You can download and update the nuclei templates using <ins>*update-templates*</ins> flag of nuclei that downloads all the available **nuclei-templates** from [Github project](https://github.com/projectdiscovery/nuclei-templates), a community curated list of templates that are ready to use.
|
||||
Nuclei has built-in support for automatic template download/update as default since version [v2.5.2](https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2). [**Nuclei-Templates**](https://github.com/projectdiscovery/nuclei-templates) project provides a community-contributed list of ready-to-use templates that is constantly updated.
|
||||
|
||||
`▶ nuclei -update-templates`
|
||||
You may still use the `update-templates` flag to update the nuclei templates at any time; You can write your own checks for your individual workflow and needs following Nuclei's [templating guide](https://nuclei.projectdiscovery.io/templating-guide/).
|
||||
|
||||
Nuclei is designed to used with custom templates according to the target and workflow, you can write your own checks for your specific workflow and needs, please refer to nuclei [templating guide](https://nuclei.projectdiscovery.io/templating-guide/) to write your own custom templates.
|
||||
The YAML DSL reference syntax is available [here](SYNTAX-REFERENCE.md).
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Running Nuclei
|
||||
|
||||
Scanning for CVEs on given list of URLs.
|
||||
### Usage
|
||||
|
||||
```sh
|
||||
▶ nuclei -l target_urls.txt -t cves/
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
This will display help for the tool. Here are all the switches it supports.
|
||||
|
||||
|
||||
```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)
|
||||
-resume Resume scan using resume.cfg (clustering will be disabled)
|
||||
|
||||
TEMPLATES:
|
||||
-nt, -new-templates run only new templates added in latest nuclei-templates release
|
||||
-t, -templates string[] list of template or template directory to run (comma-separated, file)
|
||||
-tu, -template-url string[] list of template urls to run (comma-separated, file)
|
||||
-w, -workflows string[] list of workflow or workflow directory to run (comma-separated, file)
|
||||
-wu, -workflow-url string[] list of workflow urls to run (comma-separated, file)
|
||||
-validate validate the passed templates to nuclei
|
||||
-tl list all available 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)
|
||||
-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)
|
||||
-s, -severity value[] templates to run based on severity. Possible values: info, low, medium, high, critical
|
||||
-es, -exclude-severity value[] templates to exclude based on severity. Possible values: info, low, medium, high, critical
|
||||
-pt, -type value[] templates to run based on protocol type. Possible values: dns, file, http, headless, network, workflow, ssl, websocket, whois
|
||||
-ept, -exclude-type value[] templates to exclude based on protocol type. Possible values: dns, file, http, headless, network, workflow, ssl, websocket, whois
|
||||
|
||||
OUTPUT:
|
||||
-o, -output string output file to write found issues/vulnerabilities
|
||||
-silent display findings only
|
||||
-nc, -no-color disable output content coloring (ANSI escape codes)
|
||||
-json write output in JSONL(ines) format
|
||||
-irr, -include-rr include request/response pairs in the JSONL output (for findings only)
|
||||
-nm, -no-meta disable printing result metadata in cli output
|
||||
-nts, -no-timestamp disable 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
|
||||
|
||||
CONFIGURATIONS:
|
||||
-config string path to the nuclei configuration file
|
||||
-rc, -report-config string nuclei reporting module configuration file
|
||||
-H, -header string[] custom headers in header:value format
|
||||
-V, -var value custom vars in var=value format
|
||||
-r, -resolvers string file containing resolver list for nuclei
|
||||
-sr, -system-resolvers use system DNS resolving as error fallback
|
||||
-passive enable passive HTTP response processing mode
|
||||
-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
|
||||
-ztls Use ztls library with autofallback to standard one for tls13
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
-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)
|
||||
-hc, -headless-concurrency int maximum number of headless templates to be executed in parallel (default 10)
|
||||
|
||||
OPTIMIZATIONS:
|
||||
-timeout int time to wait in seconds before timeout (default 5)
|
||||
-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)
|
||||
-project use a project folder to avoid sending same request multiple times
|
||||
-project-path string set a specific project path
|
||||
-spm, -stop-at-first-path stop processing HTTP requests after the first match (may break template/workflow logic)
|
||||
-stream stream mode - start elaborating without sorting the input
|
||||
|
||||
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
|
||||
|
||||
DEBUG:
|
||||
-debug show all requests and responses
|
||||
-debug-req show all sent requests
|
||||
-debug-resp show all received responses
|
||||
-p, -proxy string[] List of HTTP(s)/SOCKS5 proxy to use (comma separated or file input)
|
||||
-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
|
||||
-v, -verbose show verbose output
|
||||
-vv display templates loaded for scan
|
||||
-tv, -templates-version shows the version of the installed nuclei-templates
|
||||
|
||||
UPDATE:
|
||||
-update update nuclei engine to the latest released version
|
||||
-ut, -update-templates update nuclei-templates to latest released version
|
||||
-ud, -update-directory string overwrite the default directory to install nuclei-templates
|
||||
-duc, -disable-update-check disable automatic nuclei/templates update check
|
||||
|
||||
STATISTICS:
|
||||
-stats display statistics about the running scan
|
||||
-sj, -stats-json write statistics data to an output file 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)
|
||||
```
|
||||
|
||||
### Running Nuclei
|
||||
|
||||
Scanning target domain with [community-curated](https://github.com/projectdiscovery/nuclei-templates) nuclei templates.
|
||||
|
||||
```sh
|
||||
nuclei -u https://example.com
|
||||
```
|
||||
|
||||
Scanning target URLs with [community-curated](https://github.com/projectdiscovery/nuclei-templates) nuclei templates.
|
||||
|
||||
```sh
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
Example of `urls.txt`:
|
||||
|
||||
```yaml
|
||||
http://example.com
|
||||
http://app.example.com
|
||||
http://test.example.com
|
||||
http://uat.example.com
|
||||
```
|
||||
|
||||
**More detailed examples of running nuclei can be found [here](https://nuclei.projectdiscovery.io/nuclei/get-started/#running-nuclei).**
|
||||
@@ -92,9 +247,9 @@ Nuclei offers great number of features that are helpful for security engineers t
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
**For bugbounty hunters:**
|
||||
**For Bug Bounty hunters:**
|
||||
|
||||
Nuclei allows you to customise your testing approach with your own suite of checks and easily run across your bug bounty programs. Moroever, Nuclei can be easily integrated into any continuous scanning workflow.
|
||||
Nuclei allows you to customise your testing approach with your own suite of checks and easily run across your bug bounty programs. Moreover, Nuclei can be easily integrated into any continuous scanning workflow.
|
||||
|
||||
- Designed to be easily integrated into other tool workflow.
|
||||
- Can process thousands of hosts in few minutes.
|
||||
@@ -110,11 +265,11 @@ Please check our other open-source projects that might fit into your bug bounty
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
**For pentesters:**
|
||||
**For Penetration Testers:**
|
||||
|
||||
Nuclei immensely improve how you approach security assessment by augmenting the manual repetitve processes. Consultancies are already converting their manual assessment steps with Nuclei, it allows them to run set of their custom assessment approach across thousands of hosts in an automated manner.
|
||||
Nuclei immensely improve how you approach security assessment by augmenting the manual, repetitive processes. Consultancies are already converting their manual assessment steps with Nuclei, it allows them to run set of their custom assessment approach across thousands of hosts in an automated manner.
|
||||
|
||||
Pen-testers get the full power of our public templates and customization capabilities to speed-up their assessment process, and specifically with the regression cycle where you can easily verify the fix.
|
||||
Pen-testers get the full power of our public templates and customization capabilities to speed up their assessment process, and specifically with the regression cycle where you can easily verify the fix.
|
||||
|
||||
- Easily create your compliance, standards suite (e.g. OWASP Top 10) checklist.
|
||||
- With capabilities like [fuzz](https://nuclei.projectdiscovery.io/templating-guide/#advance-fuzzing) and [workflows](https://nuclei.projectdiscovery.io/templating-guide/#workflows), complex manual steps and repetitive assessment can be easily automated with Nuclei.
|
||||
@@ -127,7 +282,7 @@ Pen-testers get the full power of our public templates and customization capabil
|
||||
|
||||
# For Developers and Organisations
|
||||
|
||||
Nuclei is built with simplicity in mind, with the community backed templates by hundreds of security researchers, it allows you to stay updated with latest security threats using continuous Nuclei scanning on the hosts. It is designed to be easily integrated into regression tests cycle, to verify the fixes and eliminate vulnerabilities from occuring in future.
|
||||
Nuclei is built with simplicity in mind, with the community backed templates by hundreds of security researchers, it allows you to stay updated with the latest security threats using continuous Nuclei scanning on the hosts. It is designed to be easily integrated into regression tests cycle, to verify the fixes and eliminate vulnerabilities from occurring in the future.
|
||||
|
||||
- **CI/CD:** Engineers are already utilising Nuclei within their CI/CD pipeline, it allows them to constantly monitor their staging and production environments with customised templates.
|
||||
- **Continuous Regression Cycle:** With Nuclei, you can create your custom template on every new identified vulnerability and put into Nuclei engine to eliminate in the continuous regression cycle.
|
||||
@@ -144,11 +299,15 @@ We have [a discussion thread around this](https://github.com/projectdiscovery/nu
|
||||
|
||||
### Resources
|
||||
|
||||
|
||||
- [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
|
||||
|
||||
@@ -161,5 +320,5 @@ Thanks to all the amazing community [contributors for sending PRs](https://githu
|
||||
Nuclei is distributed under [MIT License](https://github.com/projectdiscovery/nuclei/blob/master/LICENSE.md)
|
||||
|
||||
<h1 align="left">
|
||||
<a href="https://discord.gg/KECAGdH"><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>
|
||||
<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>
|
||||
+224
-174
@@ -1,253 +1,303 @@
|
||||
<h1 align="center">
|
||||
<img src="static/nuclei-logo.png" alt="nuclei" width="200px"></a>
|
||||
<br>
|
||||
<a href="https://nuclei.projectdiscovery.io"><img src="static/nuclei-logo.png" width="200px" alt="Nuclei"></a>
|
||||
</h1>
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://goreportcard.com/report/github.com/projectdiscovery/nuclei)
|
||||
[](https://github.com/projectdiscovery/nuclei/issues)
|
||||
[](https://github.com/projectdiscovery/nuclei/releases)
|
||||
[](https://twitter.com/pdnuclei)
|
||||
[](https://hub.docker.com/r/projectdiscovery/nuclei)
|
||||
[](https://discord.gg/KECAGdH)
|
||||
<h4 align="center">基于YAML语法模板的定制化快速漏洞扫描器</h4>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://nuclei.projectdiscovery.io/templating-guide/" target="_blank"><img src="static/read-the-docs-button.png" height="42px"/></center></a> <a href="https://github.com/projectdiscovery/nuclei-templates" target="_blank"><img src="static/download-templates-button.png" height="42px"/></a>
|
||||
<a href="https://goreportcard.com/report/github.com/projectdiscovery/nuclei"><img src="https://goreportcard.com/badge/github.com/projectdiscovery/nuclei"></a>
|
||||
<a href="https://github.com/projectdiscovery/nuclei/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat"></a>
|
||||
<a href="https://github.com/projectdiscovery/nuclei/releases"><img src="https://img.shields.io/github/release/projectdiscovery/nuclei"></a>
|
||||
<a href="https://twitter.com/pdnuclei"><img src="https://img.shields.io/twitter/follow/pdnuclei.svg?logo=twitter"></a>
|
||||
<a href="https://discord.gg/projectdiscovery"><img src="https://img.shields.io/discord/695645237418131507.svg?logo=discord"></a>
|
||||
<a href="https://github.com/projectdiscovery/nuclei/actions/workflows/build-test.yml"><img src="https://github.com/projectdiscovery/nuclei/actions/workflows/build-test.yml/badge.svg?branch=master"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#工作流程">工作流程</a> •
|
||||
<a href="#安装Nuclei">安装</a> •
|
||||
<a href="#对于安全工程师">对于安全工程师</a> •
|
||||
<a href="#对于开发者和组织">对于开发者</a> •
|
||||
<a href="https://nuclei.projectdiscovery.io/nuclei/get-started/">文档</a> •
|
||||
<a href="#c致谢">致谢</a> •
|
||||
<a href="https://nuclei.projectdiscovery.io/faq/nuclei/">常见问题</a> •
|
||||
<a href="https://discord.gg/projectdiscovery">加入Discord</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README.md">English</a> •
|
||||
<a href="https://github.com/projectdiscovery/nuclei/blob/master/README_CN.md">中文</a>
|
||||
</p>
|
||||
|
||||
Nuclei是一个基于模板的、可配置攻击目标的扫描快速工具,同时还提供了强大的可扩展性和易用性。
|
||||
---
|
||||
|
||||
基于模板的nuclei被用来发送请求给目标,有着实现零误报的优点,并且可以对已知的路径进行有效的扫描。nuclei的主要用于在初期的探测阶段快速地对已知的且易于检测的漏洞或者CVE进行扫描。如果存在WAF的话,nuclei使用[retryablehttp-go库](https://github.com/projectdiscovery/retryablehttp-go)来处理各种错误,并且重新尝试攻击,这也是我们自定义功能的核心模块之一。
|
||||
Nuclei使用零误报的定制模板向目标发送请求,同时可以对大量主机进行快速扫描。Nuclei提供TCP、DNS、HTTP、FILE等各类协议的扫描,通过强大且灵活的模板,可以使用Nuclei模拟各种安全检查。
|
||||
|
||||
我们也维护一个具有各个类型的模板的[开源库](https://github.com/projectdiscovery/nuclei-templates),我们希望你也能贡献一些模板,贡献的这些模板最好是有效的,并且能允许每个人基于你的模板重新构建。查看[**nuclei.projectdiscovery.io**](https://nuclei.projectdiscovery.io/templating-guide/)这个网站去学习制作模板的入门知识。
|
||||
我们的[模板仓库](https://github.com/projectdiscovery/nuclei-templates)包含**超过200**安全研究员和工程师提供的模板。
|
||||
|
||||
## 目录
|
||||
|
||||
- [目录](#目录)
|
||||
- [功能](#功能)
|
||||
- [安装](#安装)
|
||||
- [Nuclei模板](#nuclei模板)
|
||||
- [用法](#用法)
|
||||
- [运行Nuclei](#运行nuclei)
|
||||
- [排除模板](#排除模板)
|
||||
- [致谢](#致谢)
|
||||
|
||||
## 功能
|
||||
## 工作流程
|
||||
|
||||
<h1 align="left">
|
||||
<img src="static/nuclei-run.png" alt="nuclei" width="700px"></a>
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
- 有着易于开发的、简单的、模块化的代码库
|
||||
- 使用了基于模板的引擎,运行速度极快,可以修改所以配置
|
||||
- 可以对特殊情况处理、重试、绕过等,可以绕过WAF
|
||||
- 智能匹配,零误报
|
||||
<h3 align="center">
|
||||
<img src="static/nuclei-flow.jpg" alt="nuclei-flow" width="700px"></a>
|
||||
</h3>
|
||||
|
||||
## 安装
|
||||
|
||||
### 二进制文件安装
|
||||
# 安装Nuclei
|
||||
|
||||
二进制文件安装很简单,你可以从[Releases](https://github.com/projectdiscovery/nuclei/releases/)页面下载已经构建好的二进制文件压缩包,使用解压工具提取下载的压缩包,并将解压的文件夹移动到$PATH目录,就可以直接使用了。
|
||||
Nuclei需要**go1.17**才能安装成功。执行下列命令安装最新版本的Nuclei
|
||||
|
||||
```sh
|
||||
Download latest binary from https://github.com/projectdiscovery/nuclei/releases
|
||||
|
||||
▶ tar -xzvf nuclei-linux-amd64.tar.gz
|
||||
▶ mv nuclei /usr/local/bin/
|
||||
▶ nuclei -version
|
||||
go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latest
|
||||
```
|
||||
|
||||
### 源码安装
|
||||
**更多的安装方式 [请点击此处](https://nuclei.projectdiscovery.io/nuclei/get-started/).**
|
||||
|
||||
nuclei需要**go1.14+**才能成功安装,运行以下命令获取repo
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```sh
|
||||
▶ GO111MODULE=on go get -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei
|
||||
```
|
||||
### Nuclei模板
|
||||
|
||||
### GitHub安装
|
||||
自从[v2.5.2]((https://github.com/projectdiscovery/nuclei/releases/tag/v2.5.2))起,Nuclei就内置了自动下载和更新模板的功能。[**Nuclei模板**](https://github.com/projectdiscovery/nuclei-templates)仓库随时更新社区中可用的模板列表。
|
||||
|
||||
```sh
|
||||
▶ git clone https://github.com/projectdiscovery/nuclei.git; cd nuclei/v2/cmd/nuclei/; go build; mv nuclei /usr/local/bin/; nuclei -version
|
||||
```
|
||||
您仍然可以随时使用`update-templates`命令更新模板,您可以根据[模板指南](https://nuclei.projectdiscovery.io/templating-guide/)编写您自己的模板。
|
||||
|
||||
## Nuclei模板
|
||||
YAML的语法规范在[这里](SYNTAX-REFERENCE.md)。
|
||||
|
||||
你可以使用`update-templates`来下载和更新nuclei模板,该命令会从unclei的[模板库]()中下载最新版本,这个由社区来维护的库是可以随时使用的。
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
```sh
|
||||
▶ nuclei -update-templates
|
||||
```
|
||||
|
||||
此外您可以根据自己的工作情况或者需求编写模板,请参阅**nuclei[模板向导](https://nuclei.projectdiscovery.io/templating-guide/)去编写自定义模板**
|
||||
|
||||
## 用法
|
||||
### 用法
|
||||
|
||||
```sh
|
||||
nuclei -h
|
||||
```
|
||||
|
||||
这条命令会显示帮助,以下是nuclei支持的所有命令
|
||||
这将显示Nuclei的帮助,以下是所有支持的命令
|
||||
|
||||
|命令|描述|例子|
|
||||
|-----|-----|-----|
|
||||
|bulk-size|每个模板最大并行的主机数(默认25)|nuclei -bulk-size 25|
|
||||
|burp-collaborator-biid|使用burp-collaborator插件|nuclei -burp-collaborator-biid XXXX|
|
||||
|c|并行的最大模板数量(默认10)|nuclei -c 10|
|
||||
|l|对URL列表进行测试|nuclei -l urls.txt|
|
||||
|target|对目标进行测试|nuclei -target hxxps://example.com|
|
||||
|t|要检测的模板种类|nuclei -t git-core.yaml -t cves/|
|
||||
|no-color|输出不显示颜色|nuclei -no-color|
|
||||
|no-meta|不显示匹配的元数据|nuclei -no-meta|
|
||||
|json|输出为json格式|nuclei -json|
|
||||
|include-rr|json输出格式中包含请求和响应数据|nuclei -json -include-rr|
|
||||
|o|输出为文件|nuclei -o output.txt|
|
||||
|project|避免发送相同的请求|nuclei -project|
|
||||
|stats|使用进度条|nuclei -stats|
|
||||
|silent|只输出测试成功的结果|nuclei -silent|
|
||||
|retries|失败后的重试次数|nuclei -retries 1|
|
||||
|timeout|超时时间(默认为5秒)|nuclei -timeout 5|
|
||||
|trace-log|输出日志到log文件|nuclei -trace-log logs|
|
||||
|rate-limit|每秒最大请求数(默认150)|nuclei -rate-limit 150|
|
||||
|severity|根据严重性选择模板|nuclei -severity critical,high|
|
||||
|stop-at-first-match|第一次匹配不要处理HTTP请求|nuclei -stop-at-frst-match|
|
||||
|exclude|排除的模板或文件夹|nuclei -exclude panels -exclude tokens|
|
||||
|debug|调试请求或者响应|nuclei -debug|
|
||||
|update-templates|下载或者升级模板|nuclei -update-templates|
|
||||
|update-directory|选择储存模板的目录(可选)|nuclei -update-directory templates|
|
||||
|tl|列出可用的模板|nuclei -tl|
|
||||
|templates-version|显示已安装的模板版本|nuclei -templates-version|
|
||||
|v|显示发送请求的详细信息|nuclei -v|
|
||||
|version|显示nuclei的版本号|nuclei -version|
|
||||
|proxy-url|输入代理地址|nuclei -proxy-url hxxp://127.0.0.1:8080|
|
||||
|proxy-socks-url|输入socks代理地址|nuclei -proxy-socks-url socks5://127.0.0.1:8080|
|
||||
|random-agent|使用随机的UA|nuclei -random-agent|
|
||||
|H|自定义请求头|nuclei -H “x-bug-bounty:hacker”|
|
||||
|
||||
## 运行Nuclei
|
||||
```yaml
|
||||
Nuclei是一款注重于可配置性、可扩展性和易用性的基于模板的快速漏洞扫描器。
|
||||
|
||||
### 运行单个模板
|
||||
用法:
|
||||
nuclei [命令]
|
||||
|
||||
这将对`urls.txt`中所有的主机运行`git-core.yaml`并返回结果到`results.txt`
|
||||
命令:
|
||||
目标:
|
||||
-u, -target string[] 指定扫描的URL/主机
|
||||
-l, -list string 指定需要扫描的URL/主机文件(一行一个)
|
||||
|
||||
模板:
|
||||
-t, -templates string[] 指定需要扫描的模板或者模板的路径
|
||||
-nt, -new-templates 只扫描最新版本中添加的模板
|
||||
-w, -workflows string[] 指定扫描中的工作流或者工作流目录
|
||||
-validate 验证通过的模板
|
||||
-tl 列出所有可用的模板
|
||||
|
||||
过滤:
|
||||
-tags string[] 执行有标记的模板子集
|
||||
-etags, -exclude-tags string[] 执行标记为排除的模板
|
||||
-itags, -include-tags string[] 不执行具有攻击性的模板
|
||||
-et, -exclude-templates string[] 要排除的模板或者模板目录
|
||||
-it, -include-templates string[] 执行默认或配置中排除的模板
|
||||
-s, -severity value[] 根据严重程度运行模板,可候选的值有:info,low,medium,high,critical
|
||||
-es, -exclude-severity value[] 根据严重程度排除模板,可候选的值有:info,low,medium,high,critical
|
||||
-a, -author string[] 执行指定作者的模板
|
||||
|
||||
输出:
|
||||
-o, -output string 输出发现的问题到文件
|
||||
-silent 只显示结果
|
||||
-nc, -no-color 禁用输出内容着色(ANSI转义码)
|
||||
-json 输出为jsonL(ines)
|
||||
-irr, -include-rr 在JSONL中输出对应的请求和相应(仅结果)
|
||||
-nm, -no-meta 不显示匹配的元数据
|
||||
-nts, -no-timestamp 不在输出中显示时间戳
|
||||
-rdb, -report-db string 本地的Nuclei结果数据库(始终使用该数据库保存结果)
|
||||
-me, -markdown-export string 以markdown导出结果
|
||||
-se, -sarif-export string 以SARIF导出结果
|
||||
|
||||
配置:
|
||||
-config string 指定Nuclei的配置文件
|
||||
-rc, -report-config string 指定Nuclei报告模板文件
|
||||
-H, -header string[] 指定报告中的标题:value格式
|
||||
-V, -var value 通过var=value指定var值
|
||||
-r, -resolvers string 指定Nuclei的解析文件
|
||||
-sr, -system-resolvers 当DNS错误时使用系统DNS
|
||||
-passive 启用被动扫描处理HTTP响应
|
||||
-ev, env-vars 在模板中使用环境变量
|
||||
|
||||
交互:
|
||||
-inserver, -ineractsh-server string 使用interactsh反连检测平台(默认为"https://interact.sh")
|
||||
-itoken, -interactsh-token string 指定反连检测平台的身份凭证
|
||||
-interactions-cache-size int 指定保存在交互缓存中的请求数(默认:5000)
|
||||
-interactions-eviction int 从缓存中删除请求前等待的时间(默认为60秒)
|
||||
-interactions-poll-duration int 每个轮询前等待时间(默认为5秒)
|
||||
-interactions-cooldown-period int 退出轮询前的等待时间(默认为5秒)
|
||||
-ni, -no-interactsh 禁用反连检测平台,同时排除基于反连检测的模板
|
||||
|
||||
限速:
|
||||
-r1, -rate-limit int 每秒最大请求量(默认:150)
|
||||
-rlm, -rate-limit-minute int 每分钟最大请求量
|
||||
-bs, -bulk-size int 每个模板最大并行检测数(默认:25)
|
||||
-c, -concurrency int 并行执行的最大模板数量(默认:25)
|
||||
|
||||
|
||||
优化:
|
||||
-timeout int 超时时间(默认为5秒)
|
||||
-retries int 重试次数(默认:1)
|
||||
-mhe, -max-host-error int 某主机扫描失败次数,跳过该主机(默认:30)
|
||||
-project 使用项目文件夹避免多次发送同一请求
|
||||
-project-path string 设置特定的项目文件夹
|
||||
-spm, -stop-at-first-path 得到一个结果后停止(或许会中断模板和工作流的逻辑)
|
||||
-stream 流模式 - 在不整理输入的情况下详细描述
|
||||
|
||||
无界面浏览器:
|
||||
-headless 启用需要无界面浏览器的模板
|
||||
-page-timeout int 在无界面下超时秒数(默认:20)
|
||||
-sb, -show-brower 在无界面浏览器运行模板时,显示浏览器
|
||||
-sc, -system-chrome 不使用Nuclei自带的浏览器,使用本地浏览器
|
||||
|
||||
调试:
|
||||
-debug 显示所有请求和响应
|
||||
-debug-req 显示所有请求
|
||||
-debug-resp 显示所有响应
|
||||
-proxy, -proxy-url string 使用HTTP代理
|
||||
-proxy-socks-url string 使用SOCK5代理
|
||||
-tlog, -trace-log string 写入请求日志到文件
|
||||
-version 显示版本信息
|
||||
-v, -verbose 显示详细信息
|
||||
-vv 显示额外的详细信息
|
||||
-tv, -templates-version 显示已安装的模板版本
|
||||
|
||||
升级:
|
||||
-update 更新Nuclei到最新版本
|
||||
-ut, -update-templates 更新Nuclei模板到最新版
|
||||
-ud, -update-directory string 覆盖安装模板
|
||||
-duc, -disable-update-check 禁用更新
|
||||
|
||||
统计:
|
||||
-stats 显示正在扫描的统计信息
|
||||
-sj, -stats-json 将统计信息以JSONL格式输出到文件
|
||||
-si, -stats-inerval int 显示统计信息更新的间隔秒数(默认:5)
|
||||
-m, -metrics 显示Nuclei端口信息
|
||||
-mp, -metrics-port int 更改Nuclei默认端口(默认:9092)
|
||||
```
|
||||
|
||||
### 运行Nuclei
|
||||
|
||||
使用[社区提供的模板](https://github.com/projectdiscovery/nuclei-templates)扫描单个目标
|
||||
|
||||
```sh
|
||||
▶ nuclei -l urls.txt -t files/git-core.yaml -o results.txt
|
||||
nuclei -u https://example.com
|
||||
```
|
||||
|
||||
你可以轻松的通过管道使用标准的输入(STDIN)传递URL列表。
|
||||
使用[社区提供的模板](https://github.com/projectdiscovery/nuclei-templates)扫描多个目标
|
||||
|
||||
```sh
|
||||
▶ cat urls.txt | nuclei -t files/git-core.yaml -o results.txt
|
||||
nuclei -list urls.txt
|
||||
```
|
||||
|
||||
💡 Nuclei可以接受如下列表的URL作为输入,例如以下URL:
|
||||
Example of `urls.txt`:
|
||||
|
||||
```
|
||||
https://test.some-site.com
|
||||
http://vuls-testing.com
|
||||
https://test.com
|
||||
```
|
||||
### 运行多个模板
|
||||
|
||||
这将会对`urls.txt`中所有的URL运行`cves`和`files`模板检查,并返回输出到`results.txt`
|
||||
|
||||
```sh
|
||||
▶ nuclei -l urls.txt -t cves/ -t files/ -o results.txt
|
||||
```yaml
|
||||
http://example.com
|
||||
http://app.example.com
|
||||
http://test.example.com
|
||||
http://uat.example.com
|
||||
```
|
||||
|
||||
### 使用subfinder运行
|
||||
**更多关于Nuclei的详细实例可以在[这里](https://nuclei.projectdiscovery.io/nuclei/get-started/#running-nuclei)找到**
|
||||
|
||||
```sh
|
||||
▶ subfinder -d hackerone.com -silent | httpx -silent | nuclei -t cves/ -o results.txt
|
||||
```
|
||||
# 对于安全工程师
|
||||
|
||||
### 在docker中运行
|
||||
Nuclei提供了大量有助于安全工程师在工作流定制相关的功能。通过各种扫描功能(如DNS、HTTP、TCP),安全工程师可以更轻松的使用Nuclei创建一套自定义的检查方式。
|
||||
|
||||
你需要使用[nuclei的docker镜像](https://hub.docker.com/r/projectdiscovery/nuclei)来运行
|
||||
- 支持多种协议:TCP、DNS、HTTP、FILE等
|
||||
- 通过工作流和动态请求实现复杂的漏洞扫描
|
||||
- 易于集成到CI/CD,旨在可以轻松的集成到周期扫描中,以主动检测漏洞的修复和重新出现
|
||||
|
||||
```sh
|
||||
▶ docker pull projectdiscovery/nuclei
|
||||
```
|
||||
<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
|
||||
▶ docker run -it projectdiscovery/nuclei
|
||||
```
|
||||
**对于赏金猎人:**
|
||||
|
||||
这将会对`urls.txt`中的URL通过docker中的nuclei进行检测,并将结果输出到本机的`results.txt`文件的:
|
||||
Nuclei允许您定制自己的测试方法,可以轻松的运行您的程序。此外Nuclei可以更容易的集成到您的漏扫设备中。
|
||||
|
||||
```sh
|
||||
▶ cat urls.txt | docker run -v /path/to/nuclei-templates:/app/nuclei-templates -v /path/to/nuclei/config:/app/.nuclei-config.json -i projectdiscovery/nuclei -t /app/nuclei-templates/files/git-config.yaml > results.txt
|
||||
```
|
||||
记住更改的模板路径到本机
|
||||
- 可以集成到其他工作流中
|
||||
- 可以在几分钟处理上千台主机
|
||||
- 使用YAML语法定制自动化测试
|
||||
|
||||
### 速率限制
|
||||
欢迎查看我们其他的开源项目,可能有适合您的赏金猎人工作流:[github.com/projectdiscovery](http://github.com/projectdiscovery),我们还使用[Chaos绘制了每日的DNS数据](http://chaos.projectdiscovery.io)。
|
||||
|
||||
Nuclei有多种控制速率的方法,包括并行执行多个模板、并行检查多个主机,以及使nuclei限制全局的请求速率,下面就是示例。
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
- `-c`参数 => 限制并行的模板数
|
||||
- `-bulk-size`参数 => 限制并行的主机数
|
||||
- `-rate-limit`参数 => 全局速率限制
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
如果你想快速扫描或者控制扫描,请使用这些标志并输入限制数,`速率限制`只保证控制传出的请求,与其他参数无关。
|
||||
**对于渗透测试:**
|
||||
|
||||
### 排除模板
|
||||
Nuclei通过增加手动、自动的过程,极大地改变了安全评估的方式。一些公司已经在用Nuclei升级他们的手动测试步骤,可以使用Nulcei对数千台主机使用同样的流程自动化测试。
|
||||
|
||||
[Nuclei模板](https://github.com/projectdiscovery/nuclei-templates)包含多种检查,其中有许多对攻击有用的检查,但并不是都有用的。如果您只希望扫描少数特定的模板或目录,则可以使用如下的参数筛选模板,或将某些模板排除。
|
||||
渗透测试员可以使用公共模板或者自定义模板来更快的完成渗透测试,特别是漏洞验证时,可以轻松的验证漏洞是否修复。
|
||||
|
||||
#### 排除模板运行
|
||||
- 轻松根据您的要求创建标准清单(例如:OWASP TOP 10)
|
||||
- 通过[FUZZ](https://nuclei.projectdiscovery.io/templating-guide/#advance-fuzzing)和[工作流](https://nuclei.projectdiscovery.io/templating-guide/#workflows)等功能,可以使用Nuclei完成复杂的手动步骤和重复性渗透测试
|
||||
- 只需要重新运行Nuclei即可验证漏洞修复情况
|
||||
|
||||
我们不建议同时运行所有的nuclei模板,如果要排除模板,可以使用`exclude`参数来排除特定的目录或模板。
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
```sh
|
||||
nuclei -l urls.txt -t nuclei-templates -exclude panels/ -exclude technologies -exclude files/wp-xmlrpc.yaml
|
||||
```
|
||||
# 对于开发和组织
|
||||
|
||||
注意:如上述示例中显示的那样,目录和特定模板都将不会扫描
|
||||
Nuclei构建很简单,通过数百名安全研究员的社区模板,Nuclei可以随时扫描来了解安全威胁。Nuclei通常用来用于复测,以确定漏洞是否被修复。
|
||||
|
||||
#### 基于严重性运行模板
|
||||
- **CI/CD:**工程师已经支持了CI/CD,可以使用Nuclei来监控生产环境
|
||||
- **周期性扫描:**使用Nuclei创建新发现的漏洞模板,通过Nuclei可以周期性扫描消除漏洞
|
||||
|
||||
您可以根据模板的严重性运行模板,扫描时可以选择单个严重性或多个严重性。
|
||||
我们有个[讨论组](https://github.com/projectdiscovery/nuclei-templates/discussions/693),黑客提交自己的模板后可以获得赏金,这可以减少资产的漏洞,并且减少重复。如果你想实行该计划,可以[联系我](mailto:[email protected])。我们非常乐意提供帮助,或者在[讨论组](https://github.com/projectdiscovery/nuclei-templates/discussions/693)中发布相关信息。
|
||||
|
||||
```sh
|
||||
nuclei -l urls.txt -t cves/ -severity critical,medium
|
||||
```
|
||||
<h3 align="center">
|
||||
<img src="static/regression-with-nuclei.jpg" alt="regression-cycle-with-nuclei" width="1100px"></a>
|
||||
</h3>
|
||||
|
||||
上面的例子将运行`cves`目录下所有`严重`和`中等`的模板。
|
||||
<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>
|
||||
|
||||
```sh
|
||||
nuclei -l urls.txt -t panels/ -t technologies -severity info
|
||||
```
|
||||
### 资源
|
||||
- [使用Nuclei扫描](https://blog.projectdiscovery.io/community-powered-scanning-with-nuclei/)
|
||||
- [Nuclei Unleashed - 快速编写复杂漏洞](https://blog.projectdiscovery.io/nuclei-unleashed-quickly-write-complex-exploits/)
|
||||
- [Nuclei - FUZZ一切](https://blog.projectdiscovery.io/nuclei-fuzz-all-the-things/)
|
||||
- [Nuclei + Interactsh Integration,用于自动化OOB测试](https://blog.projectdiscovery.io/nuclei-interactsh-integration/)
|
||||
- [武器化Nuclei](https://medium.com/@dwisiswant0/weaponizes-nuclei-workflows-to-pwn-all-the-things-cd01223feb77) 作者:[@dwisiswant0](https://github.com/dwisiswant0)
|
||||
- [如何使用Nuclei连续扫描?](https://medium.com/@dwisiswant0/how-to-scan-continuously-with-nuclei-fcb7e9d8b8b9) 作者:[@dwisiswant0](https://github.com/dwisiswant0)
|
||||
- [自动化攻击](https://dhiyaneshgeek.github.io/web/security/2021/07/19/hack-with-automation/) 作者:[@DhiyaneshGeek](https://github.com/DhiyaneshGeek)
|
||||
|
||||
上面的例子将运行`panels`和`technologies`目录下严重性标记为`info`的模板
|
||||
### 致谢
|
||||
|
||||
#### 使用`.nuclei-ignore`文件排除模板
|
||||
感谢所有[社区贡献者提供的PR](https://github.com/projectdiscovery/nuclei/graphs/contributors),另外您可以其他类似的开源项目:
|
||||
|
||||
自从nuclei的[v2.1.1版本](https://github.com/projectdiscovery/nuclei/releases/tag/v2.1.1)以来,我们添加了对`.nuclei-ignore`文件的支持,该文件与`update-templates`参数一起使用,在 **.nuclei-ignore** 文件中,您可以定义要从nuclei扫描中排除的所有模板目录或者模板路径,要开始使用此功能,请确保使用`nuclei-update-templates`参数安装nuclei模板,现在可以根据`.nuclei-ignore`的文件来添加、更新、删除模板文件。
|
||||
[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)
|
||||
|
||||
```
|
||||
nano ~/nuclei-templates/.nuclei-ignore
|
||||
```
|
||||
### 许可证
|
||||
|
||||
默认的**nuclei忽略**列表可以访问[这里]((https://github.com/projectdiscovery/nuclei-templates/blob/master/.nuclei-ignore),如果不想排除任何内容,只需要删除`.nuclei-ignore`文件。
|
||||
Nuclei使用[MIT许可证](https://github.com/projectdiscovery/nuclei/blob/master/LICENSE.md)
|
||||
|
||||
* * *
|
||||
|
||||
### 📋 笔记
|
||||
|
||||
- 进度条是实验性功能,在某些情况下可能无法使用。
|
||||
- 进度条不适用于工作流,因为是条件执行,所以不准确。
|
||||
|
||||
|
||||
## 致谢
|
||||
|
||||
也要看看这些类似的好项目,或许它们也适合你:
|
||||
|
||||
[Burp Suite](https://portswigger.net/burp), [FFuF](https://github.com/ffuf/ffuf), [Jaeles](https://github.com/jaeles-project/jaeles), [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), [ChopChop](https://github.com/michelin/ChopChop)
|
||||
|
||||
--------
|
||||
|
||||
Nuclei是由[projectdiscovery](https://projectdiscovery.io)团队用🖤制作的,当然社区也贡献了很多,通过 **[Thanks.md](https://github.com/projectdiscovery/nuclei/blob/master/THANKS.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>
|
||||
@@ -0,0 +1,5 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
DO NOT CREATE AN ISSUE to report a security problem. Instead, please send an email to security@projectdiscovery.io, and we will acknowledge it within 3 working days.
|
||||
Executable
+4037
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,22 @@
|
||||
id: caa-fingerprinting
|
||||
|
||||
info:
|
||||
name: CAA Fingerprint
|
||||
author: pdteam
|
||||
severity: info
|
||||
tags: dns,caa
|
||||
|
||||
dns:
|
||||
- name: "{{FQDN}}"
|
||||
type: CAA
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "IN\tCAA"
|
||||
|
||||
extractors:
|
||||
- type: regex
|
||||
group: 1
|
||||
regex:
|
||||
- "IN\tCAA\t(.+)"
|
||||
@@ -0,0 +1,22 @@
|
||||
id: ptr-fingerprint
|
||||
|
||||
info:
|
||||
name: PTR Fingerprint
|
||||
author: pdteam
|
||||
severity: info
|
||||
tags: dns,ptr
|
||||
|
||||
dns:
|
||||
- name: "{{FQDN}}"
|
||||
type: PTR
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "IN\tPTR"
|
||||
|
||||
extractors:
|
||||
- type: regex
|
||||
group: 1
|
||||
regex:
|
||||
- "IN\tPTR\t(.+)"
|
||||
@@ -0,0 +1,18 @@
|
||||
id: headless-basic
|
||||
info:
|
||||
name: Headless Basic
|
||||
author: pdteam
|
||||
severity: info
|
||||
tags: headless
|
||||
|
||||
headless:
|
||||
- steps:
|
||||
- action: navigate
|
||||
args:
|
||||
url: "{{BaseURL}}/"
|
||||
|
||||
- action: waitload
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "<html>"
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
id: headless-extract-values
|
||||
info:
|
||||
name: Headless Extract Value
|
||||
author: pdteam
|
||||
severity: info
|
||||
tags: headless
|
||||
|
||||
headless:
|
||||
- steps:
|
||||
- action: navigate
|
||||
args:
|
||||
url: "{{BaseURL}}"
|
||||
- action: waitload
|
||||
# From headless/extract-urls.yaml
|
||||
- action: script
|
||||
name: extract
|
||||
args:
|
||||
code: |
|
||||
'\n' + [...new Set(Array.from(document.querySelectorAll('[src], [href], [url], [action]')).map(i => i.src || i.href || i.url || i.action))].join('\r\n') + '\n'
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "test.html"
|
||||
|
||||
extractors:
|
||||
- type: kval
|
||||
part: extract
|
||||
kval:
|
||||
- extract
|
||||
@@ -0,0 +1,24 @@
|
||||
id: headless-header-action
|
||||
info:
|
||||
name: Headless Header Action
|
||||
author: pdteam
|
||||
severity: info
|
||||
tags: headless
|
||||
|
||||
headless:
|
||||
- steps:
|
||||
- action: setheader
|
||||
args:
|
||||
part: request
|
||||
key: Test
|
||||
value: test value
|
||||
|
||||
- action: navigate
|
||||
args:
|
||||
url: "{{BaseURL}}/"
|
||||
|
||||
- action: waitload
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "test value"
|
||||
@@ -0,0 +1,26 @@
|
||||
id: headless-payloads
|
||||
|
||||
info:
|
||||
name: headless payloads example
|
||||
author: pdteam
|
||||
severity: info
|
||||
tags: headless
|
||||
|
||||
headless:
|
||||
- attack: clusterbomb
|
||||
payloads:
|
||||
aa:
|
||||
- aa
|
||||
- bb
|
||||
bb:
|
||||
- cc
|
||||
- dd
|
||||
steps:
|
||||
- args:
|
||||
url: "{{BaseURL}}?aa={{aa}}&bb={{bb}}"
|
||||
action: navigate
|
||||
- action: waitload
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "test"
|
||||
@@ -0,0 +1,72 @@
|
||||
id: helper-functions-examples
|
||||
|
||||
info:
|
||||
name: RAW Template with Helper Functions
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- raw:
|
||||
- |
|
||||
GET / HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
01: {{base64("Hello")}}
|
||||
02: {{base64(1234)}}
|
||||
03: {{base64_decode("SGVsbG8=")}}
|
||||
04: {{base64_py("Hello")}}
|
||||
05: {{concat("Hello", "world")}}
|
||||
06: {{contains("Hello", "lo")}}
|
||||
07: {{generate_java_gadget("commons-collections3.1", "wget http://{{interactsh-url}}", "base64")}}
|
||||
08: {{gzip("Hello")}}
|
||||
09: {{hex_decode("6161")}}
|
||||
10: {{hex_encode("aa")}}
|
||||
11: {{html_escape("<body>test</body>")}}
|
||||
12: {{html_unescape("<body>test</body>")}}
|
||||
13: {{len("Hello")}}
|
||||
14: {{len(5555)}}
|
||||
15: {{md5("Hello")}}
|
||||
16: {{md5(1234)}}
|
||||
17: {{mmh3("Hello")}}
|
||||
18: {{print_debug(1+2, "Hello")}}
|
||||
19: {{rand_base(5, "abc")}}
|
||||
20: {{rand_base(5, "")}}
|
||||
21: {{rand_base(5)}}
|
||||
22: {{rand_char("abc")}}
|
||||
23: {{rand_char("")}}
|
||||
24: {{rand_char()}}
|
||||
25: {{rand_int(1, 10)}}
|
||||
26: {{rand_int(10)}}
|
||||
27: {{rand_int()}}
|
||||
28: {{rand_text_alpha(10, "abc")}}
|
||||
29: {{rand_text_alpha(10, "")}}
|
||||
30: {{rand_text_alpha(10)}}
|
||||
31: {{rand_text_alphanumeric(10, "ab12")}}
|
||||
32: {{rand_text_alphanumeric(10)}}
|
||||
33: {{rand_text_numeric(10, 123)}}
|
||||
34: {{rand_text_numeric(10)}}
|
||||
35: {{regex("H([a-z]+)o", "Hello")}}
|
||||
36: {{remove_bad_chars("abcd", "bc")}}
|
||||
37: {{repeat("a", 5)}}
|
||||
38: {{replace("Hello", "He", "Ha")}}
|
||||
39: {{replace_regex("He123llo", "(\\d+)", "")}}
|
||||
40: {{reverse("abc")}}
|
||||
41: {{sha1("Hello")}}
|
||||
42: {{sha256("Hello")}}
|
||||
43: {{to_lower("HELLO")}}
|
||||
44: {{to_upper("hello")}}
|
||||
45: {{trim("aaaHelloddd", "ad")}}
|
||||
46: {{trim_left("aaaHelloddd", "ad")}}
|
||||
47: {{trim_prefix("aaHelloaa", "aa")}}
|
||||
48: {{trim_right("aaaHelloddd", "ad")}}
|
||||
49: {{trim_space(" Hello ")}}
|
||||
50: {{trim_suffix("aaHelloaa", "aa")}}
|
||||
51: {{unix_time(10)}}
|
||||
52: {{url_decode("https:%2F%2Fprojectdiscovery.io%3Ftest=1")}}
|
||||
53: {{url_encode("https://projectdiscovery.io/test?a=1")}}
|
||||
54: {{wait_for(1)}}
|
||||
|
||||
extractors:
|
||||
- type: regex
|
||||
name: results
|
||||
regex:
|
||||
- '\d+: [^\s]+'
|
||||
@@ -0,0 +1,23 @@
|
||||
id: dsl-matcher-variable
|
||||
|
||||
info:
|
||||
name: dsl-matcher-variable
|
||||
author: pd-team
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
-
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
payloads:
|
||||
VALUES:
|
||||
- This
|
||||
- is
|
||||
- test
|
||||
- matcher
|
||||
- text
|
||||
matchers:
|
||||
-
|
||||
dsl:
|
||||
- 'contains(body,"{{VALUES}}")'
|
||||
type: dsl
|
||||
@@ -0,0 +1,16 @@
|
||||
id: basic-get-case-insensitive
|
||||
|
||||
info:
|
||||
name: Basic GET Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
matchers:
|
||||
- type: word
|
||||
case-insensitive: true
|
||||
words:
|
||||
- "ThIS is TEsT MAtcHEr TExT"
|
||||
@@ -0,0 +1,23 @@
|
||||
id: basic-get-redirects-chain-headers
|
||||
|
||||
info:
|
||||
name: Basic GET Redirects Request With Chain header
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
redirects: true
|
||||
max-redirects: 3
|
||||
matchers-condition: and
|
||||
matchers:
|
||||
- type: word
|
||||
part: header
|
||||
words:
|
||||
- "TestRedirectHeaderMatch"
|
||||
|
||||
- type: status
|
||||
status:
|
||||
- 302
|
||||
@@ -0,0 +1,23 @@
|
||||
id: interactsh-stop-at-first-match-integration-test
|
||||
|
||||
info:
|
||||
name: Interactsh StopAtFirstMatch Integration Test
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
- "{{BaseURL}}"
|
||||
- "{{BaseURL}}"
|
||||
headers:
|
||||
url: 'http://{{interactsh-url}}'
|
||||
|
||||
stop-at-first-match: true
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
part: interactsh_protocol # Confirms the HTTP Interaction
|
||||
words:
|
||||
- "http"
|
||||
@@ -0,0 +1,19 @@
|
||||
id: interactsh-integration-test
|
||||
|
||||
info:
|
||||
name: Interactsh Integration Test
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
headers:
|
||||
url: 'http://{{interactsh-url}}'
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
part: interactsh_protocol # Confirms the HTTP Interaction
|
||||
words:
|
||||
- "http"
|
||||
@@ -0,0 +1,46 @@
|
||||
id: race-condition-testing
|
||||
|
||||
info:
|
||||
name: Race condition testing with multiple requests
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- raw:
|
||||
- |
|
||||
GET / HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
|
||||
id=1
|
||||
|
||||
- |
|
||||
GET / HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
|
||||
id=2
|
||||
|
||||
- |
|
||||
GET / HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
|
||||
id=3
|
||||
|
||||
- |
|
||||
GET / HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
|
||||
id=4
|
||||
|
||||
- |
|
||||
GET / HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
|
||||
id=5
|
||||
|
||||
threads: 5
|
||||
race: true
|
||||
|
||||
matchers:
|
||||
- type: status
|
||||
status:
|
||||
- 200
|
||||
@@ -0,0 +1,23 @@
|
||||
id: race-condition-testing
|
||||
|
||||
info:
|
||||
name: Race Condition testing
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- raw:
|
||||
- |
|
||||
GET / HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
|
||||
test
|
||||
|
||||
race: true
|
||||
race_count: 10
|
||||
|
||||
matchers:
|
||||
- type: status
|
||||
part: header
|
||||
status:
|
||||
- 200
|
||||
@@ -7,7 +7,7 @@ info:
|
||||
|
||||
requests:
|
||||
- raw:
|
||||
- |
|
||||
- |+
|
||||
GET / HTTP/1.1
|
||||
Host:
|
||||
Content-Length: 4
|
||||
@@ -17,4 +17,4 @@ requests:
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "This is test-raw-unsafe request matcher."
|
||||
- "This is test raw-unsafe-matcher test"
|
||||
@@ -0,0 +1,18 @@
|
||||
id: example-self-contained-input
|
||||
|
||||
info:
|
||||
name: example-self-contained
|
||||
author: pd-team
|
||||
severity: info
|
||||
|
||||
self-contained: true
|
||||
requests:
|
||||
- raw:
|
||||
- |
|
||||
GET http://127.0.0.1:5431/ HTTP/1.1
|
||||
Host: {{Hostname}}
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- This is self-contained response
|
||||
@@ -0,0 +1,18 @@
|
||||
id: stop-at-first-match-with-extractors
|
||||
|
||||
info:
|
||||
name: Stop at first match Request with extractors
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}?a=1"
|
||||
- "{{BaseURL}}?a=2"
|
||||
stop-at-first-match: true
|
||||
extractors:
|
||||
- type: kval
|
||||
part: header
|
||||
kval:
|
||||
- "date"
|
||||
@@ -0,0 +1,17 @@
|
||||
id: stop-at-first-match
|
||||
|
||||
info:
|
||||
name: Stop at first match Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}?a=1"
|
||||
- "{{BaseURL}}?a=2"
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "This is test"
|
||||
stop-at-first-match: true
|
||||
@@ -0,0 +1,10 @@
|
||||
id: workflow-example
|
||||
|
||||
info:
|
||||
name: Test Workflow Template
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
workflows:
|
||||
- template: workflow/match-1.yaml
|
||||
- template: workflow/match-2.yaml
|
||||
@@ -0,0 +1,11 @@
|
||||
id: condition-matched-workflow
|
||||
|
||||
info:
|
||||
name: Condition Matched Workflow
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
workflows:
|
||||
- template: workflow/match-1.yaml
|
||||
subtemplates:
|
||||
- template: workflow/match-2.yaml
|
||||
@@ -0,0 +1,17 @@
|
||||
id: basic-get-headers
|
||||
|
||||
info:
|
||||
name: Basic GET Headers Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
headers:
|
||||
test: nuclei
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "This is test headers matcher text"
|
||||
@@ -0,0 +1,15 @@
|
||||
id: basic-get
|
||||
|
||||
info:
|
||||
name: Basic GET Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
requests:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}"
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "This is test matcher text"
|
||||
@@ -0,0 +1,2 @@
|
||||
loader/get.yaml
|
||||
loader/get-headers.yaml
|
||||
@@ -0,0 +1,2 @@
|
||||
loader/basic.yaml
|
||||
loader/condition-matched.yaml
|
||||
@@ -0,0 +1,16 @@
|
||||
id: example-self-contained-input
|
||||
|
||||
info:
|
||||
name: example-self-contained
|
||||
author: pd-team
|
||||
severity: info
|
||||
|
||||
self-contained: true
|
||||
network:
|
||||
- host:
|
||||
- "127.0.0.1:5431"
|
||||
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "Authentication successful"
|
||||
Regular → Executable
+7
-2
@@ -1,12 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "::group::Build nuclei"
|
||||
rm integration-test nuclei 2>/dev/null
|
||||
cd ../v2/cmd/nuclei
|
||||
go build
|
||||
cp nuclei ../../../integration_tests/nuclei
|
||||
mv nuclei ../../../integration_tests/nuclei
|
||||
echo "::endgroup::"
|
||||
echo "::group::Build nuclei integration-test"
|
||||
cd ../integration-test
|
||||
go build
|
||||
cp integration-test ../../../integration_tests/integration-test
|
||||
mv integration-test ../../../integration_tests/integration-test
|
||||
cd ../../../integration_tests
|
||||
echo "::endgroup::"
|
||||
./integration-test
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
id: basic-ssl-tls
|
||||
|
||||
info:
|
||||
name: Basic SSL Request with ztls
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
ssl:
|
||||
- address: "{{Host}}:{{Port}}"
|
||||
min_version: sslv3
|
||||
max_version: tls12
|
||||
matchers:
|
||||
- type: dsl
|
||||
dsl:
|
||||
- "not_after>=0"
|
||||
@@ -0,0 +1,13 @@
|
||||
id: expired-ssl
|
||||
|
||||
info:
|
||||
name: Basic SSL Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
ssl:
|
||||
- address: "{{Host}}:{{Port}}"
|
||||
matchers:
|
||||
- type: dsl
|
||||
dsl:
|
||||
- "not_after>=0"
|
||||
@@ -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
|
||||
@@ -0,0 +1,70 @@
|
||||
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
|
||||
@@ -0,0 +1,16 @@
|
||||
id: basic-request
|
||||
|
||||
info:
|
||||
name: Basic Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
websocket:
|
||||
- address: '{{Scheme}}://{{Hostname}}'
|
||||
inputs:
|
||||
- data: hello
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- world
|
||||
part: response
|
||||
@@ -0,0 +1,16 @@
|
||||
id: basic-cswsh-request
|
||||
|
||||
info:
|
||||
name: Basic cswsh Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
websocket:
|
||||
- address: '{{Scheme}}://{{Hostname}}'
|
||||
headers:
|
||||
Origin: 'http://evil.com'
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- true
|
||||
part: success
|
||||
@@ -0,0 +1,16 @@
|
||||
id: basic-nocswsh-request
|
||||
|
||||
info:
|
||||
name: Basic Non-Vulnerable cswsh Request
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
websocket:
|
||||
- address: '{{Scheme}}://{{Hostname}}'
|
||||
headers:
|
||||
Origin: 'http://evil.com'
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- true
|
||||
part: success
|
||||
@@ -0,0 +1,16 @@
|
||||
id: basic-request-path
|
||||
|
||||
info:
|
||||
name: Basic Request Path
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
websocket:
|
||||
- address: '{{Scheme}}://{{Hostname}}'
|
||||
inputs:
|
||||
- data: hello
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- world
|
||||
part: response
|
||||
@@ -0,0 +1,14 @@
|
||||
id: basic-whois-example
|
||||
|
||||
info:
|
||||
name: test template for WHOIS
|
||||
author: pdteam
|
||||
severity: info
|
||||
|
||||
whois:
|
||||
- query: "{{Host}}"
|
||||
extractors:
|
||||
- type: kval
|
||||
kval:
|
||||
- "expiration date"
|
||||
- "registrar"
|
||||
Executable
+1310
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,17 @@
|
||||
sonar.projectKey=projectdiscovery_nuclei
|
||||
sonar.organization=projectdiscovery
|
||||
|
||||
# This is the name and version displayed in the SonarCloud UI.
|
||||
#sonar.projectName=dnsx
|
||||
#sonar.projectVersion=1.0
|
||||
|
||||
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
|
||||
sonar.sources=v2/
|
||||
sonar.tests=v2/
|
||||
sonar.test.inclusions=**/*_test.go
|
||||
sonar.exclusions=v2/pkg/protocols/common/helpers/deserialization/testdata/*.java
|
||||
sonar.go.coverage.reportPaths=v2/cov.out
|
||||
sonar.externalIssuesReportPaths=v2/report.json
|
||||
|
||||
# Encoding of the source code. Default is default system encoding
|
||||
#sonar.sourceEncoding=UTF-8
|
||||
+32
-19
@@ -3,23 +3,36 @@ before:
|
||||
- go mod tidy
|
||||
|
||||
builds:
|
||||
- binary: nuclei
|
||||
main: cmd/nuclei/main.go
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- 386
|
||||
- arm
|
||||
- arm64
|
||||
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- windows
|
||||
- linux
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- 386
|
||||
- arm
|
||||
- arm64
|
||||
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: '386'
|
||||
- goos: windows
|
||||
goarch: 'arm'
|
||||
- goos: windows
|
||||
goarch: 'arm64'
|
||||
|
||||
binary: '{{ .ProjectName }}'
|
||||
main: cmd/nuclei/main.go
|
||||
|
||||
flags:
|
||||
- -trimpath
|
||||
|
||||
archives:
|
||||
- id: tgz
|
||||
format: tar.gz
|
||||
replacements:
|
||||
darwin: macOS
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
- format: zip
|
||||
replacements:
|
||||
darwin: macOS
|
||||
|
||||
checksum:
|
||||
algorithm: sha256
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Go parameters
|
||||
GOCMD=go
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOMOD=$(GOCMD) mod
|
||||
GOTEST=$(GOCMD) test
|
||||
GOGET=$(GOCMD) get
|
||||
|
||||
all: build
|
||||
build:
|
||||
$(GOBUILD) -v -ldflags="-extldflags=-static" -o "nuclei" cmd/nuclei/main.go
|
||||
docs:
|
||||
if ! which dstdocgen > /dev/null; then
|
||||
echo -e "Command not found! Install? (y/n) \c"
|
||||
go get -v github.com/projectdiscovery/yamldoc-go/cmd/docgen/dstdocgen
|
||||
fi
|
||||
$(GOCMD) generate pkg/templates/templates.go
|
||||
$(GOBUILD) -o "cmd/docgen/docgen" cmd/docgen/docgen.go
|
||||
./cmd/docgen/docgen docs.md nuclei-jsonschema.json
|
||||
test:
|
||||
$(GOTEST) -v ./...
|
||||
integration:
|
||||
bash ../integration_tests/run.sh
|
||||
functional:
|
||||
bash cmd/functional-tests/run.sh
|
||||
tidy:
|
||||
$(GOMOD) tidy
|
||||
@@ -0,0 +1,163 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Ice3man543/nvd"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
||||
)
|
||||
|
||||
var (
|
||||
input = flag.String("i", "", "Templates to annotate")
|
||||
templateDir = flag.String("d", "", "Custom template directory for update")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *input == "" || *templateDir == "" {
|
||||
log.Fatalf("invalid input, see -h\n")
|
||||
}
|
||||
|
||||
if err := process(); err != nil {
|
||||
log.Fatalf("could not process: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
func process() error {
|
||||
tempDir, err := ioutil.TempDir("", "nuclei-nvd-%s")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
client, err := nvd.NewClient(tempDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
catalog := catalog.New(*templateDir)
|
||||
|
||||
paths, err := catalog.GetTemplatePath(*input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, path := range paths {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
getCVEData(client, path, string(data))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
idRegex = regexp.MustCompile("id: ([C|c][V|v][E|e]-[0-9]+-[0-9]+)")
|
||||
severityRegex = regexp.MustCompile(`severity: ([a-z]+)`)
|
||||
)
|
||||
|
||||
func getCVEData(client *nvd.Client, filePath, data string) {
|
||||
matches := idRegex.FindAllStringSubmatch(data, 1)
|
||||
if len(matches) == 0 {
|
||||
return
|
||||
}
|
||||
cveName := matches[0][1]
|
||||
|
||||
severityMatches := severityRegex.FindAllStringSubmatch(data, 1)
|
||||
if len(severityMatches) == 0 {
|
||||
return
|
||||
}
|
||||
severityValue := severityMatches[0][1]
|
||||
|
||||
// Skip if there's classification data already
|
||||
if strings.Contains(data, "classification:") {
|
||||
return
|
||||
}
|
||||
cveItem, err := client.FetchCVE(cveName)
|
||||
if err != nil {
|
||||
log.Printf("Could not fetch cve %s: %s\n", cveName, err)
|
||||
return
|
||||
}
|
||||
var cweID []string
|
||||
for _, problemData := range cveItem.CVE.Problemtype.ProblemtypeData {
|
||||
for _, description := range problemData.Description {
|
||||
cweID = append(cweID, description.Value)
|
||||
}
|
||||
}
|
||||
cvssScore := cveItem.Impact.BaseMetricV3.CvssV3.BaseScore
|
||||
cvssMetrics := cveItem.Impact.BaseMetricV3.CvssV3.VectorString
|
||||
|
||||
// Perform some hacky string replacement to place the metadata in templates
|
||||
infoBlockIndexData := data[strings.Index(data, "info:"):]
|
||||
requestsIndex := strings.Index(infoBlockIndexData, "requests:")
|
||||
networkIndex := strings.Index(infoBlockIndexData, "network:")
|
||||
if requestsIndex == -1 && networkIndex == -1 {
|
||||
return
|
||||
}
|
||||
if networkIndex != -1 {
|
||||
requestsIndex = networkIndex
|
||||
}
|
||||
infoBlockData := infoBlockIndexData[:requestsIndex]
|
||||
infoBlockClean := strings.TrimRight(infoBlockData, "\n")
|
||||
|
||||
newInfoBlock := infoBlockClean
|
||||
var changed bool
|
||||
|
||||
if newSeverity := isSeverityMatchingCvssScore(severityValue, cvssScore); newSeverity != "" {
|
||||
changed = true
|
||||
newInfoBlock = strings.ReplaceAll(newInfoBlock, severityMatches[0][0], "severity: "+newSeverity)
|
||||
fmt.Printf("Adjusting severity for %s from %s=>%s (%.2f)\n", filePath, severityValue, newSeverity, cvssScore)
|
||||
}
|
||||
if !strings.Contains(infoBlockClean, "classification") && (cvssScore != 0 && cvssMetrics != "") {
|
||||
changed = true
|
||||
newInfoBlock += fmt.Sprintf("\n classification:\n cvss-metrics: %s\n cvss-score: %.2f\n cve-id: %s", cvssMetrics, cvssScore, cveName)
|
||||
if len(cweID) > 0 && (cweID[0] != "NVD-CWE-Other" && cweID[0] != "NVD-CWE-noinfo") {
|
||||
newInfoBlock += fmt.Sprintf("\n cwe-id: %s", strings.Join(cweID, ","))
|
||||
}
|
||||
}
|
||||
// If there is no description field, fill the description from CVE information
|
||||
if !strings.Contains(infoBlockClean, "description:") && len(cveItem.CVE.Description.DescriptionData) > 0 {
|
||||
changed = true
|
||||
newInfoBlock += fmt.Sprintf("\n description: %s", fmt.Sprintf("%q", cveItem.CVE.Description.DescriptionData[0].Value))
|
||||
}
|
||||
if !strings.Contains(infoBlockClean, "reference:") && len(cveItem.CVE.References.ReferenceData) > 0 {
|
||||
changed = true
|
||||
newInfoBlock += "\n reference:"
|
||||
for _, reference := range cveItem.CVE.References.ReferenceData {
|
||||
newInfoBlock += fmt.Sprintf("\n - %s", reference.URL)
|
||||
}
|
||||
}
|
||||
newTemplate := strings.ReplaceAll(data, infoBlockClean, newInfoBlock)
|
||||
if changed {
|
||||
_ = ioutil.WriteFile(filePath, []byte(newTemplate), 0644)
|
||||
fmt.Printf("Wrote updated template to %s\n", filePath)
|
||||
}
|
||||
}
|
||||
|
||||
func isSeverityMatchingCvssScore(severity string, score float64) string {
|
||||
if score == 0.0 {
|
||||
return ""
|
||||
}
|
||||
var expected string
|
||||
|
||||
if score >= 0.1 && score <= 3.9 {
|
||||
expected = "low"
|
||||
} else if score >= 4.0 && score <= 6.9 {
|
||||
expected = "medium"
|
||||
} else if score >= 7.0 && score <= 8.9 {
|
||||
expected = "high"
|
||||
} else if score >= 9.0 && score <= 10.0 {
|
||||
expected = "critical"
|
||||
}
|
||||
if expected != "" && expected != severity {
|
||||
return expected
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/jsonschema"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
||||
)
|
||||
|
||||
var pathRegex = regexp.MustCompile(`github\.com/projectdiscovery/nuclei/v2/(?:internal|pkg)/(?:.*/)?([A-Za-z.]+)`)
|
||||
|
||||
func main() {
|
||||
// Generate yaml syntax documentation
|
||||
data, err := templates.GetTemplateDoc().Encode()
|
||||
if err != nil {
|
||||
log.Fatalf("Could not encode docs: %s\n", err)
|
||||
}
|
||||
err = ioutil.WriteFile(os.Args[1], data, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not write docs: %s\n", err)
|
||||
}
|
||||
|
||||
// Generate jsonschema
|
||||
r := &jsonschema.Reflector{
|
||||
PreferYAMLSchema: true,
|
||||
YAMLEmbeddedStructs: true,
|
||||
FullyQualifyTypeNames: true,
|
||||
}
|
||||
jsonschemaData := r.Reflect(&templates.Template{})
|
||||
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
encoder.SetIndent("", " ")
|
||||
_ = encoder.Encode(jsonschemaData)
|
||||
|
||||
schema := buf.String()
|
||||
for _, match := range pathRegex.FindAllStringSubmatch(schema, -1) {
|
||||
schema = strings.ReplaceAll(schema, match[0], match[1])
|
||||
}
|
||||
err = ioutil.WriteFile(os.Args[2], []byte(schema), 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not write jsonschema: %s\n", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var (
|
||||
success = aurora.Green("[✓]").String()
|
||||
failed = aurora.Red("[✘]").String()
|
||||
githubAction = os.Getenv("GH_ACTION") == "true"
|
||||
|
||||
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"
|
||||
|
||||
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 file.Close()
|
||||
|
||||
errored, failedTestCases := runTestCases(file, debug)
|
||||
|
||||
if githubAction {
|
||||
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
|
||||
}
|
||||
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 {
|
||||
parts := strings.Fields(testcase)
|
||||
|
||||
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)
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# reading os type from arguments
|
||||
CURRENT_OS=$1
|
||||
|
||||
if [ "${CURRENT_OS}" == "windows-latest" ];then
|
||||
extension=.exe
|
||||
fi
|
||||
|
||||
echo "::group::Building functional-test binary"
|
||||
go build -o functional-test$extension
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Building Nuclei binary from current branch"
|
||||
go build -o nuclei_dev$extension ../nuclei
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Building latest release of nuclei"
|
||||
go build -o nuclei$extension -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei
|
||||
echo "::endgroup::"
|
||||
|
||||
echo 'Starting Nuclei functional test'
|
||||
./functional-test$extension -main ./nuclei$extension -dev ./nuclei_dev$extension -testcases testcases.txt
|
||||
@@ -0,0 +1,51 @@
|
||||
{{binary}}
|
||||
{{binary}} -tags cve
|
||||
{{binary}} -tags cve,exposure
|
||||
{{binary}} -tags cve,exposure -tags token
|
||||
{{binary}} -tags cve,exposure -tags token,logs
|
||||
{{binary}} -tags "cve","exposure" -tags "token","logs"
|
||||
{{binary}} -tags 'cve','exposure' -tags 'token','logs'
|
||||
{{binary}} -tags cve -severity high
|
||||
{{binary}} -tags cve,exposure -severity high,critical
|
||||
{{binary}} -tags cve,exposure -severity high,critical,medium
|
||||
{{binary}} -tags cve -author geeknik
|
||||
{{binary}} -tags cve -author geeknik,pdteam
|
||||
{{binary}} -tags cve -author geeknik -severity high
|
||||
{{binary}} -tags cve
|
||||
{{binary}} -tags cve,exposure
|
||||
{{binary}} -tags cve,exposure -tags token
|
||||
{{binary}} -tags cve,exposure -tags token,logs
|
||||
{{binary}} -tags "cve","exposure" -tags "token","logs"
|
||||
{{binary}} -tags 'cve','exposure' -tags 'token','logs'
|
||||
{{binary}} -tags cve -severity high
|
||||
{{binary}} -tags cve,exposure -severity high,critical
|
||||
{{binary}} -tags cve,exposure -severity high,critical,medium
|
||||
{{binary}} -tags cve -author geeknik
|
||||
{{binary}} -tags cve -author geeknik,pdteam
|
||||
{{binary}} -tags cve -author geeknik -severity high
|
||||
{{binary}} -tags cve,exposure -author geeknik,pdteam -severity high,critical
|
||||
{{binary}} -tags "cve,exposure" -author "geeknik,pdteam" -severity high,critical
|
||||
{{binary}} -tags cve -etags ssrf
|
||||
{{binary}} -tags cve,exposure -etags ssrf,config
|
||||
{{binary}} -tags cve,exposure -etags ssrf,config -severity high
|
||||
{{binary}} -tags cve,exposure -etags ssrf,config -severity high -author geeknik
|
||||
{{binary}} -tags cve,dos,fuzz
|
||||
{{binary}} -tags cve -include-tags dos,fuzz
|
||||
{{binary}} -tags cve -exclude-tags cve2020
|
||||
{{binary}} -tags cve -exclude-templates cves/2020/
|
||||
{{binary}} -tags cve -exclude-templates cves/2020/CVE-2020-9757.yaml
|
||||
{{binary}} -tags cve -exclude-templates cves/2020/CVE-2020-9757.yaml -exclude-templates cves/2021/
|
||||
{{binary}} -t cves/
|
||||
{{binary}} -t cves/ -t exposures/
|
||||
{{binary}} -t cves/ -t exposures/ -tags config
|
||||
{{binary}} -t cves/ -t exposures/ -tags config,ssrf
|
||||
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical
|
||||
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam
|
||||
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam -etags sqli
|
||||
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam -etags sqli -exclude-templates cves/2021/
|
||||
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam -etags sqli -exclude-templates cves/2017/CVE-2017-7269.yaml
|
||||
{{binary}} -t cves/ -t exposures/ -tags config -severity high,critical -author geeknik,pdteam -etags sqli -include-templates cves/2017/CVE-2017-7269.yaml
|
||||
{{binary}} -w workflows
|
||||
{{binary}} -w workflows -author geeknik,pdteam
|
||||
{{binary}} -w workflows -severity high,critical
|
||||
{{binary}} -w workflows -author geeknik,pdteam -severity high,critical
|
||||
@@ -1,28 +1,59 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/testutils"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var dnsTestCases = map[string]testutils.TestCase{
|
||||
"dns/basic.yaml": &dnsBasic{},
|
||||
"dns/ptr.yaml": &dnsPtr{},
|
||||
"dns/caa.yaml": &dnsCAA{},
|
||||
}
|
||||
|
||||
type dnsBasic struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *dnsBasic) Execute(filePath string) error {
|
||||
var routerErr error
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, "one.one.one.one", debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "one.one.one.one", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
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 {
|
||||
var routerErr error
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "1.1.1.1", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
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 {
|
||||
var routerErr error
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "google.com", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var headlessTestcases = map[string]testutils.TestCase{
|
||||
"headless/headless-basic.yaml": &headlessBasic{},
|
||||
"headless/headless-header-action.yaml": &headlessHeaderActions{},
|
||||
"headless/headless-extract-values.yaml": &headlessExtractValues{},
|
||||
"headless/headless-payloads.yaml": &headlessPayloads{},
|
||||
}
|
||||
|
||||
type headlessBasic struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *headlessBasic) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = w.Write([]byte("<html><body></body></html>"))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type headlessHeaderActions struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *headlessHeaderActions) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
testValue := r.Header.Get("test")
|
||||
if r.Header.Get("test") != "" {
|
||||
_, _ = w.Write([]byte("<html><body>" + testValue + "</body></html>"))
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type headlessExtractValues struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *headlessExtractValues) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = w.Write([]byte("<html><body><a href='/test.html'>test</a></body></html>"))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 3)
|
||||
}
|
||||
|
||||
type headlessPayloads struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *headlessPayloads) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = w.Write([]byte("<html><body>test</body></html>"))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-headless")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 4)
|
||||
}
|
||||
+412
-167
@@ -8,144 +8,256 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/http/httputil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/testutils"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var httpTestcases = map[string]testutils.TestCase{
|
||||
"http/get-headers.yaml": &httpGetHeaders{},
|
||||
"http/get-query-string.yaml": &httpGetQueryString{},
|
||||
"http/get-redirects.yaml": &httpGetRedirects{},
|
||||
"http/get.yaml": &httpGet{},
|
||||
"http/post-body.yaml": &httpPostBody{},
|
||||
"http/post-json-body.yaml": &httpPostJSONBody{},
|
||||
"http/post-multipart-body.yaml": &httpPostMultipartBody{},
|
||||
"http/raw-cookie-reuse.yaml": &httpRawCookieReuse{},
|
||||
"http/raw-dynamic-extractor.yaml": &httpRawDynamicExtractor{},
|
||||
"http/raw-get-query.yaml": &httpRawGetQuery{},
|
||||
"http/raw-get.yaml": &httpRawGet{},
|
||||
"http/raw-payload.yaml": &httpRawPayload{},
|
||||
"http/raw-post-body.yaml": &httpRawPostBody{},
|
||||
"http/raw-unsafe-request.yaml": &httpRawUnsafeRequest{},
|
||||
"http/request-condition.yaml": &httpRequestCondition{},
|
||||
"http/request-condition-new.yaml": &httpRequestCondition{},
|
||||
"http/get-headers.yaml": &httpGetHeaders{},
|
||||
"http/get-query-string.yaml": &httpGetQueryString{},
|
||||
"http/get-redirects.yaml": &httpGetRedirects{},
|
||||
"http/get.yaml": &httpGet{},
|
||||
"http/post-body.yaml": &httpPostBody{},
|
||||
"http/post-json-body.yaml": &httpPostJSONBody{},
|
||||
"http/post-multipart-body.yaml": &httpPostMultipartBody{},
|
||||
"http/raw-cookie-reuse.yaml": &httpRawCookieReuse{},
|
||||
"http/raw-dynamic-extractor.yaml": &httpRawDynamicExtractor{},
|
||||
"http/raw-get-query.yaml": &httpRawGetQuery{},
|
||||
"http/raw-get.yaml": &httpRawGet{},
|
||||
"http/raw-payload.yaml": &httpRawPayload{},
|
||||
"http/raw-post-body.yaml": &httpRawPostBody{},
|
||||
"http/raw-unsafe-request.yaml": &httpRawUnsafeRequest{},
|
||||
"http/request-condition.yaml": &httpRequestCondition{},
|
||||
"http/request-condition-new.yaml": &httpRequestCondition{},
|
||||
"http/interactsh.yaml": &httpInteractshRequest{},
|
||||
"http/interactsh-stop-at-first-match.yaml": &httpInteractshStopAtFirstMatchRequest{},
|
||||
"http/self-contained.yaml": &httpRequestSelContained{},
|
||||
"http/get-case-insensitive.yaml": &httpGetCaseInsensitive{},
|
||||
"http/get.yaml,http/get-case-insensitive.yaml": &httpGetCaseInsensitiveCluster{},
|
||||
"http/get-redirects-chain-headers.yaml": &httpGetRedirectsChainHeaders{},
|
||||
"http/dsl-matcher-variable.yaml": &httpDSLVariable{},
|
||||
"http/dsl-functions.yaml": &httpDSLFunctions{},
|
||||
"http/race-simple.yaml": &httpRaceSimple{},
|
||||
"http/race-multiple.yaml": &httpRaceMultiple{},
|
||||
"http/stop-at-first-match.yaml": &httpStopAtFirstMatch{},
|
||||
"http/stop-at-first-match-with-extractors.yaml": &httpStopAtFirstMatchWithExtractors{},
|
||||
}
|
||||
|
||||
func httpDebugRequestDump(r *http.Request) {
|
||||
if debug {
|
||||
if dump, err := httputil.DumpRequest(r, true); err == nil {
|
||||
fmt.Printf("\nRequest dump: \n%s\n\n", string(dump))
|
||||
type httpInteractshRequest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpInteractshRequest) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
value := r.Header.Get("url")
|
||||
if value != "" {
|
||||
if resp, _ := http.DefaultClient.Get(value); resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpInteractshStopAtFirstMatchRequest struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpInteractshStopAtFirstMatchRequest) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
value := r.Header.Get("url")
|
||||
if value != "" {
|
||||
if resp, _ := http.DefaultClient.Get(value); resp != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpGetHeaders struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpGetHeaders) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
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.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpGetQueryString struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpGetQueryString) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if strings.EqualFold(r.URL.Query().Get("test"), "nuclei") {
|
||||
fmt.Fprintf(w, "This is test querystring matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpGetRedirects struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpGetRedirects) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
http.Redirect(w, r, "/redirected", http.StatusFound)
|
||||
}))
|
||||
router.GET("/redirected", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
})
|
||||
router.GET("/redirected", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test redirects matcher text")
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpGet struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpGet) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test matcher text")
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpDSLVariable struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpDSLVariable) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "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, 5)
|
||||
}
|
||||
|
||||
type httpDSLFunctions struct{}
|
||||
|
||||
func (h *httpDSLFunctions) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
request, err := httputil.DumpRequest(r, true)
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprint(w, err.Error())
|
||||
} else {
|
||||
_, _ = fmt.Fprint(w, string(request))
|
||||
}
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-nc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := expectResultsCount(results, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resultPattern := regexp.MustCompile(`\[[^]]+] \[[^]]+] \[[^]]+] [^]]+ \[([^]]+)]`)
|
||||
submatch := resultPattern.FindStringSubmatch(results[0])
|
||||
if len(submatch) != 2 {
|
||||
return errors.New("could not parse the result")
|
||||
}
|
||||
|
||||
totalExtracted := strings.Split(submatch[1], ",")
|
||||
numberOfDslFunctions := 54
|
||||
if len(totalExtracted) != numberOfDslFunctions {
|
||||
return errors.New("incorrect number of results")
|
||||
}
|
||||
|
||||
for _, header := range totalExtracted {
|
||||
parts := strings.Split(header, ": ")
|
||||
index, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if index < 0 || index > numberOfDslFunctions {
|
||||
return fmt.Errorf("incorrect header index found: %d", index)
|
||||
}
|
||||
if strings.TrimSpace(parts[1]) == "" {
|
||||
return fmt.Errorf("the DSL expression with index %d was not evaluated correctly", index)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type httpPostBody struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpPostBody) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.POST("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
@@ -153,33 +265,29 @@ func (h *httpPostBody) Execute(filePath string) error {
|
||||
if strings.EqualFold(r.Form.Get("username"), "test") && strings.EqualFold(r.Form.Get("password"), "nuclei") {
|
||||
fmt.Fprintf(w, "This is test post-body matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpPostJSONBody struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpPostJSONBody) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.POST("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
|
||||
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
type doc struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
@@ -192,32 +300,29 @@ func (h *httpPostJSONBody) Execute(filePath string) error {
|
||||
if strings.EqualFold(obj.Username, "test") && strings.EqualFold(obj.Password, "nuclei") {
|
||||
fmt.Fprintf(w, "This is test post-json-body matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpPostMultipartBody struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpPostMultipartBody) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.POST("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if err := r.ParseMultipartForm(1 * 1024); err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
@@ -235,32 +340,29 @@ func (h *httpPostMultipartBody) Execute(filePath string) error {
|
||||
if strings.EqualFold(password[0], "nuclei") && strings.EqualFold(file[0].Filename, "username") {
|
||||
fmt.Fprintf(w, "This is test post-multipart matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRawDynamicExtractor struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRawDynamicExtractor) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.POST("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
@@ -268,95 +370,84 @@ func (h *httpRawDynamicExtractor) Execute(filePath string) error {
|
||||
if strings.EqualFold(r.Form.Get("testing"), "parameter") {
|
||||
fmt.Fprintf(w, "Token: 'nuclei'")
|
||||
}
|
||||
}))
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
})
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if strings.EqualFold(r.URL.Query().Get("username"), "nuclei") {
|
||||
fmt.Fprintf(w, "Test is test-dynamic-extractor-raw matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRawGetQuery struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRawGetQuery) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if strings.EqualFold(r.URL.Query().Get("test"), "nuclei") {
|
||||
fmt.Fprintf(w, "Test is test raw-get-query-matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRawGet struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRawGet) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "Test is test raw-get-matcher text")
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRawPayload struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRawPayload) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.POST("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
@@ -367,32 +458,29 @@ func (h *httpRawPayload) Execute(filePath string) error {
|
||||
if strings.EqualFold(r.Form.Get("username"), "test") && (strings.EqualFold(r.Form.Get("password"), "nuclei") || strings.EqualFold(r.Form.Get("password"), "guest")) {
|
||||
fmt.Fprintf(w, "Test is raw-payload matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 2 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
type httpRawPostBody struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRawPostBody) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.POST("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
@@ -400,32 +488,29 @@ func (h *httpRawPostBody) Execute(filePath string) error {
|
||||
if strings.EqualFold(r.Form.Get("username"), "test") && strings.EqualFold(r.Form.Get("password"), "nuclei") {
|
||||
fmt.Fprintf(w, "Test is test raw-post-body-matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRawCookieReuse struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRawCookieReuse) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.POST("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.POST("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
@@ -433,9 +518,8 @@ func (h *httpRawCookieReuse) Execute(filePath string) error {
|
||||
if strings.EqualFold(r.Form.Get("testing"), "parameter") {
|
||||
http.SetCookie(w, &http.Cookie{Name: "nuclei", Value: "test"})
|
||||
}
|
||||
}))
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
})
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
routerErr = err
|
||||
return
|
||||
@@ -449,76 +533,237 @@ func (h *httpRawCookieReuse) Execute(filePath string) error {
|
||||
if strings.EqualFold(cookie.Value, "test") {
|
||||
fmt.Fprintf(w, "Test is test-cookie-reuse matcher text")
|
||||
}
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRawUnsafeRequest struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRawUnsafeRequest) Execute(filePath string) error {
|
||||
var routerErr error
|
||||
|
||||
ts := testutils.NewTCPServer(func(conn net.Conn) {
|
||||
ts := testutils.NewTCPServer(false, defaultStaticPort, func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
_, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 40\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Thu, 25 Feb 2021 17:17:28 GMT\r\n\r\nThis is test-raw-unsafe request matcher.\r\n"))
|
||||
_, _ = conn.Write([]byte("HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 36\r\nContent-Type: text/plain; charset=utf-8\r\n\r\nThis is test raw-unsafe-matcher test"))
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, "http://"+ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "http://"+ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRequestCondition struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRequestCondition) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.GET("/200", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/200", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
router.GET("/400", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
})
|
||||
router.GET("/400", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.WriteHeader(400)
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRequestSelContained struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRequestSelContained) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
var routerErr error
|
||||
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = w.Write([]byte("This is self-contained response"))
|
||||
})
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf("localhost:%d", defaultStaticPort),
|
||||
Handler: router,
|
||||
}
|
||||
return nil
|
||||
go func() {
|
||||
_ = server.ListenAndServe()
|
||||
}()
|
||||
defer server.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpGetCaseInsensitive struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpGetCaseInsensitive) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "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, 1)
|
||||
}
|
||||
|
||||
type httpGetCaseInsensitiveCluster struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpGetCaseInsensitiveCluster) Execute(filesPath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test matcher text")
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
files := strings.Split(filesPath, ",")
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(files[0], ts.URL, debug, "-t", files[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
type httpGetRedirectsChainHeaders struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpGetRedirectsChainHeaders) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
http.Redirect(w, r, "/redirected", http.StatusFound)
|
||||
})
|
||||
router.GET("/redirected", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.Header().Set("Secret", "TestRedirectHeaderMatch")
|
||||
http.Redirect(w, r, "/final", http.StatusFound)
|
||||
})
|
||||
router.GET("/final", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
_, _ = w.Write([]byte("ok"))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpRaceSimple struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRaceSimple) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 10)
|
||||
}
|
||||
|
||||
type httpRaceMultiple struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpRaceMultiple) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 5)
|
||||
}
|
||||
|
||||
type httpStopAtFirstMatch struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpStopAtFirstMatch) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test")
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type httpStopAtFirstMatchWithExtractors struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *httpStopAtFirstMatchWithExtractors) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test")
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
@@ -6,45 +6,102 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/testutils"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var (
|
||||
debug = os.Getenv("DEBUG") == "true"
|
||||
customTest = os.Getenv("TEST")
|
||||
protocol = os.Getenv("PROTO")
|
||||
debug = os.Getenv("DEBUG") == "true"
|
||||
githubAction = os.Getenv("GH_ACTION") == "true"
|
||||
customTests = os.Getenv("TESTS")
|
||||
|
||||
success = aurora.Green("[✓]").String()
|
||||
failed = aurora.Red("[✘]").String()
|
||||
|
||||
protocolTests = map[string]map[string]testutils.TestCase{
|
||||
"http": httpTestcases,
|
||||
"network": networkTestcases,
|
||||
"dns": dnsTestCases,
|
||||
"workflow": workflowTestcases,
|
||||
"loader": loaderTestcases,
|
||||
"websocket": websocketTestCases,
|
||||
"headless": headlessTestcases,
|
||||
"whois": whoisTestCases,
|
||||
"ssl": sslTestcases,
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
success := aurora.Green("[✓]").String()
|
||||
failed := aurora.Red("[✘]").String()
|
||||
failedTestTemplatePaths := runTests(toMap(toSlice(customTests)))
|
||||
|
||||
protocolTests := map[string]map[string]testutils.TestCase{
|
||||
"http": httpTestcases,
|
||||
"network": networkTestcases,
|
||||
"dns": dnsTestCases,
|
||||
"workflow": workflowTestcases,
|
||||
if len(failedTestTemplatePaths) > 0 {
|
||||
if githubAction {
|
||||
debug = true
|
||||
fmt.Println("::group::Failed integration tests in debug mode")
|
||||
_ = runTests(failedTestTemplatePaths)
|
||||
fmt.Println("::endgroup::")
|
||||
}
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
for proto, tests := range protocolTests {
|
||||
if protocol == "" || protocol == proto {
|
||||
fmt.Printf("Running test cases for \"%s\" protocol\n", aurora.Blue(proto))
|
||||
}
|
||||
|
||||
for file, test := range tests {
|
||||
if customTest != "" && !strings.Contains(file, customTest) {
|
||||
continue // only run tests user asked
|
||||
}
|
||||
err := test.Execute(file)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed: %s\n", failed, file, err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
fmt.Printf("%s Test \"%s\" passed!\n", success, file)
|
||||
func runTests(customTemplatePaths map[string]struct{}) map[string]struct{} {
|
||||
failedTestTemplatePaths := map[string]struct{}{}
|
||||
|
||||
for proto, testCases := range protocolTests {
|
||||
if len(customTemplatePaths) == 0 {
|
||||
fmt.Printf("Running test cases for %q protocol\n", aurora.Blue(proto))
|
||||
}
|
||||
|
||||
for templatePath, testCase := range testCases {
|
||||
if len(customTemplatePaths) == 0 || contains(customTemplatePaths, templatePath) {
|
||||
if err, failedTemplatePath := execute(testCase, templatePath); err != nil {
|
||||
failedTestTemplatePaths[failedTemplatePath] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return failedTestTemplatePaths
|
||||
}
|
||||
|
||||
func errIncorrectResultsCount(results []string) error {
|
||||
return fmt.Errorf("incorrect number of results %s", strings.Join(results, "\n\t"))
|
||||
func execute(testCase testutils.TestCase, templatePath string) (error, string) {
|
||||
if err := testCase.Execute(templatePath); err != nil {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed: %s\n", failed, templatePath, err)
|
||||
return err, templatePath
|
||||
}
|
||||
|
||||
fmt.Printf("%s Test \"%s\" passed!\n", success, templatePath)
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
func expectResultsCount(results []string, expectedNumber int) error {
|
||||
if len(results) != expectedNumber {
|
||||
return fmt.Errorf("incorrect number of results: %d (actual) vs %d (expected) \nResults:\n\t%s\n", len(results), expectedNumber, strings.Join(results, "\n\t"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toSlice(value string) []string {
|
||||
if strings.TrimSpace(value) == "" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
return strings.Split(value, ",")
|
||||
}
|
||||
|
||||
func toMap(slice []string) map[string]struct{} {
|
||||
result := make(map[string]struct{}, len(slice))
|
||||
for _, value := range slice {
|
||||
if _, ok := result[value]; !ok {
|
||||
result[value] = struct{}{}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func contains(input map[string]struct{}, value string) bool {
|
||||
_, ok := input[value]
|
||||
return ok
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var loaderTestcases = map[string]testutils.TestCase{
|
||||
"loader/template-list.yaml": &remoteTemplateList{},
|
||||
"loader/workflow-list.yaml": &remoteWorkflowList{},
|
||||
"loader/nonexistent-template-list.yaml": &nonExistentTemplateList{},
|
||||
"loader/nonexistent-workflow-list.yaml": &nonExistentWorkflowList{},
|
||||
"loader/template-list-not-allowed.yaml": &remoteTemplateListNotAllowed{},
|
||||
}
|
||||
|
||||
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 := ioutil.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove("test-config.yaml")
|
||||
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-tu", ts.URL+"/template_list", "-config", "test-config.yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
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, "-target", ts.URL, "-tu", 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 := ioutil.WriteFile("test-config.yaml", []byte(configFileData), os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove("test-config.yaml")
|
||||
|
||||
results, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-wu", 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()
|
||||
|
||||
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-tu", ts.URL+"/404")
|
||||
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()
|
||||
|
||||
_, err := testutils.RunNucleiBareArgsAndGetResults(debug, "-target", ts.URL, "-wu", ts.URL+"/404")
|
||||
if err == nil {
|
||||
return fmt.Errorf("expected error for nonexisting workflow url")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -3,22 +3,25 @@ package main
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/testutils"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var networkTestcases = map[string]testutils.TestCase{
|
||||
"network/basic.yaml": &networkBasic{},
|
||||
"network/hex.yaml": &networkBasic{},
|
||||
"network/multi-step.yaml": &networkMultiStep{},
|
||||
"network/basic.yaml": &networkBasic{},
|
||||
"network/hex.yaml": &networkBasic{},
|
||||
"network/multi-step.yaml": &networkMultiStep{},
|
||||
"network/self-contained.yaml": &networkRequestSelContained{},
|
||||
}
|
||||
|
||||
const defaultStaticPort = 5431
|
||||
|
||||
type networkBasic struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkBasic) Execute(filePath string) error {
|
||||
var routerErr error
|
||||
|
||||
ts := testutils.NewTCPServer(func(conn net.Conn) {
|
||||
ts := testutils.NewTCPServer(false, defaultStaticPort, func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
data := make([]byte, 4)
|
||||
@@ -32,26 +35,24 @@ func (h *networkBasic) Execute(filePath string) error {
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type networkMultiStep struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *networkMultiStep) Execute(filePath string) error {
|
||||
var routerErr error
|
||||
|
||||
ts := testutils.NewTCPServer(func(conn net.Conn) {
|
||||
ts := testutils.NewTCPServer(false, defaultStaticPort, func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
data := make([]byte, 5)
|
||||
@@ -75,15 +76,43 @@ func (h *networkMultiStep) Execute(filePath string) error {
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiAndGetResults(filePath, ts.URL, debug)
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
|
||||
var expectedResultsSize int
|
||||
if debug {
|
||||
expectedResultsSize = 3
|
||||
} else {
|
||||
expectedResultsSize = 1
|
||||
}
|
||||
return nil
|
||||
|
||||
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 {
|
||||
var routerErr error
|
||||
|
||||
ts := testutils.NewTCPServer(false, defaultStaticPort, func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
_, _ = conn.Write([]byte("Authentication successful"))
|
||||
})
|
||||
defer ts.Close()
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if routerErr != nil {
|
||||
return routerErr
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var sslTestcases = map[string]testutils.TestCase{
|
||||
"ssl/basic.yaml": &sslBasic{},
|
||||
"ssl/basic-ztls.yaml": &sslBasicZtls{},
|
||||
}
|
||||
|
||||
type sslBasic struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *sslBasic) Execute(filePath string) error {
|
||||
ts := testutils.NewTCPServer(true, defaultStaticPort, func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
|
||||
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(true, defaultStaticPort, func(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
data := make([]byte, 4)
|
||||
if _, err := conn.Read(data); err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
defer ts.Close()
|
||||
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-ztls")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var websocketTestCases = map[string]testutils.TestCase{
|
||||
"websocket/basic.yaml": &websocketBasic{},
|
||||
"websocket/cswsh.yaml": &websocketCswsh{},
|
||||
"websocket/no-cswsh.yaml": &websocketNoCswsh{},
|
||||
"websocket/path.yaml": &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)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var whoisTestCases = map[string]testutils.TestCase{
|
||||
"whois/basic.yaml": &whoisBasic{},
|
||||
}
|
||||
|
||||
type whoisBasic struct{}
|
||||
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *whoisBasic) Execute(filePath string) error {
|
||||
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, "https://example.com", debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -6,7 +6,8 @@ import (
|
||||
"net/http/httptest"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/testutils"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
var workflowTestcases = map[string]testutils.TestCase{
|
||||
@@ -18,13 +19,12 @@ var workflowTestcases = map[string]testutils.TestCase{
|
||||
|
||||
type workflowBasic struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *workflowBasic) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test matcher text")
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
@@ -32,21 +32,18 @@ func (h *workflowBasic) Execute(filePath string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 2 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 2)
|
||||
}
|
||||
|
||||
type workflowConditionMatched struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *workflowConditionMatched) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test matcher text")
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
@@ -54,21 +51,18 @@ func (h *workflowConditionMatched) Execute(filePath string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
|
||||
type workflowConditionUnmatch struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *workflowConditionUnmatch) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test matcher text")
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
@@ -76,21 +70,18 @@ func (h *workflowConditionUnmatch) Execute(filePath string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 0 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 0)
|
||||
}
|
||||
|
||||
type workflowMatcherName struct{}
|
||||
|
||||
// Executes executes a test case and returns an error if occurred
|
||||
// Execute executes a test case and returns an error if occurred
|
||||
func (h *workflowMatcherName) Execute(filePath string) error {
|
||||
router := httprouter.New()
|
||||
router.GET("/", httprouter.Handle(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
httpDebugRequestDump(r)
|
||||
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
fmt.Fprintf(w, "This is test matcher text")
|
||||
}))
|
||||
})
|
||||
ts := httptest.NewServer(router)
|
||||
defer ts.Close()
|
||||
|
||||
@@ -98,8 +89,6 @@ func (h *workflowMatcherName) Execute(filePath string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(results) != 1 {
|
||||
return errIncorrectResultsCount(results)
|
||||
}
|
||||
return nil
|
||||
|
||||
return expectResultsCount(results, 1)
|
||||
}
|
||||
@@ -1,47 +1,68 @@
|
||||
#allow-list:
|
||||
# severity: high,critical
|
||||
# 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: ""
|
||||
# # username is the username of the github user
|
||||
# username: ""
|
||||
# # owner is the owner name of the repository for issues.
|
||||
# owner: ""
|
||||
# # token is the token for github account.
|
||||
# token: ""
|
||||
# # project-name is the name of the repository.
|
||||
# project-name: ""
|
||||
#
|
||||
# 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: ""
|
||||
|
||||
# gitlab contains configuration options for gitlab issue tracker
|
||||
#gitlab:
|
||||
# # base-url is the optional self-hosted gitlab application url
|
||||
# base-url: ""
|
||||
# # username is the username of the gitlab user
|
||||
# username: ""
|
||||
# # token is the token for gitlab account.
|
||||
# token: ""
|
||||
# # project-id is the ID of the repository.
|
||||
# project-id: ""
|
||||
# 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: ""
|
||||
|
||||
# jira contains configuration options for jira issue tracker
|
||||
#jira:
|
||||
# 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: ""
|
||||
# # account-id is the account-id of the jira user
|
||||
# account-id: ""
|
||||
# # email is the email of the user for jira instance
|
||||
# email: ""
|
||||
# # token is the token for jira instance.
|
||||
# token: ""
|
||||
# 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: ""
|
||||
# project-name: test-project-name
|
||||
# # issue-type is the name of the created issue type
|
||||
# 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
|
||||
+197
-60
@@ -1,12 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/projectdiscovery/fileutil"
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/interactsh/pkg/client"
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/runner"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
|
||||
templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||
)
|
||||
|
||||
@@ -16,6 +24,10 @@ var (
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := runner.ConfigureOptions(); err != nil {
|
||||
gologger.Fatal().Msgf("Could not initialize options: %s\n", err)
|
||||
}
|
||||
|
||||
readConfig()
|
||||
|
||||
runner.ParseOptions(options)
|
||||
@@ -24,73 +36,198 @@ func main() {
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not create runner: %s\n", err)
|
||||
}
|
||||
nucleiRunner.RunEnumeration()
|
||||
if nucleiRunner == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Setup graceful exits
|
||||
resumeFileName := types.DefaultResumeFilePath()
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
go func() {
|
||||
for range c {
|
||||
gologger.Info().Msgf("CTRL+C pressed: Exiting\n")
|
||||
nucleiRunner.Close()
|
||||
if options.ShouldSaveResume() {
|
||||
gologger.Info().Msgf("Creating resume file: %s\n", resumeFileName)
|
||||
err := nucleiRunner.SaveResumeConfig()
|
||||
if err != nil {
|
||||
gologger.Error().Msgf("Couldn't create resume file: %s\n", err)
|
||||
}
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := nucleiRunner.RunEnumeration(); err != nil {
|
||||
gologger.Fatal().Msgf("Could not run nuclei: %s\n", err)
|
||||
}
|
||||
nucleiRunner.Close()
|
||||
// on successful execution remove the resume file in case it exists
|
||||
if fileutil.FileExists(resumeFileName) {
|
||||
os.Remove(resumeFileName)
|
||||
}
|
||||
}
|
||||
|
||||
func readConfig() {
|
||||
home, _ := os.UserHomeDir()
|
||||
templatesDirectory := path.Join(home, "nuclei-templates")
|
||||
templatesDirectory := filepath.Join(home, "nuclei-templates")
|
||||
|
||||
set := goflags.New()
|
||||
set.SetDescription(`Nuclei is a fast tool for configurable targeted scanning
|
||||
based on templates offering massive extensibility and ease of use.`)
|
||||
set.StringVar(&cfgFile, "config", "", "Nuclei configuration file")
|
||||
set.BoolVar(&options.Metrics, "metrics", false, "Expose nuclei metrics on a port")
|
||||
set.IntVar(&options.MetricsPort, "metrics-port", 9092, "Port to expose nuclei metrics on")
|
||||
set.StringVarP(&options.Target, "target", "u", "", "URL to scan with nuclei")
|
||||
set.StringSliceVarP(&options.Templates, "templates", "t", []string{}, "Templates to run, supports single and multiple templates using directory.")
|
||||
set.StringSliceVarP(&options.Workflows, "workflows", "w", []string{}, "Workflows to run for nuclei")
|
||||
set.StringSliceVarP(&options.ExcludedTemplates, "exclude", "et", []string{}, "Templates to exclude, supports single and multiple templates using directory.")
|
||||
set.StringSliceVarP(&options.Severity, "severity", "impact", []string{}, "Templates to run based on severity, supports single and multiple severity.")
|
||||
set.StringVarP(&options.Targets, "list", "l", "", "List of URLs to run templates on")
|
||||
set.StringVarP(&options.Output, "output", "o", "", "File to write output to (optional)")
|
||||
set.StringVar(&options.ProxyURL, "proxy-url", "", "URL of the proxy server")
|
||||
set.StringVar(&options.ProxySocksURL, "proxy-socks-url", "", "URL of the proxy socks server")
|
||||
set.BoolVar(&options.Silent, "silent", false, "Show only results in output")
|
||||
set.BoolVar(&options.Version, "version", false, "Show version of nuclei")
|
||||
set.BoolVarP(&options.Verbose, "verbose", "v", false, "Show verbose output")
|
||||
set.BoolVarP(&options.NoColor, "no-color", "nc", false, "Disable colors in output")
|
||||
set.IntVar(&options.Timeout, "timeout", 5, "Time to wait in seconds before timeout")
|
||||
set.IntVar(&options.Retries, "retries", 1, "Number of times to retry a failed request")
|
||||
set.BoolVarP(&options.RandomAgent, "random-agent", "ra", false, "Use randomly selected HTTP User-Agent header value")
|
||||
set.StringSliceVarP(&options.CustomHeaders, "header", "H", []string{}, "Custom Header.")
|
||||
set.BoolVar(&options.Debug, "debug", false, "Debugging request and responses")
|
||||
set.BoolVar(&options.DebugRequests, "debug-req", false, "Debugging request")
|
||||
set.BoolVar(&options.DebugResponse, "debug-resp", false, "Debugging response")
|
||||
set.BoolVarP(&options.UpdateTemplates, "update-templates", "ut", false, "Download / updates nuclei community templates")
|
||||
set.StringVar(&options.TraceLogFile, "trace-log", "", "File to write sent requests trace log")
|
||||
set.StringVarP(&options.TemplatesDirectory, "update-directory", "ud", templatesDirectory, "Directory storing nuclei-templates")
|
||||
set.BoolVar(&options.JSON, "json", false, "Write json output to files")
|
||||
set.BoolVarP(&options.JSONRequests, "include-rr", "irr", false, "Write requests/responses for matches in JSON output")
|
||||
set.BoolVar(&options.EnableProgressBar, "stats", false, "Display stats of the running scan")
|
||||
set.BoolVar(&options.TemplateList, "tl", false, "List available templates")
|
||||
set.IntVarP(&options.RateLimit, "rate-limit", "rl", 150, "Maximum requests to send per second")
|
||||
set.BoolVarP(&options.StopAtFirstMatch, "stop-at-first-path", "spm", false, "Stop processing http requests at first match (this may break template/workflow logic)")
|
||||
set.IntVarP(&options.BulkSize, "bulk-size", "bs", 25, "Maximum Number of hosts analyzed in parallel per template")
|
||||
set.IntVarP(&options.TemplateThreads, "concurrency", "c", 10, "Maximum Number of templates executed in parallel")
|
||||
set.BoolVar(&options.Project, "project", false, "Use a project folder to avoid sending same request multiple times")
|
||||
set.StringVar(&options.ProjectPath, "project-path", "", "Use a user defined project folder, temporary folder is used if not specified but enabled")
|
||||
set.BoolVarP(&options.NoMeta, "no-meta", "nm", false, "Don't display metadata for the matches")
|
||||
set.BoolVarP(&options.TemplatesVersion, "templates-version", "tv", false, "Shows the installed nuclei-templates version")
|
||||
set.BoolVar(&options.OfflineHTTP, "passive", false, "Enable Passive HTTP response processing mode")
|
||||
set.StringVarP(&options.BurpCollaboratorBiid, "burp-collaborator-biid", "biid", "", "Burp Collaborator BIID")
|
||||
set.StringVarP(&options.ReportingConfig, "report-config", "rc", "", "Nuclei Reporting Module configuration file")
|
||||
set.StringVarP(&options.ReportingDB, "report-db", "rdb", "", "Local Nuclei Reporting Database (Always use this to persistent report data)")
|
||||
set.StringSliceVar(&options.Tags, "tags", []string{}, "Tags to execute templates for")
|
||||
set.StringSliceVarP(&options.ExcludeTags, "exclude-tags", "etags", []string{}, "Exclude templates with the provided tags")
|
||||
set.StringVarP(&options.ResolversFile, "resolvers", "r", "", "File containing resolver list for nuclei")
|
||||
set.BoolVar(&options.Headless, "headless", false, "Enable headless browser based templates support")
|
||||
set.BoolVar(&options.ShowBrowser, "show-browser", false, "Show the browser on the screen")
|
||||
set.IntVarP(&options.StatsInterval, "stats-interval", "si", 5, "Number of seconds between each stats line")
|
||||
set.BoolVar(&options.SystemResolvers, "system-resolvers", false, "Use system dns resolving as error fallback")
|
||||
set.IntVar(&options.PageTimeout, "page-timeout", 20, "Seconds to wait for each page in headless")
|
||||
set.BoolVarP(&options.NewTemplates, "new-templates", "nt", false, "Only run newly added templates")
|
||||
set.StringVarP(&options.DiskExportDirectory, "disk-export", "de", "", "Directory on disk to export reports in markdown to")
|
||||
_ = set.Parse()
|
||||
flagSet := goflags.NewFlagSet()
|
||||
flagSet.SetDescription(`Nuclei is a fast, template based vulnerability scanner focusing
|
||||
on extensive configurability, massive extensibility and ease of use.`)
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
createGroup(flagSet, "input", "Target",
|
||||
flagSet.StringSliceVarP(&options.Targets, "target", "u", []string{}, "target URLs/hosts to scan"),
|
||||
flagSet.StringVarP(&options.TargetsFilePath, "list", "l", "", "path to file containing a list of target URLs/hosts to scan (one per line)"),
|
||||
flagSet.BoolVar(&options.Resume, "resume", false, "Resume scan using resume.cfg (clustering will be disabled)"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "templates", "Templates",
|
||||
|
||||
flagSet.BoolVarP(&options.NewTemplates, "new-templates", "nt", false, "run only new templates added in latest nuclei-templates release"),
|
||||
flagSet.FileNormalizedOriginalStringSliceVarP(&options.Templates, "templates", "t", []string{}, "list of template or template directory to run (comma-separated, file)"),
|
||||
flagSet.FileNormalizedOriginalStringSliceVarP(&options.TemplateURLs, "template-url", "tu", []string{}, "list of template urls to run (comma-separated, file)"),
|
||||
flagSet.FileNormalizedOriginalStringSliceVarP(&options.Workflows, "workflows", "w", []string{}, "list of workflow or workflow directory to run (comma-separated, file)"),
|
||||
flagSet.FileNormalizedOriginalStringSliceVarP(&options.WorkflowURLs, "workflow-url", "wu", []string{}, "list of workflow urls to run (comma-separated, file)"),
|
||||
flagSet.BoolVar(&options.Validate, "validate", false, "validate the passed templates to nuclei"),
|
||||
flagSet.BoolVar(&options.TemplateList, "tl", false, "list all available templates"),
|
||||
flagSet.StringSliceVarConfigOnly(&options.RemoteTemplateDomainList, "remote-template-domain", []string{"api.nuclei.sh"}, "allowed domain list to load remote templates from"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "filters", "Filtering",
|
||||
flagSet.FileNormalizedStringSliceVarP(&options.Authors, "author", "a", []string{}, "templates to run based on authors (comma-separated, file)"),
|
||||
flagSet.FileNormalizedStringSliceVar(&options.Tags, "tags", []string{}, "templates to run based on tags (comma-separated, file)"),
|
||||
flagSet.FileNormalizedStringSliceVarP(&options.ExcludeTags, "exclude-tags", "etags", []string{}, "templates to exclude based on tags (comma-separated, file)"),
|
||||
flagSet.FileNormalizedStringSliceVarP(&options.IncludeTags, "include-tags", "itags", []string{}, "tags to be executed even if they are excluded either by default or configuration"), // TODO show default deny list
|
||||
flagSet.FileNormalizedStringSliceVarP(&options.IncludeIds, "template-id", "id", []string{}, "templates to run based on template ids (comma-separated, file)"),
|
||||
flagSet.FileNormalizedStringSliceVarP(&options.ExcludeIds, "exclude-id", "eid", []string{}, "templates to exclude based on template ids (comma-separated, file)"),
|
||||
flagSet.FileNormalizedOriginalStringSliceVarP(&options.IncludeTemplates, "include-templates", "it", []string{}, "templates to be executed even if they are excluded either by default or configuration"),
|
||||
flagSet.FileNormalizedOriginalStringSliceVarP(&options.ExcludedTemplates, "exclude-templates", "et", []string{}, "template or template directory to exclude (comma-separated, file)"),
|
||||
flagSet.VarP(&options.Severities, "severity", "s", fmt.Sprintf("templates to run based on severity. Possible values: %s", severity.GetSupportedSeverities().String())),
|
||||
flagSet.VarP(&options.ExcludeSeverities, "exclude-severity", "es", fmt.Sprintf("templates to exclude based on severity. Possible values: %s", severity.GetSupportedSeverities().String())),
|
||||
flagSet.VarP(&options.Protocols, "type", "pt", fmt.Sprintf("templates to run based on protocol type. Possible values: %s", templateTypes.GetSupportedProtocolTypes())),
|
||||
flagSet.VarP(&options.ExcludeProtocols, "exclude-type", "ept", fmt.Sprintf("templates to exclude based on protocol type. Possible values: %s", templateTypes.GetSupportedProtocolTypes())),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "output", "Output",
|
||||
flagSet.StringVarP(&options.Output, "output", "o", "", "output file to write found issues/vulnerabilities"),
|
||||
flagSet.BoolVar(&options.Silent, "silent", false, "display findings only"),
|
||||
flagSet.BoolVarP(&options.NoColor, "no-color", "nc", false, "disable output content coloring (ANSI escape codes)"),
|
||||
flagSet.BoolVar(&options.JSON, "json", false, "write output in JSONL(ines) format"),
|
||||
flagSet.BoolVarP(&options.JSONRequests, "include-rr", "irr", false, "include request/response pairs in the JSONL output (for findings only)"),
|
||||
flagSet.BoolVarP(&options.NoMeta, "no-meta", "nm", false, "disable printing result metadata in cli output"),
|
||||
flagSet.BoolVarP(&options.NoTimestamp, "no-timestamp", "nts", false, "disable printing timestamp in cli output"),
|
||||
flagSet.StringVarP(&options.ReportingDB, "report-db", "rdb", "", "nuclei reporting database (always use this to persist report data)"),
|
||||
flagSet.BoolVarP(&options.MatcherStatus, "matcher-status", "ms", false, "display match failure status"),
|
||||
flagSet.StringVarP(&options.MarkdownExportDirectory, "markdown-export", "me", "", "directory to export results in markdown format"),
|
||||
flagSet.StringVarP(&options.SarifExport, "sarif-export", "se", "", "file to export results in SARIF format"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "configs", "Configurations",
|
||||
flagSet.StringVar(&cfgFile, "config", "", "path to the nuclei configuration file"),
|
||||
flagSet.StringVarP(&options.ReportingConfig, "report-config", "rc", "", "nuclei reporting module configuration file"), // TODO merge into the config file or rename to issue-tracking
|
||||
flagSet.StringSliceVarP(&options.CustomHeaders, "header", "H", []string{}, "custom headers in header:value format"),
|
||||
flagSet.RuntimeMapVarP(&options.Vars, "var", "V", []string{}, "custom vars in var=value format"),
|
||||
flagSet.StringVarP(&options.ResolversFile, "resolvers", "r", "", "file containing resolver list for nuclei"),
|
||||
flagSet.BoolVarP(&options.SystemResolvers, "system-resolvers", "sr", false, "use system DNS resolving as error fallback"),
|
||||
flagSet.BoolVar(&options.OfflineHTTP, "passive", false, "enable passive HTTP response processing mode"),
|
||||
flagSet.BoolVarP(&options.EnvironmentVariables, "env-vars", "ev", false, "enable environment variables to be used in template"),
|
||||
flagSet.StringVarP(&options.ClientCertFile, "client-cert", "cc", "", "client certificate file (PEM-encoded) used for authenticating against scanned hosts"),
|
||||
flagSet.StringVarP(&options.ClientKeyFile, "client-key", "ck", "", "client key file (PEM-encoded) used for authenticating against scanned hosts"),
|
||||
flagSet.StringVarP(&options.ClientCAFile, "client-ca", "ca", "", "client certificate authority file (PEM-encoded) used for authenticating against scanned hosts"),
|
||||
flagSet.BoolVar(&options.ZTLS, "ztls", false, "Use ztls library with autofallback to standard one for tls13"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "interactsh", "interactsh",
|
||||
flagSet.StringVarP(&options.InteractshURL, "interactsh-server", "iserver", "", fmt.Sprintf("interactsh server url for self-hosted instance (default: %s)", client.DefaultOptions.ServerURL)),
|
||||
flagSet.StringVarP(&options.InteractshToken, "interactsh-token", "itoken", "", "authentication token for self-hosted interactsh server"),
|
||||
flagSet.IntVar(&options.InteractionsCacheSize, "interactions-cache-size", 5000, "number of requests to keep in the interactions cache"),
|
||||
flagSet.IntVar(&options.InteractionsEviction, "interactions-eviction", 60, "number of seconds to wait before evicting requests from cache"),
|
||||
flagSet.IntVar(&options.InteractionsPollDuration, "interactions-poll-duration", 5, "number of seconds to wait before each interaction poll request"),
|
||||
flagSet.IntVar(&options.InteractionsCoolDownPeriod, "interactions-cooldown-period", 5, "extra time for interaction polling before exiting"),
|
||||
flagSet.BoolVarP(&options.NoInteractsh, "no-interactsh", "ni", false, "disable interactsh server for OAST testing, exclude OAST based templates"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "rate-limit", "Rate-Limit",
|
||||
flagSet.IntVarP(&options.RateLimit, "rate-limit", "rl", 150, "maximum number of requests to send per second"),
|
||||
flagSet.IntVarP(&options.RateLimitMinute, "rate-limit-minute", "rlm", 0, "maximum number of requests to send per minute"),
|
||||
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"),
|
||||
flagSet.IntVarP(&options.HeadlessBulkSize, "headless-bulk-size", "hbs", 10, "maximum number of headless hosts to be analyzed in parallel per template"),
|
||||
flagSet.IntVarP(&options.HeadlessTemplateThreads, "headless-concurrency", "hc", 10, "maximum number of headless templates to be executed in parallel"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "optimization", "Optimizations",
|
||||
flagSet.IntVar(&options.Timeout, "timeout", 5, "time to wait in seconds before timeout"),
|
||||
flagSet.IntVar(&options.Retries, "retries", 1, "number of times to retry a failed request"),
|
||||
flagSet.BoolVarP(&options.LeaveDefaultPorts, "leave-default-ports", "ldp", false, "leave default HTTP/HTTPS ports (eg. host:80,host:443"),
|
||||
flagSet.IntVarP(&options.MaxHostError, "max-host-error", "mhe", 30, "max errors for a host before skipping from scan"),
|
||||
flagSet.BoolVar(&options.Project, "project", false, "use a project folder to avoid sending same request multiple times"),
|
||||
flagSet.StringVar(&options.ProjectPath, "project-path", os.TempDir(), "set a specific project path"),
|
||||
flagSet.BoolVarP(&options.StopAtFirstMatch, "stop-at-first-path", "spm", false, "stop processing HTTP requests after the first match (may break template/workflow logic)"),
|
||||
flagSet.BoolVar(&options.Stream, "stream", false, "stream mode - start elaborating without sorting the input"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "headless", "Headless",
|
||||
flagSet.BoolVar(&options.Headless, "headless", false, "enable templates that require headless browser support (root user on linux will disable sandbox)"),
|
||||
flagSet.IntVar(&options.PageTimeout, "page-timeout", 20, "seconds to wait for each page in headless mode"),
|
||||
flagSet.BoolVarP(&options.ShowBrowser, "show-browser", "sb", false, "show the browser on the screen when running templates with headless mode"),
|
||||
flagSet.BoolVarP(&options.UseInstalledChrome, "system-chrome", "sc", false, "Use local installed chrome browser instead of nuclei installed"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "debug", "Debug",
|
||||
flagSet.BoolVar(&options.Debug, "debug", false, "show all requests and responses"),
|
||||
flagSet.BoolVar(&options.DebugRequests, "debug-req", false, "show all sent requests"),
|
||||
flagSet.BoolVar(&options.DebugResponse, "debug-resp", false, "show all received responses"),
|
||||
flagSet.NormalizedOriginalStringSliceVarP(&options.Proxy, "proxy", "p", []string{}, "List of HTTP(s)/SOCKS5 proxy to use (comma separated or file input)"),
|
||||
flagSet.StringVarP(&options.TraceLogFile, "trace-log", "tlog", "", "file to write sent requests trace log"),
|
||||
flagSet.StringVarP(&options.ErrorLogFile, "error-log", "elog", "", "file to write sent requests error log"),
|
||||
flagSet.BoolVar(&options.Version, "version", false, "show nuclei version"),
|
||||
flagSet.BoolVarP(&options.Verbose, "verbose", "v", false, "show verbose output"),
|
||||
flagSet.BoolVar(&options.VerboseVerbose, "vv", false, "display templates loaded for scan"),
|
||||
flagSet.BoolVarP(&options.TemplatesVersion, "templates-version", "tv", false, "shows the version of the installed nuclei-templates"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "update", "Update",
|
||||
flagSet.BoolVar(&options.UpdateNuclei, "update", 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.TemplatesDirectory, "update-directory", "ud", templatesDirectory, "overwrite the default directory to install nuclei-templates"),
|
||||
flagSet.BoolVarP(&options.NoUpdateTemplates, "disable-update-check", "duc", false, "disable automatic nuclei/templates update check"),
|
||||
)
|
||||
|
||||
createGroup(flagSet, "stats", "Statistics",
|
||||
flagSet.BoolVar(&options.EnableProgressBar, "stats", false, "display statistics about the running scan"),
|
||||
flagSet.BoolVarP(&options.StatsJSON, "stats-json", "sj", false, "write statistics data to an output file in JSONL(ines) format"),
|
||||
flagSet.IntVarP(&options.StatsInterval, "stats-interval", "si", 5, "number of seconds to wait between showing a statistics update"),
|
||||
flagSet.BoolVarP(&options.Metrics, "metrics", "m", false, "expose nuclei metrics on a port"),
|
||||
flagSet.IntVarP(&options.MetricsPort, "metrics-port", "mp", 9092, "port to expose nuclei metrics on"),
|
||||
)
|
||||
|
||||
_ = flagSet.Parse()
|
||||
|
||||
if options.LeaveDefaultPorts {
|
||||
http.LeaveDefaultPorts = true
|
||||
}
|
||||
|
||||
if cfgFile != "" {
|
||||
if err := set.MergeConfigFile(cfgFile); err != nil {
|
||||
if err := flagSet.MergeConfigFile(cfgFile); err != nil {
|
||||
gologger.Fatal().Msgf("Could not read config: %s\n", err)
|
||||
}
|
||||
cfgFileFolder := filepath.Dir(cfgFile)
|
||||
if err := config.OverrideIgnoreFilePath(cfgFileFolder); err != nil {
|
||||
gologger.Warning().Msgf("Could not read ignore file from custom path: %s\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createGroup(flagSet *goflags.FlagSet, groupName, description string, flags ...*goflags.FlagData) {
|
||||
flagSet.SetGroup(groupName, description)
|
||||
for _, currentFlag := range flags {
|
||||
currentFlag.Group(groupName)
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,160 @@
|
||||
module github.com/projectdiscovery/nuclei/v2
|
||||
|
||||
go 1.15
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible
|
||||
github.com/andygrunwald/go-jira v1.13.0
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
|
||||
github.com/alecthomas/jsonschema v0.0.0-20211022214203-8b29eab41725
|
||||
github.com/andygrunwald/go-jira v1.15.0
|
||||
github.com/antchfx/htmlquery v1.2.4
|
||||
github.com/apex/log v1.9.0
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/corpix/uarand v0.1.1
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/go-rod/rod v0.91.1
|
||||
github.com/golang/protobuf v1.4.3 // indirect
|
||||
github.com/go-playground/validator/v10 v10.10.0
|
||||
github.com/go-rod/rod v0.102.0
|
||||
github.com/gobwas/ws v1.1.0
|
||||
github.com/google/go-github v17.0.0+incompatible
|
||||
github.com/google/go-github/v32 v32.1.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
|
||||
github.com/json-iterator/go v1.1.10
|
||||
github.com/itchyny/gojq v0.12.6
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/karlseguin/ccache v2.0.3+incompatible
|
||||
github.com/karrick/godirwalk v1.16.1
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mattn/go-runewidth v0.0.10 // indirect
|
||||
github.com/miekg/dns v1.1.38
|
||||
github.com/mitchellh/go-ps v1.0.0
|
||||
github.com/miekg/dns v1.1.46
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/owenrumney/go-sarif v1.1.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/projectdiscovery/clistats v0.0.8
|
||||
github.com/projectdiscovery/collaborator v0.0.2
|
||||
github.com/projectdiscovery/fastdialer v0.0.8
|
||||
github.com/projectdiscovery/goflags v0.0.4
|
||||
github.com/projectdiscovery/cryptoutil v0.0.0-20220124150510-1f21e1ec3143
|
||||
github.com/projectdiscovery/fastdialer v0.0.15-0.20220127193345-f06b0fd54d47
|
||||
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20210928100737-cab279c5d4b5
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220223132346-fcffa47ead36
|
||||
github.com/projectdiscovery/gologger v1.1.4
|
||||
github.com/projectdiscovery/hmap v0.0.1
|
||||
github.com/projectdiscovery/rawhttp v0.0.6
|
||||
github.com/projectdiscovery/retryabledns v1.0.10
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.1
|
||||
github.com/projectdiscovery/hmap v0.0.2-0.20210917080408-0fd7bd286bfa
|
||||
github.com/projectdiscovery/interactsh v1.0.1-0.20220131074403-ca8bb8f87cd0
|
||||
github.com/projectdiscovery/nuclei-updatecheck-api v0.0.0-20211006155443-c0a8d610a4df
|
||||
github.com/projectdiscovery/rawhttp v0.0.7
|
||||
github.com/projectdiscovery/retryabledns v1.0.13-0.20211109182249-43d38df59660
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.2
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20220119085121-22513a958700
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.3-0.20211126104922-00d2c6bb43b6
|
||||
github.com/remeh/sizedwaitgroup v1.0.0
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rs/xid v1.2.1
|
||||
github.com/segmentio/ksuid v1.0.3
|
||||
github.com/rs/xid v1.3.0 // indirect
|
||||
github.com/segmentio/ksuid v1.0.4
|
||||
github.com/shirou/gopsutil/v3 v3.22.1
|
||||
github.com/spaolacci/murmur3 v1.1.0
|
||||
github.com/spf13/cast v1.3.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/spf13/cast v1.4.1
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/trivago/tgo v1.0.7 // indirect
|
||||
github.com/tj/go-update v2.2.5-0.20200519121640-62b4b798fd68+incompatible
|
||||
github.com/valyala/fasttemplate v1.2.1
|
||||
github.com/xanzy/go-gitlab v0.44.0
|
||||
go.uber.org/atomic v1.7.0
|
||||
go.uber.org/multierr v1.6.0
|
||||
go.uber.org/ratelimit v0.1.0
|
||||
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df // indirect
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 // indirect
|
||||
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b // indirect
|
||||
golang.org/x/text v0.3.4 // indirect
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
github.com/weppos/publicsuffix-go v0.15.1-0.20210928183822-5ee35905bd95
|
||||
github.com/xanzy/go-gitlab v0.55.1
|
||||
github.com/ysmood/gson v0.6.4 // indirect
|
||||
github.com/ysmood/leakless v0.7.0 // indirect
|
||||
go.uber.org/atomic v1.9.0
|
||||
go.uber.org/multierr v1.7.0
|
||||
go.uber.org/ratelimit v0.2.0
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1
|
||||
golang.org/x/text v0.3.7
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
moul.io/http2curl v1.0.0
|
||||
)
|
||||
|
||||
require github.com/aws/aws-sdk-go v1.43.4
|
||||
|
||||
require github.com/projectdiscovery/folderutil v0.0.0-20211206150108-b4e7ea80f36e
|
||||
|
||||
require (
|
||||
github.com/Ice3man543/nvd v1.0.8
|
||||
github.com/openrdap/rdap v0.9.1-0.20191017185644-af93e7ef17b7
|
||||
github.com/projectdiscovery/iputil v0.0.0-20210804143329-3a30fcde43f3
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/zmap/zcrypto v0.0.0-20211005224000-2d0ffdec8a9b
|
||||
)
|
||||
|
||||
require (
|
||||
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a // indirect
|
||||
github.com/Mzack9999/ldapserver v1.0.2-0.20211229000134-b44a0d6ad0dd // indirect
|
||||
github.com/PuerkitoBio/goquery v1.6.0 // indirect
|
||||
github.com/akrylysov/pogreb v0.10.1 // indirect
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
|
||||
github.com/andybalholm/cascadia v1.1.0 // indirect
|
||||
github.com/antchfx/xpath v1.2.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.0 // indirect
|
||||
github.com/bits-and-blooms/bloom/v3 v3.0.1 // indirect
|
||||
github.com/c4milo/unpackit v0.1.0 // indirect
|
||||
github.com/caddyserver/certmagic v0.15.2 // indirect
|
||||
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/goburrow/cache v0.1.4 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gosuri/uilive v0.0.4 // indirect
|
||||
github.com/gosuri/uiprogress v0.0.1 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8 // indirect
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.3 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/klauspost/compress v1.14.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mholt/acmez v1.0.1 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/projectdiscovery/blackrock v0.0.0-20210415162320-b38689ae3a2e // indirect
|
||||
github.com/projectdiscovery/mapcidr v0.0.8 // indirect
|
||||
github.com/projectdiscovery/networkpolicy v0.0.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.9 // indirect
|
||||
github.com/tklauser/numcpus v0.3.0 // indirect
|
||||
github.com/trivago/tgo v1.0.7 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
github.com/ysmood/goob v0.3.1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
github.com/zclconf/go-cty v1.10.0 // indirect
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.uber.org/zap v1.20.0 // indirect
|
||||
goftp.io/server/v2 v2.0.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
|
||||
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
@@ -31,18 +31,79 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a h1:3i+FJ7IpSZHL+VAjtpQeZCRhrpP0odl5XfoLBY4fxJ8=
|
||||
git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a/go.mod h1:C7hXLmFmPYPjIDGfQl1clsmQ5TMEQfmzWTrJk475bUs=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible h1:7o6+MAPhYTCF0+fdvoz1xDedhRb4f6s9Tn1Tt7/WTEg=
|
||||
github.com/Ice3man543/nvd v1.0.8 h1:2CBEgOxyWAkQocnnmEMmRtVPWooPRvcuHFLWj48EM4c=
|
||||
github.com/Ice3man543/nvd v1.0.8/go.mod h1:0DxLJk6revOcJKiZxa2K+rNF/HO1zJO97lqQtXhXfSc=
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/glide v0.13.2/go.mod h1:STyF5vcenH/rUqTEv+/hBXlSTo7KYwg2oc2f4tzPWic=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
github.com/andygrunwald/go-jira v1.13.0 h1:vvIImGgX32bHfoiyUwkNo+/YrPnRczNarvhLOncP6dE=
|
||||
github.com/andygrunwald/go-jira v1.13.0/go.mod h1:jYi4kFDbRPZTJdJOVJO4mpMMIwdB+rcZwSO58DzPd2I=
|
||||
github.com/Mzack9999/ldapserver v1.0.2-0.20211229000134-b44a0d6ad0dd h1:RTWs+wEY9efxTKK5aFic5C5KybqQelGcX+JdM69KoTo=
|
||||
github.com/Mzack9999/ldapserver v1.0.2-0.20211229000134-b44a0d6ad0dd/go.mod h1:AqtPw7WNT0O69k+AbPKWVGYeW94TqgMW/g+Ppc8AZr4=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/PuerkitoBio/goquery v1.6.0 h1:j7taAbelrdcsOlGeMenZxc2AWXD5fieT1/znArdnx94=
|
||||
github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||
github.com/akrylysov/pogreb v0.10.0/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
|
||||
github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w=
|
||||
github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
|
||||
github.com/alecthomas/jsonschema v0.0.0-20210818095345-1014919a589c/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
|
||||
github.com/alecthomas/jsonschema v0.0.0-20211022214203-8b29eab41725 h1:NjwIgLQlD46o79bheVG4SCdRnnOz4XtgUN1WABX5DLA=
|
||||
github.com/alecthomas/jsonschema v0.0.0-20211022214203-8b29eab41725/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=
|
||||
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
|
||||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/andygrunwald/go-jira v1.14.0/go.mod h1:KMo2f4DgMZA1C9FdImuLc04x4WQhn5derQpnsuBFgqE=
|
||||
github.com/andygrunwald/go-jira v1.15.0 h1:krX3Ad4i44mOG0u+vIxQLhLkyyQKPbTsOISsDRgBNjU=
|
||||
github.com/andygrunwald/go-jira v1.15.0/go.mod h1:GIYN1sHOIsENWUZ7B4pDeT/nxEtrZpE8l0987O67ZR8=
|
||||
github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0=
|
||||
github.com/antchfx/htmlquery v1.2.4 h1:qLteofCMe/KGovBI6SQgmou2QNyedFUW+pE+BpeZ494=
|
||||
github.com/antchfx/htmlquery v1.2.4/go.mod h1:2xO6iu3EVWs7R2JYqBbp8YzG50gj/ofqs5/0VZoDZLc=
|
||||
github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||
github.com/antchfx/xpath v1.2.0 h1:mbwv7co+x0RwgeGAOHdrKy89GvHaGvxxBtPK0uF9Zr8=
|
||||
github.com/antchfx/xpath v1.2.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
|
||||
github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
|
||||
github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
|
||||
github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
|
||||
github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.43.4 h1:EtsGbtOB+1548T6Nb62XCOofgXtMHwf+WZh5gQc3xTY=
|
||||
github.com/aws/aws-sdk-go v1.43.4/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
|
||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bits-and-blooms/bloom/v3 v3.0.1 h1:Inlf0YXbgehxVjMPmCGv86iMCKMGPPrPSHtBF5yRHwA=
|
||||
github.com/bits-and-blooms/bloom/v3 v3.0.1/go.mod h1:MC8muvBzzPOFsrcdND/A7kU7kMhkqb9KI70JlZCP+C8=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
||||
github.com/c4milo/unpackit v0.1.0 h1:91pWJ6B3svZ4LOE+p3rnyucRK5fZwBdF/yQ/pcZO31I=
|
||||
github.com/c4milo/unpackit v0.1.0/go.mod h1:pvXCMYlSV8zwGFWMaT+PWYkAB/cvDjN2mv9r7ZRSxEo=
|
||||
github.com/caddyserver/certmagic v0.15.2 h1:OMTakTsLM1ZfzMDjwvYprfUgFzpVPh3u87oxMPwmeBc=
|
||||
github.com/caddyserver/certmagic v0.15.2/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -51,33 +112,78 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
||||
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
|
||||
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
|
||||
github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/corpix/uarand v0.1.1 h1:RMr1TWc9F4n5jiPDzFHtmaUXLKLNUFK0SgCLo4BhX/U=
|
||||
github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/dave/dst v0.26.2/go.mod h1:UMDJuIRPfyUCC78eFuB+SV/WI8oDeyFDvM/JR6NI3IU=
|
||||
github.com/dave/gopackages v0.0.0-20170318123100-46e7023ec56e/go.mod h1:i00+b/gKdIDIxuLDFob7ustLAVqhsZRk2qVZrArELGQ=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
github.com/dave/kerr v0.0.0-20170318121727-bc25dd6abe8e/go.mod h1:qZqlPyPvfsDJt+3wHJ1EvSXDuVjFTK0j2p/ca+gtsb8=
|
||||
github.com/dave/rebecca v0.9.1/go.mod h1:N6XYdMD/OKw3lkF3ywh8Z6wPGuwNFDNtWYEMFWEmXBA=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
|
||||
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
|
||||
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
|
||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eggsampler/acme/v3 v3.2.1/go.mod h1:/qh0rKC/Dh7Jj+p4So7DbWmFNzC4dpcpK53r226Fhuo=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-rod/rod v0.91.1 h1:7xIlC/bXCXosZqZUl2x6GVB8tv4yMQ4W/ZVdGVa1qYI=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-rod/rod v0.91.1/go.mod h1:/W4lcZiCALPD603MnJGIvhtywP3R6yRB9EDfFfsHiiI=
|
||||
github.com/go-rod/rod v0.102.0 h1:jmfb9YYOQJF9jDCzwH3/rX0M0ZKobXbrAGz75MK7x4s=
|
||||
github.com/go-rod/rod v0.102.0/go.mod h1:RXSLAlPodTFOmZnwaAQJIcOJ1i835r0uuTGPLO09t/M=
|
||||
github.com/goburrow/cache v0.1.4 h1:As4KzO3hgmzPlnaMniZU9+VmoNYseUhuELbxy9mRBfw=
|
||||
github.com/goburrow/cache v0.1.4/go.mod h1:cDFesZDnIlrHoNlMYqqMpCRawuXulgx+y7mXU8HZ+/c=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
|
||||
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
@@ -99,11 +205,14 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
|
||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
@@ -112,19 +221,23 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
|
||||
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181127221834-b4f47329b966/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
@@ -133,153 +246,403 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gosuri/uilive v0.0.4 h1:hUEBpQDj8D8jXgtCdBu7sWsy5sbW/5GhuO8KBwJ2jyY=
|
||||
github.com/gosuri/uilive v0.0.4/go.mod h1:V/epo5LjjlDE5RJUcqx8dbw+zc93y5Ya3yg8tfZ74VI=
|
||||
github.com/gosuri/uiprogress v0.0.1 h1:0kpv/XY/qTmFWl/SkaJykZXrBBzwwadmW8fRb7RJSxw=
|
||||
github.com/gosuri/uiprogress v0.0.1/go.mod h1:C1RTYn4Sc7iEyf6j8ft5dyoZ4212h8G1ol9QQluh5+0=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hooklift/assert v0.1.0 h1:UZzFxx5dSb9aBtvMHTtnPuvFnBvcEhHTPb9+0+jpEjs=
|
||||
github.com/hooklift/assert v0.1.0/go.mod h1:pfexfvIHnKCdjh6CkkIZv5ic6dQ6aU2jhKghBlXuwwY=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/itchyny/go-flags v1.5.0/go.mod h1:lenkYuCobuxLBAd/HGFE4LRoW8D3B6iXRQfWYJ+MNbA=
|
||||
github.com/itchyny/gojq v0.12.4/go.mod h1:EQUSKgW/YaOxmXpAwGiowFDO4i2Rmtk5+9dFyeiymAg=
|
||||
github.com/itchyny/gojq v0.12.6 h1:VjaFn59Em2wTxDNGcrRkDK9ZHMNa8IksOgL13sLL4d0=
|
||||
github.com/itchyny/gojq v0.12.6/go.mod h1:ZHrkfu7A+RbZLy5J1/JKpS4poEqrzItSTGDItqsfP0A=
|
||||
github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU=
|
||||
github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
|
||||
github.com/jarcoal/httpmock v1.0.4 h1:jp+dy/+nonJE4g4xbVtl9QdrUNbn6/3hDT5R4nDIZnA=
|
||||
github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
github.com/jasonlvhit/gocron v0.0.1/go.mod h1:k9a3TV8VcU73XZxfVHCHWMWF9SOqgoku0/QlY2yvlA4=
|
||||
github.com/jlaffaye/ftp v0.0.0-20190624084859-c1312a7102bf/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/karlseguin/ccache v2.0.3+incompatible h1:j68C9tWOROiOLWTS/kCGg9IcJG+ACqn5+0+t8Oh83UU=
|
||||
github.com/karlseguin/ccache v2.0.3+incompatible/go.mod h1:CM9tNPzT6EdRh14+jiW8mEF9mkNZuuE51qmgGYUB93w=
|
||||
github.com/karlseguin/ccache/v2 v2.0.8 h1:lT38cE//uyf6KcFok0rlgXtGFBWxkI6h/qg4tbFyDnA=
|
||||
github.com/karlseguin/ccache/v2 v2.0.8/go.mod h1:2BDThcfQMf/c0jnZowt16eW405XIqZPavt+HoYEtcxQ=
|
||||
github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003 h1:vJ0Snvo+SLMY72r5J4sEfkuE7AFbixEP2qRbEcum/wA=
|
||||
github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8=
|
||||
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
||||
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.14.1 h1:hLQYb23E8/fO+1u53d02A97a8UnsddcvYzq4ERRU4ds=
|
||||
github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 h1:wIONC+HMNRqmWBjuMxhatuSzHaljStc4gjDeKycxy0A=
|
||||
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mholt/acmez v1.0.1 h1:J7uquHOKEmo71UDnVApy1sSLA0oF/r+NtVrNzMKKA9I=
|
||||
github.com/mholt/acmez v1.0.1/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
||||
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.38 h1:MtIY+fmHUVVgv1AXzmKMWcwdCYxTRPG1EDjpqF4RCEw=
|
||||
github.com/miekg/dns v1.1.38/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.46 h1:uzwpxRtSVxtcIZmz/4Uz6/Rn7G11DvsaslXoy5LxQio=
|
||||
github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/minio/minio-go/v6 v6.0.46/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
|
||||
github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4=
|
||||
github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ=
|
||||
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/openrdap/rdap v0.9.1-0.20191017185644-af93e7ef17b7 h1:3Xn/CN6GVY+7mVuGgt5bfp0F9JwcWqnvwfb23Jf8Vxg=
|
||||
github.com/openrdap/rdap v0.9.1-0.20191017185644-af93e7ef17b7/go.mod h1:inRbqVxN7ri77yTJY3ZtGtKegIFa3Qnarh7Xp9P7LgY=
|
||||
github.com/owenrumney/go-sarif v1.0.11/go.mod h1:hTBFbxU7GuVRUvwMx+eStp9M/Oun4xHCS3vqpPvket8=
|
||||
github.com/owenrumney/go-sarif v1.1.1 h1:QNObu6YX1igyFKhdzd7vgzmw7XsWN3/6NMGuDzBgXmE=
|
||||
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/projectdiscovery/blackrock v0.0.0-20210415162320-b38689ae3a2e h1:7bwaFH1jvtOo5ndhTQgoA349ozhX+1dc4b6tbaPnBOA=
|
||||
github.com/projectdiscovery/blackrock v0.0.0-20210415162320-b38689ae3a2e/go.mod h1:/IsapnEYiWG+yEDPXp0e8NWj3npzB9Ccy9lXEUJwMZs=
|
||||
github.com/projectdiscovery/clistats v0.0.8 h1:tjmWb15mqsPf/yrQXVHLe2ThZX/5+mgKSfZBKWWLh20=
|
||||
github.com/projectdiscovery/clistats v0.0.8/go.mod h1:lV6jUHAv2bYWqrQstqW8iVIydKJhWlVaLl3Xo9ioVGg=
|
||||
github.com/projectdiscovery/collaborator v0.0.2 h1:BSiMlWM3NvuKbpedn6fIjjEo5b7q5zmiJ6tI7+6mB3s=
|
||||
github.com/projectdiscovery/collaborator v0.0.2/go.mod h1:J1z0fC7Svutz3LJqoRyTHA3F0Suh4livmkYv8MnKw20=
|
||||
github.com/projectdiscovery/fastdialer v0.0.8 h1:mEMc8bfXV5hc1PUEkJiUnR5imYQe6+839Zezd5jLkc0=
|
||||
github.com/projectdiscovery/fastdialer v0.0.8/go.mod h1:AuaV0dzrNeBLHqjNnzpFSnTXnHGIZAlGQE+WUMmSIW4=
|
||||
github.com/projectdiscovery/goflags v0.0.4 h1:fWKLMAr3KmPlZxE1b54pfei+vGIUJn9q6aM7woZIbCY=
|
||||
github.com/projectdiscovery/goflags v0.0.4/go.mod h1:Ae1mJ5MIIqjys0lFe3GiMZ10Z8VLaxkYJ1ySA4Zv8HA=
|
||||
github.com/projectdiscovery/cryptoutil v0.0.0-20210805184155-b5d2512f9345/go.mod h1:clhQmPnt35ziJW1AhJRKyu8aygXCSoyWj6dtmZBRjjc=
|
||||
github.com/projectdiscovery/cryptoutil v0.0.0-20220124150510-1f21e1ec3143 h1:ulWFeH179xgDUfNQT/LyimW1znNlivsqv2d/lNFZU30=
|
||||
github.com/projectdiscovery/cryptoutil v0.0.0-20220124150510-1f21e1ec3143/go.mod h1:VJvSNE8f8A1MgpjgAL2GPJSQcJa4jbdaeQJstARFrU4=
|
||||
github.com/projectdiscovery/fastdialer v0.0.12/go.mod h1:RkRbxqDCcCFhfNUbkzBIz/ieD4uda2JuUA4WJ+RLee0=
|
||||
github.com/projectdiscovery/fastdialer v0.0.15-0.20220127193345-f06b0fd54d47 h1:TUsZiwez9uFmph1hlTsiH7rdB+wi4524+lMuV2z6FaM=
|
||||
github.com/projectdiscovery/fastdialer v0.0.15-0.20220127193345-f06b0fd54d47/go.mod h1:GbQvP1ezGlQn0af3lVcl08b5eRQu960T7A9pwazybSo=
|
||||
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08 h1:NwD1R/du1dqrRKN3SJl9kT6tN3K9puuWFXEvYF2ihew=
|
||||
github.com/projectdiscovery/filekv v0.0.0-20210915124239-3467ef45dd08/go.mod h1:paLCnwV8sL7ppqIwVQodQrk3F6mnWafwTDwRd7ywZwQ=
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20210804142714-ebba15fa53ca/go.mod h1:U+QCpQnX8o2N2w0VUGyAzjM3yBAe4BKedVElxiImsx0=
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20210914153648-31f843feaad4/go.mod h1:U+QCpQnX8o2N2w0VUGyAzjM3yBAe4BKedVElxiImsx0=
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20210926202739-6050d0acf73c/go.mod h1:U+QCpQnX8o2N2w0VUGyAzjM3yBAe4BKedVElxiImsx0=
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20210928100737-cab279c5d4b5 h1:2dbm7UhrAKnccZttr78CAmG768sSCd+MBn4ayLVDeqA=
|
||||
github.com/projectdiscovery/fileutil v0.0.0-20210928100737-cab279c5d4b5/go.mod h1:U+QCpQnX8o2N2w0VUGyAzjM3yBAe4BKedVElxiImsx0=
|
||||
github.com/projectdiscovery/folderutil v0.0.0-20211206150108-b4e7ea80f36e h1:RJJuYyuwskYtzZi2gziy6SE/b7saWEzyskaA252E0VY=
|
||||
github.com/projectdiscovery/folderutil v0.0.0-20211206150108-b4e7ea80f36e/go.mod h1:BMqXH4jNGByVdE2iLtKvc/6XStaiZRuCIaKv1vw9PnI=
|
||||
github.com/projectdiscovery/goflags v0.0.7/go.mod h1:Jjwsf4eEBPXDSQI2Y+6fd3dBumJv/J1U0nmpM+hy2YY=
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220208065736-e1d58bce8ce5 h1:IoDOKD+ZWctt0yGMwgGSCjWmSAaaMds7J9Tbxy6zv+A=
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220208065736-e1d58bce8ce5/go.mod h1:37KhVbVLllyuIAgpXGqcvE/hsFEwJ+ctEUSHawjhsBY=
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220223122339-bb3affd53c37 h1:wqvD7YOYzJsLxgp51saFR6Dr3niEi0e+b9OiOcnAnw8=
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220223122339-bb3affd53c37/go.mod h1:37KhVbVLllyuIAgpXGqcvE/hsFEwJ+ctEUSHawjhsBY=
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220223132346-fcffa47ead36 h1:7tPZ9Ui9Iyo/bfP+LtOOKJRrXO7ZzunzMjqHClTDZEA=
|
||||
github.com/projectdiscovery/goflags v0.0.8-0.20220223132346-fcffa47ead36/go.mod h1:37KhVbVLllyuIAgpXGqcvE/hsFEwJ+ctEUSHawjhsBY=
|
||||
github.com/projectdiscovery/gologger v1.0.1/go.mod h1:Ok+axMqK53bWNwDSU1nTNwITLYMXMdZtRc8/y1c7sWE=
|
||||
github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI=
|
||||
github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY=
|
||||
github.com/projectdiscovery/hmap v0.0.1 h1:VAONbJw5jP+syI5smhsfkrq9XPGn4aiYy5pR6KR1wog=
|
||||
github.com/projectdiscovery/hmap v0.0.1/go.mod h1:VDEfgzkKQdq7iGTKz8Ooul0NuYHQ8qiDs6r8bPD1Sb0=
|
||||
github.com/projectdiscovery/rawhttp v0.0.6 h1:HbgPB1eKXQVV5F9sq0Uxflm95spWFyZYD8dgFpeOC9M=
|
||||
github.com/projectdiscovery/rawhttp v0.0.6/go.mod h1:PQERZAhAv7yxI/hR6hdDPgK1WTU56l204BweXrBec+0=
|
||||
github.com/projectdiscovery/retryabledns v1.0.7/go.mod h1:/UzJn4I+cPdQl6pKiiQfvVAT636YZvJQYZhYhGB0dUQ=
|
||||
github.com/projectdiscovery/retryabledns v1.0.10 h1:xJZ2aKoqrNg/OZEw1+4+QIOH40V/WkZDYY1ZZc+uphE=
|
||||
github.com/projectdiscovery/retryabledns v1.0.10/go.mod h1:4sMC8HZyF01HXukRleSQYwz4870bwgb4+hTSXTMrkf4=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.1 h1:V7wUvsZNq1Rcz7+IlcyoyQlNwshuwptuBVYWw9lx8RE=
|
||||
github.com/projectdiscovery/hmap v0.0.2-0.20210616215655-7b78e7f33d1f/go.mod h1:FH+MS/WNKTXJQtdRn+/Zg5WlKCiMN0Z1QUedUIuM5n8=
|
||||
github.com/projectdiscovery/hmap v0.0.2-0.20210917080408-0fd7bd286bfa h1:9sZWFUAshIa/ea0RKjGRuuZiS5PzYXAFjTRUnSbezr0=
|
||||
github.com/projectdiscovery/hmap v0.0.2-0.20210917080408-0fd7bd286bfa/go.mod h1:lV5f/PNPmCCjCN/dR317/chN9s7VG5h/xcbFfXOz8Fo=
|
||||
github.com/projectdiscovery/interactsh v0.0.4/go.mod h1:PtJrddeBW1/LeOVgTvvnjUl3Hu/17jTkoIi8rXeEODE=
|
||||
github.com/projectdiscovery/interactsh v1.0.1-0.20220131074403-ca8bb8f87cd0 h1:Olf2RG9sLqZF157gC664G6A3DU0Fta6VD/OWiNP3LbI=
|
||||
github.com/projectdiscovery/interactsh v1.0.1-0.20220131074403-ca8bb8f87cd0/go.mod h1:UW8wdok5mrDOXzcHxRjUCCDIScc/3hCpw8QjVDeXHEE=
|
||||
github.com/projectdiscovery/ipranger v0.0.2/go.mod h1:kcAIk/lo5rW+IzUrFkeYyXnFJ+dKwYooEOHGVPP/RWE=
|
||||
github.com/projectdiscovery/iputil v0.0.0-20210414194613-4b4d2517acf0/go.mod h1:PQAqn5h5NXsQTF4ZA00ZTYLRzGCjOtcCq8llAqrsd1A=
|
||||
github.com/projectdiscovery/iputil v0.0.0-20210429152401-c18a5408ca46/go.mod h1:PQAqn5h5NXsQTF4ZA00ZTYLRzGCjOtcCq8llAqrsd1A=
|
||||
github.com/projectdiscovery/iputil v0.0.0-20210804143329-3a30fcde43f3 h1:VZ9H51A7tI7R/9I5W5l960Nkq7eMJqGd3y1wsuwzdjE=
|
||||
github.com/projectdiscovery/iputil v0.0.0-20210804143329-3a30fcde43f3/go.mod h1:blmYJkS8lSrrx3QcmcgS2tZIxlojeVmoGeA9twslCBU=
|
||||
github.com/projectdiscovery/mapcidr v0.0.4/go.mod h1:ALOIj6ptkWujNoX8RdQwB2mZ+kAmKuLJBq9T5gR5wG0=
|
||||
github.com/projectdiscovery/mapcidr v0.0.6/go.mod h1:ZEBhMmBU3laUl3g9QGTrzJku1VJOzjdFwW01f/zVVzM=
|
||||
github.com/projectdiscovery/mapcidr v0.0.7/go.mod h1:7CzdUdjuLVI0s33dQ33lWgjg3vPuLFw2rQzZ0RxkT00=
|
||||
github.com/projectdiscovery/mapcidr v0.0.8 h1:16U05F2x3o/jSTsxSCY2hCuCs9xOSwVxjo2zlsL4L4E=
|
||||
github.com/projectdiscovery/mapcidr v0.0.8/go.mod h1:7CzdUdjuLVI0s33dQ33lWgjg3vPuLFw2rQzZ0RxkT00=
|
||||
github.com/projectdiscovery/networkpolicy v0.0.1 h1:RGRuPlxE8WLFF9tdKSjTsYiTIKHNHW20Kl0nGGiRb1I=
|
||||
github.com/projectdiscovery/networkpolicy v0.0.1/go.mod h1:asvdg5wMy3LPVMGALatebKeOYH5n5fV5RCTv6DbxpIs=
|
||||
github.com/projectdiscovery/nuclei-updatecheck-api v0.0.0-20211006155443-c0a8d610a4df h1:CvTNAUD5JbLMqpMFoGNgfk2gOcN0NC57ICu0+oK84vs=
|
||||
github.com/projectdiscovery/nuclei-updatecheck-api v0.0.0-20211006155443-c0a8d610a4df/go.mod h1:pxWVDgq88t9dWv4+J2AIaWgY+EqOE1AyfHS0Tn23w4M=
|
||||
github.com/projectdiscovery/nuclei/v2 v2.5.1/go.mod h1:sU2qcY0MQFS0CqP1BgkR8ZnUyFhqK0BdnY6bvTKNjXY=
|
||||
github.com/projectdiscovery/rawhttp v0.0.7 h1:5m4peVgjbl7gqDcRYMTVEuX+Xs/nh76ohTkkvufucLg=
|
||||
github.com/projectdiscovery/rawhttp v0.0.7/go.mod h1:PQERZAhAv7yxI/hR6hdDPgK1WTU56l204BweXrBec+0=
|
||||
github.com/projectdiscovery/retryabledns v1.0.11/go.mod h1:4sMC8HZyF01HXukRleSQYwz4870bwgb4+hTSXTMrkf4=
|
||||
github.com/projectdiscovery/retryabledns v1.0.12/go.mod h1:4sMC8HZyF01HXukRleSQYwz4870bwgb4+hTSXTMrkf4=
|
||||
github.com/projectdiscovery/retryabledns v1.0.13-0.20210916165024-76c5b76fd59a/go.mod h1:tXaLDs4n3pRZHwfa8mdXpUWe/AYDNK3HlWDjldhRbjI=
|
||||
github.com/projectdiscovery/retryabledns v1.0.13-0.20211109182249-43d38df59660 h1:Ooa5htghPkdyfpzy6Y5KLdyv4w8ePZWmfzFSPQlJStQ=
|
||||
github.com/projectdiscovery/retryabledns v1.0.13-0.20211109182249-43d38df59660/go.mod h1:UfszkO3x+GLKVOpXB7boddJKbwNCr+tMPSkfgCSNhl4=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.1/go.mod h1:SrN6iLZilNG1X4neq1D+SBxoqfAF4nyzvmevkTkWsek=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.2 h1:LV1/KAQU+yeWhNVlvveaYFsjBYRwXlNEq0PvrezMV0U=
|
||||
github.com/projectdiscovery/retryablehttp-go v1.0.2/go.mod h1:dx//aY9V247qHdsRf0vdWHTBZuBQ2vm6Dq5dagxrDYI=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20210804142656-fd3c28dbaafe/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20210823090203-2f5f137e8e1d/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20210830151154-f567170afdd9/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20220119085121-22513a958700 h1:L7Vb5AdzIV1Xs088Nvslfhh/piKP9gjTxjxfiqnd4mk=
|
||||
github.com/projectdiscovery/stringsutil v0.0.0-20220119085121-22513a958700/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.2/go.mod h1:7uSxfMXaBmzvw8m5EhOEjB6nhz0rK/H9sUjq1ciZu24=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.3-0.20211126104922-00d2c6bb43b6 h1:DvWRQpw7Ib2CRL3ogYm/BWM+X0UGPfz1n9Ix9YKgFM8=
|
||||
github.com/projectdiscovery/yamldoc-go v1.0.3-0.20211126104922-00d2c6bb43b6/go.mod h1:8OfZj8p/axkUM/TJoS/O9LDjj/S8u17rxRbqluE9CU4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
|
||||
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/segmentio/ksuid v1.0.3 h1:FoResxvleQwYiPAVKe1tMUlEirodZqlqglIuFsdDntY=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/segmentio/ksuid v1.0.3/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
||||
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
|
||||
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v3 v3.21.7/go.mod h1:RGl11Y7XMTQPmHh8F0ayC6haKNBgH4PXMJuTAcMOlz4=
|
||||
github.com/shirou/gopsutil/v3 v3.22.1 h1:33y31Q8J32+KstqPfscvFwBlNJ6xLaBy4xqBXzlYV5w=
|
||||
github.com/shirou/gopsutil/v3 v3.22.1/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
|
||||
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
|
||||
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
|
||||
github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
|
||||
github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc=
|
||||
github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
|
||||
github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
|
||||
github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
|
||||
github.com/tj/go-update v2.2.5-0.20200519121640-62b4b798fd68+incompatible h1:guTq1YxwB8XSILkI9q4IrOmrCOS6Hc1L3hmOhi4Swcs=
|
||||
github.com/tj/go-update v2.2.5-0.20200519121640-62b4b798fd68+incompatible/go.mod h1:waFwwyiAhGey2e+dNoYQ/iLhIcFqhCW7zL/+vDU1WLo=
|
||||
github.com/tklauser/go-sysconf v0.3.7/go.mod h1:JZIdXh4RmBvZDBZ41ld2bGxRV3n4daiiqA3skYhAoQ4=
|
||||
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
|
||||
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
|
||||
github.com/tklauser/numcpus v0.2.3/go.mod h1:vpEPS/JC+oZGGQ/My/vJnNsvMDQL6PwOqt8dsCw5j+E=
|
||||
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
|
||||
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
|
||||
github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM=
|
||||
github.com/trivago/tgo v1.0.7/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA=
|
||||
github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/xanzy/go-gitlab v0.44.0 h1:cEiGhqu7EpFGuei2a2etAwB+x6403E5CvpLn35y+GPs=
|
||||
github.com/xanzy/go-gitlab v0.44.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
|
||||
github.com/ysmood/goob v0.3.0 h1:XZ51cZJ4W3WCoCiUktixzMIQF86W7G5VFL4QQ/Q2uS0=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
github.com/weppos/publicsuffix-go v0.15.1-0.20210928183822-5ee35905bd95 h1:DyAZOw3JsVd6LJHqhl4MpKQdYQEmat0C6pPPwom39Ow=
|
||||
github.com/weppos/publicsuffix-go v0.15.1-0.20210928183822-5ee35905bd95/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE=
|
||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ=
|
||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM=
|
||||
github.com/xanzy/go-gitlab v0.50.3/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
|
||||
github.com/xanzy/go-gitlab v0.55.1 h1:IgX/DS9buV0AUz8fuJPQkdl0fQGfBiAsAHxpun8sNhg=
|
||||
github.com/xanzy/go-gitlab v0.55.1/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
|
||||
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
|
||||
github.com/ysmood/goob v0.3.0/go.mod h1:S3lq113Y91y1UBf1wj1pFOxeahvfKkCk6mTWTWbDdWs=
|
||||
github.com/ysmood/got v0.9.3 h1:qx51X49jL/WAiqZzPTkPZ0zp5pTmrWJa4zYFTYo0gHI=
|
||||
github.com/ysmood/goob v0.3.1 h1:qMp5364BGS1DLJVrAqUxTF6KOFt0YDot8GC70u/0jbI=
|
||||
github.com/ysmood/goob v0.3.1/go.mod h1:S3lq113Y91y1UBf1wj1pFOxeahvfKkCk6mTWTWbDdWs=
|
||||
github.com/ysmood/got v0.9.3/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
|
||||
github.com/ysmood/gotrace v0.2.0 h1:IkTC6rJREwXSaG8yWK+NFwIJGIsxA1DjC6/gxYyQttE=
|
||||
github.com/ysmood/got v0.14.1/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
|
||||
github.com/ysmood/got v0.15.1 h1:X5jAbMyBf5yeezuFMp9HaMGXZWMSqIQcUlAHI+kJmUs=
|
||||
github.com/ysmood/got v0.15.1/go.mod h1:pE1l4LOwOBhQg6A/8IAatkGp7uZjnalzrZolnlhhMgY=
|
||||
github.com/ysmood/gotrace v0.2.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
|
||||
github.com/ysmood/gson v0.6.3 h1:4cU+5oOdsyundXHy00t99H0rLXLthuseD3x6W+xmCiU=
|
||||
github.com/ysmood/gotrace v0.2.2 h1:006KHGRThSRf8lwh4EyhNmuuq/l+Ygs+JqojkhEG1/E=
|
||||
github.com/ysmood/gotrace v0.2.2/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM=
|
||||
github.com/ysmood/gson v0.6.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
|
||||
github.com/ysmood/leakless v0.6.12 h1:XxtRYl97bJklfv4BZVdyGnd/y42p6w8lu1hUzfCkT4M=
|
||||
github.com/ysmood/gson v0.6.4 h1:Yb6tosv6bk59HqjZu2/7o4BFherpYEMkDkXmlhgryZ4=
|
||||
github.com/ysmood/gson v0.6.4/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
|
||||
github.com/ysmood/leakless v0.6.12/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
|
||||
github.com/ysmood/leakless v0.7.0 h1:XCGdaPExyoreoQd+H5qgxM3ReNbSPFsEXpSKwbXbwQw=
|
||||
github.com/ysmood/leakless v0.7.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/zclconf/go-cty v1.8.4/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
|
||||
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521 h1:kKCF7VX/wTmdg2ZjEaqlq99Bjsoiz7vH6sFniF/vI4M=
|
||||
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
|
||||
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
|
||||
github.com/zmap/zcrypto v0.0.0-20211005224000-2d0ffdec8a9b h1:iYQzlljG1dOXBtsJGyzFC/wBK5qUCWs1eLCr/UcJYPA=
|
||||
github.com/zmap/zcrypto v0.0.0-20211005224000-2d0ffdec8a9b/go.mod h1:5nID//bFGkx3/+iHcFIFRHQ54EOPJ0iSj0IGKpMElvw=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/ratelimit v0.1.0 h1:U2AruXqeTb4Eh9sYQSTrMhH8Cb7M0Ian2ibBOnBcnAw=
|
||||
go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
|
||||
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA=
|
||||
go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.20.0 h1:N4oPlghZwYG55MlU6LXk/Zp00FVNE9X9wrYO8CEs4lc=
|
||||
go.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||
goftp.io/server/v2 v2.0.0 h1:FF8JKXXKDxAeO1uXEZz7G+IZwCDhl19dpVIlDtp3QAg=
|
||||
goftp.io/server/v2 v2.0.0/go.mod h1:7+H/EIq7tXdfo1Muu5p+l3oQ6rYkDZ8lY7IM5d5kVdQ=
|
||||
golang.org/x/arch v0.0.0-20180920145803-b19384d3c130/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df h1:y7QZzfUiTwWam+xBn29Ulb8CBwVN5UdzmMDavl9Whlw=
|
||||
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -310,16 +673,20 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -332,23 +699,39 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210414194228-064579744ee0/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210521195947-fe42d452be8f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 h1:5vD4XjIc0X5+kHZjx4UecYdjA6mJo+XXNoaW0EjU5Os=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210817223510-7df4dd6e12ab/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 h1:B333XXssMuKQeBwiNODx4TupZy7bf4sxFZnN2ZOcvUE=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -357,24 +740,36 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -387,31 +782,54 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201113233024-12cec1faf1ba/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g=
|
||||
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
|
||||
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
@@ -421,6 +839,8 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@@ -441,12 +861,19 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 h1:BonxutuHCTL0rBDnZlKjpGIQFTjyUVTexFOdWkB6Fg0=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -527,22 +954,35 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/corvus-ch/zbase32.v1 v1.0.0 h1:K4u1NprbDNvKPczKfHLbwdOWHTZ0zfv2ow71H1nRnFU=
|
||||
gopkg.in/corvus-ch/zbase32.v1 v1.0.0/go.mod h1:T3oKkPOm4AV/bNXCNFUxRmlE9RUyBz/DSo0nK9U+c0Y=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -552,6 +992,9 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||
mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
@@ -1,72 +0,0 @@
|
||||
package collaborator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/collaborator"
|
||||
)
|
||||
|
||||
var (
|
||||
// PollSeconds is the seconds to poll at.
|
||||
PollSeconds = 5
|
||||
// DefaultMaxBufferLimit is the default request buffer limit
|
||||
DefaultMaxBufferLimit = 150
|
||||
// DefaultPollInterval is the default poll interval for burp collabortor polling.
|
||||
DefaultPollInterval time.Duration = time.Second * time.Duration(PollSeconds)
|
||||
// DefaultCollaborator is the default burp collaborator instance
|
||||
DefaultCollaborator = &Collaborator{Collab: collaborator.NewBurpCollaborator()}
|
||||
)
|
||||
|
||||
// Collaborator is a client for recording burp collaborator interactions
|
||||
type Collaborator struct {
|
||||
sync.RWMutex
|
||||
options *Options // unused
|
||||
Collab *collaborator.BurpCollaborator
|
||||
}
|
||||
|
||||
// Options contains configuration options for collaborator client
|
||||
type Options struct {
|
||||
BIID string
|
||||
PollInterval time.Duration
|
||||
MaxBufferLimit int
|
||||
}
|
||||
|
||||
// New creates a new collaborator client
|
||||
func New(options *Options) *Collaborator {
|
||||
collab := collaborator.NewBurpCollaborator()
|
||||
collab.AddBIID(options.BIID)
|
||||
collab.MaxBufferLimit = options.MaxBufferLimit
|
||||
return &Collaborator{Collab: collab, options: options}
|
||||
}
|
||||
|
||||
// Poll initiates collaborator polling if any BIIDs were provided
|
||||
func (b *Collaborator) Poll() {
|
||||
// if no valid biids were provided just return
|
||||
if len(b.Collab.BIIDs) > 0 {
|
||||
go b.Collab.PollEach(DefaultPollInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// Has checks if a collabrator hit was found for a URL
|
||||
func (b *Collaborator) Has(s string) bool {
|
||||
for _, r := range b.Collab.RespBuffer {
|
||||
for i := 0; i < len(r.Responses); i++ {
|
||||
// search in dns - http - smtp
|
||||
b.RLock()
|
||||
found := strings.Contains(r.Responses[i].Data.RawRequestDecoded, s) ||
|
||||
strings.Contains(r.Responses[i].Data.RequestDecoded, s) ||
|
||||
strings.Contains(r.Responses[i].Data.MessageDecoded, s)
|
||||
b.RUnlock()
|
||||
|
||||
if found {
|
||||
b.Lock()
|
||||
r.Responses = append(r.Responses[:i], r.Responses[i+1:]...)
|
||||
b.Unlock()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,24 +1,39 @@
|
||||
package colorizer
|
||||
|
||||
import "github.com/logrusorgru/aurora"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
// Colorizer returns a colorized severity printer
|
||||
type Colorizer struct {
|
||||
Data map[string]string
|
||||
}
|
||||
"github.com/logrusorgru/aurora"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
||||
)
|
||||
|
||||
const (
|
||||
fgOrange uint8 = 208
|
||||
)
|
||||
|
||||
// New returns a new severity based colorizer
|
||||
func New(colorizer aurora.Aurora) *Colorizer {
|
||||
severityMap := map[string]string{
|
||||
"info": colorizer.Blue("info").String(),
|
||||
"low": colorizer.Green("low").String(),
|
||||
"medium": colorizer.Yellow("medium").String(),
|
||||
"high": colorizer.Index(fgOrange, "high").String(),
|
||||
"critical": colorizer.Red("critical").String(),
|
||||
func GetColor(colorizer aurora.Aurora, templateSeverity fmt.Stringer) string {
|
||||
var method func(arg interface{}) aurora.Value
|
||||
switch templateSeverity {
|
||||
case severity.Info:
|
||||
method = colorizer.Blue
|
||||
case severity.Low:
|
||||
method = colorizer.Green
|
||||
case severity.Medium:
|
||||
method = colorizer.Yellow
|
||||
case severity.High:
|
||||
method = func(stringValue interface{}) aurora.Value { return colorizer.Index(fgOrange, stringValue) }
|
||||
case severity.Critical:
|
||||
method = colorizer.Red
|
||||
default:
|
||||
method = colorizer.White
|
||||
}
|
||||
|
||||
return method(templateSeverity.String()).String()
|
||||
}
|
||||
|
||||
func New(colorizer aurora.Aurora) func(severity.Severity) string {
|
||||
return func(severity severity.Severity) string {
|
||||
return GetColor(colorizer, severity)
|
||||
}
|
||||
return &Colorizer{Data: severityMap}
|
||||
}
|
||||
@@ -1,23 +1,25 @@
|
||||
package runner
|
||||
|
||||
import "github.com/projectdiscovery/gologger"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
const banner = `
|
||||
__ _
|
||||
____ __ _______/ /__ (_)
|
||||
/ __ \/ / / / ___/ / _ \/ /
|
||||
/ / / / /_/ / /__/ / __/ /
|
||||
/_/ /_/\__,_/\___/_/\___/_/ v2.3.2
|
||||
`
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
)
|
||||
|
||||
// Version is the current version of nuclei
|
||||
const Version = `2.3.2`
|
||||
var banner = fmt.Sprintf(`
|
||||
__ _
|
||||
____ __ _______/ /__ (_)
|
||||
/ __ \/ / / / ___/ / _ \/ /
|
||||
/ / / / /_/ / /__/ / __/ /
|
||||
/_/ /_/\__,_/\___/_/\___/_/ %s
|
||||
`, config.Version)
|
||||
|
||||
// showBanner is used to show the banner to the user
|
||||
func showBanner() {
|
||||
gologger.Print().Msgf("%s\n", banner)
|
||||
gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n")
|
||||
|
||||
gologger.Warning().Msgf("Use with caution. You are responsible for your actions\n")
|
||||
gologger.Warning().Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n")
|
||||
gologger.Print().Label("WRN").Msgf("Use with caution. You are responsible for your actions.\n")
|
||||
gologger.Print().Label("WRN").Msgf("Developers assume no liability and are not responsible for any misuse or damage.\n")
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
// nucleiConfig contains some configuration options for nuclei
|
||||
type nucleiConfig struct {
|
||||
TemplatesDirectory string `json:"templates-directory,omitempty"`
|
||||
CurrentVersion string `json:"current-version,omitempty"`
|
||||
LastChecked time.Time `json:"last-checked,omitempty"`
|
||||
IgnoreURL string `json:"ignore-url,omitempty"`
|
||||
NucleiVersion string `json:"nuclei-version,omitempty"`
|
||||
LastCheckedIgnore time.Time `json:"last-checked-ignore,omitempty"`
|
||||
// IgnorePaths ignores all the paths listed unless specified manually
|
||||
IgnorePaths []string `json:"ignore-paths,omitempty"`
|
||||
}
|
||||
|
||||
// nucleiConfigFilename is the filename of nuclei configuration file.
|
||||
const nucleiConfigFilename = ".templates-config.json"
|
||||
|
||||
var reVersion = regexp.MustCompile(`\d+\.\d+\.\d+`)
|
||||
|
||||
// readConfiguration reads the nuclei configuration file from disk.
|
||||
func readConfiguration() (*nucleiConfig, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configDir := path.Join(home, "/.config", "/nuclei")
|
||||
_ = os.MkdirAll(configDir, os.ModePerm)
|
||||
|
||||
templatesConfigFile := path.Join(configDir, nucleiConfigFilename)
|
||||
file, err := os.Open(templatesConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
config := &nucleiConfig{}
|
||||
err = jsoniter.NewDecoder(file).Decode(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// readConfiguration reads the nuclei configuration file from disk.
|
||||
func (r *Runner) writeConfiguration(config *nucleiConfig) error {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configDir := path.Join(home, "/.config", "/nuclei")
|
||||
_ = os.MkdirAll(configDir, os.ModePerm)
|
||||
|
||||
if config.IgnoreURL == "" {
|
||||
config.IgnoreURL = "https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/master/.nuclei-ignore"
|
||||
}
|
||||
config.LastChecked = time.Now()
|
||||
config.LastCheckedIgnore = time.Now()
|
||||
config.NucleiVersion = Version
|
||||
templatesConfigFile := path.Join(configDir, nucleiConfigFilename)
|
||||
file, err := os.OpenFile(templatesConfigFile, os.O_WRONLY|os.O_CREATE, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
err = jsoniter.NewEncoder(file).Encode(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const nucleiIgnoreFile = ".nuclei-ignore"
|
||||
|
||||
// readNucleiIgnoreFile reads the nuclei ignore file marking it in map
|
||||
func (r *Runner) readNucleiIgnoreFile() {
|
||||
file, err := os.Open(r.getIgnoreFilePath())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(text, "#") {
|
||||
continue
|
||||
}
|
||||
r.templatesConfig.IgnorePaths = append(r.templatesConfig.IgnorePaths, text)
|
||||
}
|
||||
}
|
||||
|
||||
// getIgnoreFilePath returns the ignore file path for the runner
|
||||
func (r *Runner) getIgnoreFilePath() string {
|
||||
var defIgnoreFilePath string
|
||||
|
||||
home, err := os.UserHomeDir()
|
||||
if err == nil {
|
||||
configDir := path.Join(home, "/.config", "/nuclei")
|
||||
_ = os.MkdirAll(configDir, os.ModePerm)
|
||||
|
||||
defIgnoreFilePath = path.Join(configDir, nucleiIgnoreFile)
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return defIgnoreFilePath
|
||||
}
|
||||
cwdIgnoreFilePath := path.Join(cwd, nucleiIgnoreFile)
|
||||
|
||||
cwdIfpInfo, err := os.Stat(cwdIgnoreFilePath)
|
||||
if os.IsNotExist(err) || cwdIfpInfo.IsDir() {
|
||||
return defIgnoreFilePath
|
||||
}
|
||||
return cwdIgnoreFilePath
|
||||
}
|
||||
@@ -2,18 +2,35 @@ package runner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"net/url"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"github.com/projectdiscovery/fileutil"
|
||||
"github.com/projectdiscovery/goflags"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/gologger/formatter"
|
||||
"github.com/projectdiscovery/gologger/levels"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||
)
|
||||
|
||||
func ConfigureOptions() error {
|
||||
isFromFileFunc := func(s string) bool {
|
||||
return !isTemplate(s)
|
||||
}
|
||||
goflags.DefaultFileNormalizedStringSliceOptions.IsFromFile = isFromFileFunc
|
||||
goflags.DefaultFileOriginalNormalizedStringSliceOptions.IsFromFile = isFromFileFunc
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseOptions parses the command line flags provided by a user
|
||||
func ParseOptions(options *types.Options) {
|
||||
// Check if stdin pipe was given
|
||||
@@ -21,21 +38,23 @@ func ParseOptions(options *types.Options) {
|
||||
|
||||
// Read the inputs and configure the logging
|
||||
configureOutput(options)
|
||||
|
||||
// Show the user the banner
|
||||
showBanner()
|
||||
|
||||
options.ExcludeTags = append(options.ExcludeTags, "dos")
|
||||
if !filepath.IsAbs(options.TemplatesDirectory) {
|
||||
cwd, _ := os.Getwd()
|
||||
options.TemplatesDirectory = filepath.Join(cwd, options.TemplatesDirectory)
|
||||
}
|
||||
if options.Version {
|
||||
gologger.Info().Msgf("Current Version: %s\n", Version)
|
||||
gologger.Info().Msgf("Current Version: %s\n", config.Version)
|
||||
os.Exit(0)
|
||||
}
|
||||
if options.TemplatesVersion {
|
||||
config, err := readConfiguration()
|
||||
configuration, err := config.ReadConfiguration()
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not read template configuration: %s\n", err)
|
||||
}
|
||||
gologger.Info().Msgf("Current nuclei-templates version: %s (%s)\n", config.CurrentVersion, config.TemplatesDirectory)
|
||||
gologger.Info().Msgf("Current nuclei-templates version: %s (%s)\n", configuration.TemplateVersion, configuration.TemplatesDirectory)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@@ -45,16 +64,17 @@ func ParseOptions(options *types.Options) {
|
||||
gologger.Fatal().Msgf("Program exiting: %s\n", err)
|
||||
}
|
||||
|
||||
// Auto adjust rate limits when using headless mode if the user
|
||||
// hasn't specified any custom limits.
|
||||
if options.Headless && options.BulkSize == 25 && options.TemplateThreads == 10 {
|
||||
options.BulkSize = 2
|
||||
options.TemplateThreads = 2
|
||||
}
|
||||
|
||||
// Load the resolvers if user asked for them
|
||||
loadResolvers(options)
|
||||
|
||||
// removes all cli variables containing payloads and add them to the internal struct
|
||||
for key, value := range options.Vars.AsMap() {
|
||||
if fileutil.FileExists(value.(string)) {
|
||||
_ = options.Vars.Del(key)
|
||||
options.AddVarPayload(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
err := protocolinit.Init(options)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not initialize protocols: %s\n", err)
|
||||
@@ -63,64 +83,59 @@ func ParseOptions(options *types.Options) {
|
||||
|
||||
// hasStdin returns true if we have stdin input
|
||||
func hasStdin() bool {
|
||||
stat, err := os.Stdin.Stat()
|
||||
fi, err := os.Stdin.Stat()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
isPipedFromChrDev := (stat.Mode() & os.ModeCharDevice) == 0
|
||||
isPipedFromFIFO := (stat.Mode() & os.ModeNamedPipe) != 0
|
||||
|
||||
return isPipedFromChrDev || isPipedFromFIFO
|
||||
if fi.Mode()&os.ModeNamedPipe == 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// validateOptions validates the configuration options passed
|
||||
func validateOptions(options *types.Options) error {
|
||||
// Both verbose and silent flags were used
|
||||
validate := validator.New()
|
||||
if err := validate.Struct(options); err != nil {
|
||||
if _, ok := err.(*validator.InvalidValidationError); ok {
|
||||
return err
|
||||
}
|
||||
errs := []string{}
|
||||
for _, err := range err.(validator.ValidationErrors) {
|
||||
errs = append(errs, err.Namespace()+": "+err.Tag())
|
||||
}
|
||||
return errors.Wrap(errors.New(strings.Join(errs, ", ")), "validation failed for these fields")
|
||||
}
|
||||
if options.Verbose && options.Silent {
|
||||
return errors.New("both verbose and silent mode specified")
|
||||
}
|
||||
// loading the proxy server list from file or cli and test the connectivity
|
||||
if err := loadProxyServers(options); err != nil {
|
||||
return err
|
||||
}
|
||||
if options.Validate {
|
||||
options.Headless = true // required for correct validation of headless templates
|
||||
validateTemplatePaths(options.TemplatesDirectory, options.Templates, options.Workflows)
|
||||
}
|
||||
|
||||
if !options.TemplateList {
|
||||
// Check if a list of templates was provided and it exists
|
||||
if len(options.Templates) == 0 && !options.NewTemplates && len(options.Workflows) == 0 && len(options.Tags) == 0 && !options.UpdateTemplates {
|
||||
return errors.New("no template/templates provided")
|
||||
// Verify if any of the client certificate options were set since it requires all three to work properly
|
||||
if len(options.ClientCertFile) > 0 || len(options.ClientKeyFile) > 0 || len(options.ClientCAFile) > 0 {
|
||||
if len(options.ClientCertFile) == 0 || len(options.ClientKeyFile) == 0 || len(options.ClientCAFile) == 0 {
|
||||
return errors.New("if a client certification option is provided, then all three must be provided")
|
||||
}
|
||||
}
|
||||
|
||||
// Validate proxy options if provided
|
||||
err := validateProxyURL(options.ProxyURL, "invalid http proxy format (It should be http://username:password@host:port)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validateProxyURL(options.ProxySocksURL, "invalid socks proxy format (It should be socks5://username:password@host:port)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateProxyURL(proxyURL, message string) error {
|
||||
if proxyURL != "" && !isValidURL(proxyURL) {
|
||||
return errors.New(message)
|
||||
validateCertificatePaths([]string{options.ClientCertFile, options.ClientKeyFile, options.ClientCAFile})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidURL(urlString string) bool {
|
||||
_, err := url.Parse(urlString)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// configureOutput configures the output on the screen
|
||||
// configureOutput configures the output logging levels to be displayed on the screen
|
||||
func configureOutput(options *types.Options) {
|
||||
// If the user desires verbose output, show verbose output
|
||||
if options.Verbose {
|
||||
if options.Verbose || options.Validate {
|
||||
gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
|
||||
}
|
||||
if options.Debug {
|
||||
if options.Debug || options.DebugRequests || options.DebugResponse {
|
||||
gologger.DefaultLogger.SetMaxLevel(levels.LevelDebug)
|
||||
}
|
||||
if options.NoColor {
|
||||
@@ -129,6 +144,10 @@ func configureOutput(options *types.Options) {
|
||||
if options.Silent {
|
||||
gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
|
||||
}
|
||||
|
||||
// disable standard logger (ref: https://github.com/golang/go/issues/19895)
|
||||
log.SetFlags(0)
|
||||
log.SetOutput(io.Discard)
|
||||
}
|
||||
|
||||
// loadResolvers loads resolvers from both user provided flag and file
|
||||
@@ -156,3 +175,31 @@ func loadResolvers(options *types.Options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateTemplatePaths(templatesDirectory string, templatePaths, workflowPaths []string) {
|
||||
allGivenTemplatePaths := append(templatePaths, workflowPaths...)
|
||||
for _, templatePath := range allGivenTemplatePaths {
|
||||
if templatesDirectory != templatePath && filepath.IsAbs(templatePath) {
|
||||
fileInfo, err := os.Stat(templatePath)
|
||||
if err == nil && fileInfo.IsDir() {
|
||||
relativizedPath, err2 := filepath.Rel(templatesDirectory, templatePath)
|
||||
if err2 != nil || (len(relativizedPath) >= 2 && relativizedPath[:2] == "..") {
|
||||
gologger.Warning().Msgf("The given path (%s) is outside the default template directory path (%s)! "+
|
||||
"Referenced sub-templates with relative paths in workflows will be resolved against the default template directory.", templatePath, templatesDirectory)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateCertificatePaths(certificatePaths []string) {
|
||||
for _, certificatePath := range certificatePaths {
|
||||
if _, err := os.Stat(certificatePath); os.IsNotExist(err) {
|
||||
// The provided path to the PEM certificate does not exist for the client authentication. As this is
|
||||
// required for successful authentication, log and return an error
|
||||
gologger.Fatal().Msgf("The given path (%s) to the certificate does not exist!", certificatePath)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
||||
"github.com/remeh/sizedwaitgroup"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
// processTemplateWithList process a template on the URL list
|
||||
func (r *Runner) processTemplateWithList(template *templates.Template) bool {
|
||||
results := &atomic.Bool{}
|
||||
wg := sizedwaitgroup.New(r.options.BulkSize)
|
||||
r.hostMap.Scan(func(k, _ []byte) error {
|
||||
URL := string(k)
|
||||
|
||||
wg.Add()
|
||||
go func(URL string) {
|
||||
defer wg.Done()
|
||||
|
||||
match, err := template.Executer.Execute(URL)
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("[%s] Could not execute step: %s\n", r.colorizer.BrightBlue(template.ID), err)
|
||||
}
|
||||
results.CAS(false, match)
|
||||
}(URL)
|
||||
return nil
|
||||
})
|
||||
wg.Wait()
|
||||
return results.Load()
|
||||
}
|
||||
|
||||
// processTemplateWithList process a template on the URL list
|
||||
func (r *Runner) processWorkflowWithList(template *templates.Template) bool {
|
||||
results := &atomic.Bool{}
|
||||
wg := sizedwaitgroup.New(r.options.BulkSize)
|
||||
|
||||
r.hostMap.Scan(func(k, _ []byte) error {
|
||||
URL := string(k)
|
||||
wg.Add()
|
||||
go func(URL string) {
|
||||
defer wg.Done()
|
||||
match := template.CompiledWorkflow.RunWorkflow(URL)
|
||||
results.CAS(false, match)
|
||||
}(URL)
|
||||
return nil
|
||||
})
|
||||
wg.Wait()
|
||||
return results.Load()
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/projectdiscovery/fileutil"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||
)
|
||||
|
||||
var proxyURLList []url.URL
|
||||
|
||||
// loadProxyServers load list of proxy servers from file or comma seperated
|
||||
func loadProxyServers(options *types.Options) error {
|
||||
if len(options.Proxy) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, p := range options.Proxy {
|
||||
if proxyURL, err := validateProxyURL(p); err == nil {
|
||||
proxyURLList = append(proxyURLList, proxyURL)
|
||||
} else if fileutil.FileExists(p) {
|
||||
file, err := os.Open(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open proxy file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
proxy := scanner.Text()
|
||||
if strings.TrimSpace(proxy) == "" {
|
||||
continue
|
||||
}
|
||||
if proxyURL, err := validateProxyURL(proxy); err != nil {
|
||||
return err
|
||||
} else {
|
||||
proxyURLList = append(proxyURLList, proxyURL)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("invalid proxy file or URL provided for %s", p)
|
||||
}
|
||||
}
|
||||
return processProxyList(options)
|
||||
}
|
||||
|
||||
func processProxyList(options *types.Options) error {
|
||||
if len(proxyURLList) == 0 {
|
||||
return fmt.Errorf("could not find any valid proxy")
|
||||
} else {
|
||||
done := make(chan bool)
|
||||
exitCounter := make(chan bool)
|
||||
counter := 0
|
||||
for _, url := range proxyURLList {
|
||||
go runProxyConnectivity(url, options, done, exitCounter)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
{
|
||||
close(done)
|
||||
return nil
|
||||
}
|
||||
case <-exitCounter:
|
||||
{
|
||||
if counter += 1; counter == len(proxyURLList) {
|
||||
return errors.New("no reachable proxy found")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runProxyConnectivity(proxyURL url.URL, options *types.Options, done chan bool, exitCounter chan bool) {
|
||||
if err := testProxyConnection(proxyURL, options.Timeout); err == nil {
|
||||
if types.ProxyURL == "" && types.ProxySocksURL == "" {
|
||||
assignProxyURL(proxyURL, options)
|
||||
done <- true
|
||||
}
|
||||
}
|
||||
exitCounter <- true
|
||||
}
|
||||
|
||||
func testProxyConnection(proxyURL url.URL, timeoutDelay int) error {
|
||||
timeout := time.Duration(timeoutDelay) * time.Second
|
||||
_, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%s", proxyURL.Hostname(), proxyURL.Port()), timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func assignProxyURL(proxyURL url.URL, options *types.Options) {
|
||||
os.Setenv(types.HTTP_PROXY_ENV, proxyURL.String())
|
||||
if proxyURL.Scheme == types.HTTP || proxyURL.Scheme == types.HTTPS {
|
||||
types.ProxyURL = proxyURL.String()
|
||||
types.ProxySocksURL = ""
|
||||
gologger.Verbose().Msgf("Using %s as proxy server", proxyURL.String())
|
||||
} else if proxyURL.Scheme == types.SOCKS5 {
|
||||
types.ProxyURL = ""
|
||||
types.ProxySocksURL = proxyURL.String()
|
||||
gologger.Verbose().Msgf("Using %s as socket proxy server", proxyURL.String())
|
||||
}
|
||||
}
|
||||
|
||||
func validateProxyURL(proxy string) (url.URL, error) {
|
||||
if url, err := url.Parse(proxy); err == nil && isSupportedProtocol(url.Scheme) {
|
||||
return *url, nil
|
||||
}
|
||||
return url.URL{}, errors.New("invalid proxy format (It should be http[s]/socks5://[username:password@]host:port)")
|
||||
}
|
||||
|
||||
// isSupportedProtocol checks given protocols are supported
|
||||
func isSupportedProtocol(value string) bool {
|
||||
return value == types.HTTP || value == types.HTTPS || value == types.SOCKS5
|
||||
}
|
||||
+338
-222
@@ -2,49 +2,62 @@ package runner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/ratelimit"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/hmap/store/hybrid"
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/collaborator"
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/colorizer"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/loader"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/core"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/core/inputs/hybrid"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/progress"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/projectfile"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/clusterer"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/hosterrorscache"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/interactsh"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/protocolinit"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/headless/engine"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/reporting"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/exporters/disk"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/exporters/markdown"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/exporters/sarif"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||
"github.com/remeh/sizedwaitgroup"
|
||||
"github.com/rs/xid"
|
||||
"go.uber.org/atomic"
|
||||
"go.uber.org/ratelimit"
|
||||
"gopkg.in/yaml.v2"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/utils"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/utils/stats"
|
||||
yamlwrapper "github.com/projectdiscovery/nuclei/v2/pkg/utils/yaml"
|
||||
"github.com/projectdiscovery/stringsutil"
|
||||
)
|
||||
|
||||
// Runner is a client for running the enumeration process.
|
||||
type Runner struct {
|
||||
hostMap *hybrid.HybridMap
|
||||
output output.Writer
|
||||
inputCount int64
|
||||
templatesConfig *nucleiConfig
|
||||
options *types.Options
|
||||
projectFile *projectfile.ProjectFile
|
||||
catalog *catalog.Catalog
|
||||
progress progress.Progress
|
||||
colorizer aurora.Aurora
|
||||
issuesClient *reporting.Client
|
||||
severityColors *colorizer.Colorizer
|
||||
browser *engine.Browser
|
||||
ratelimiter ratelimit.Limiter
|
||||
output output.Writer
|
||||
interactsh *interactsh.Client
|
||||
templatesConfig *config.Config
|
||||
options *types.Options
|
||||
projectFile *projectfile.ProjectFile
|
||||
catalog *catalog.Catalog
|
||||
progress progress.Progress
|
||||
colorizer aurora.Aurora
|
||||
issuesClient *reporting.Client
|
||||
addColor func(severity.Severity) string
|
||||
hmapInputProvider *hybrid.Input
|
||||
browser *engine.Browser
|
||||
ratelimiter ratelimit.Limiter
|
||||
hostErrors *hosterrorscache.Cache
|
||||
resumeCfg *types.ResumeCfg
|
||||
}
|
||||
|
||||
// New creates a new client for running enumeration process.
|
||||
@@ -52,155 +65,137 @@ func New(options *types.Options) (*Runner, error) {
|
||||
runner := &Runner{
|
||||
options: options,
|
||||
}
|
||||
if options.UpdateNuclei {
|
||||
if err := updateNucleiVersionToLatest(runner.options.Verbose); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
if options.Validate {
|
||||
parsers.ShouldValidate = true
|
||||
// Does not update the templates when validate flag is used
|
||||
options.NoUpdateTemplates = true
|
||||
}
|
||||
if err := runner.updateTemplates(); err != nil {
|
||||
gologger.Error().Msgf("Could not update templates: %s\n", err)
|
||||
}
|
||||
if options.Headless {
|
||||
if engine.MustDisableSandbox() {
|
||||
gologger.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
|
||||
}
|
||||
if err := runner.updateTemplates(); err != nil {
|
||||
gologger.Warning().Msgf("Could not update templates: %s\n", err)
|
||||
}
|
||||
// Read nucleiignore file if given a templateconfig
|
||||
if runner.templatesConfig != nil {
|
||||
runner.readNucleiIgnoreFile()
|
||||
}
|
||||
|
||||
runner.catalog = catalog.New(runner.options.TemplatesDirectory)
|
||||
|
||||
var reportingOptions *reporting.Options
|
||||
if options.ReportingConfig != "" {
|
||||
file, err := os.Open(options.ReportingConfig)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not open reporting config file: %s\n", err)
|
||||
}
|
||||
|
||||
reportingOptions = &reporting.Options{}
|
||||
if parseErr := yaml.NewDecoder(file).Decode(reportingOptions); parseErr != nil {
|
||||
file.Close()
|
||||
gologger.Fatal().Msgf("Could not parse reporting config file: %s\n", parseErr)
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
if options.DiskExportDirectory != "" {
|
||||
if reportingOptions != nil {
|
||||
reportingOptions.DiskExporter = &disk.Options{Directory: options.DiskExportDirectory}
|
||||
} else {
|
||||
reportingOptions = &reporting.Options{}
|
||||
reportingOptions.DiskExporter = &disk.Options{Directory: options.DiskExportDirectory}
|
||||
}
|
||||
reportingOptions, err := createReportingOptions(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reportingOptions != nil {
|
||||
if client, err := reporting.New(reportingOptions, options.ReportingDB); err != nil {
|
||||
gologger.Fatal().Msgf("Could not create issue reporting client: %s\n", err)
|
||||
} else {
|
||||
runner.issuesClient = client
|
||||
client, err := reporting.New(reportingOptions, options.ReportingDB)
|
||||
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.severityColors = colorizer.New(runner.colorizer)
|
||||
runner.addColor = colorizer.New(runner.colorizer)
|
||||
|
||||
if options.TemplateList {
|
||||
runner.listAvailableTemplates()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if (len(options.Templates) == 0 || !options.NewTemplates || (options.Targets == "" && !options.Stdin && options.Target == "")) && options.UpdateTemplates {
|
||||
if (len(options.Templates) == 0 || !options.NewTemplates || (options.TargetsFilePath == "" && !options.Stdin && len(options.Targets) == 0)) && options.UpdateTemplates {
|
||||
os.Exit(0)
|
||||
}
|
||||
if hm, err := hybrid.New(hybrid.DefaultDiskOptions); err != nil {
|
||||
gologger.Fatal().Msgf("Could not create temporary input file: %s\n", err)
|
||||
} else {
|
||||
runner.hostMap = hm
|
||||
}
|
||||
|
||||
runner.inputCount = 0
|
||||
dupeCount := 0
|
||||
|
||||
// Handle single target
|
||||
if options.Target != "" {
|
||||
runner.inputCount++
|
||||
// nolint:errcheck // ignoring error
|
||||
runner.hostMap.Set(options.Target, nil)
|
||||
}
|
||||
|
||||
// Handle stdin
|
||||
if options.Stdin {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
url := strings.TrimSpace(scanner.Text())
|
||||
if url == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := runner.hostMap.Get(url); ok {
|
||||
dupeCount++
|
||||
continue
|
||||
}
|
||||
runner.inputCount++
|
||||
// nolint:errcheck // ignoring error
|
||||
runner.hostMap.Set(url, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle taget file
|
||||
if options.Targets != "" {
|
||||
input, err := os.Open(options.Targets)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not open targets file '%s': %s\n", options.Targets, err)
|
||||
}
|
||||
scanner := bufio.NewScanner(input)
|
||||
for scanner.Scan() {
|
||||
url := strings.TrimSpace(scanner.Text())
|
||||
if url == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := runner.hostMap.Get(url); ok {
|
||||
dupeCount++
|
||||
continue
|
||||
}
|
||||
runner.inputCount++
|
||||
// nolint:errcheck // ignoring error
|
||||
runner.hostMap.Set(url, nil)
|
||||
}
|
||||
input.Close()
|
||||
}
|
||||
|
||||
if dupeCount > 0 {
|
||||
gologger.Info().Msgf("Supplied input was automatically deduplicated (%d removed).", dupeCount)
|
||||
// Initialize the input source
|
||||
hmapInput, err := hybrid.New(options)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create input provider")
|
||||
}
|
||||
runner.hmapInputProvider = hmapInput
|
||||
|
||||
// Create the output file if asked
|
||||
outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.JSON, options.Output, options.TraceLogFile)
|
||||
outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.NoTimestamp, options.JSON, options.JSONRequests, options.MatcherStatus, options.Output, options.TraceLogFile, options.ErrorLogFile)
|
||||
if err != nil {
|
||||
gologger.Fatal().Msgf("Could not create output file '%s': %s\n", options.Output, err)
|
||||
return nil, errors.Wrap(err, "could not create output file")
|
||||
}
|
||||
runner.output = outputWriter
|
||||
|
||||
if options.JSON && options.EnableProgressBar {
|
||||
options.StatsJSON = true
|
||||
}
|
||||
if options.StatsJSON {
|
||||
options.EnableProgressBar = true
|
||||
}
|
||||
// Creates the progress tracking object
|
||||
var progressErr error
|
||||
runner.progress, progressErr = progress.NewStatsTicker(options.StatsInterval, options.EnableProgressBar, options.Metrics, options.MetricsPort)
|
||||
runner.progress, progressErr = progress.NewStatsTicker(options.StatsInterval, options.EnableProgressBar, options.StatsJSON, options.Metrics, options.MetricsPort)
|
||||
if progressErr != nil {
|
||||
return nil, progressErr
|
||||
}
|
||||
|
||||
// create project file if requested or load existing one
|
||||
// create project file if requested or load the existing one
|
||||
if options.Project {
|
||||
var projectFileErr error
|
||||
runner.projectFile, projectFileErr = projectfile.New(&projectfile.Options{Path: options.ProjectPath, Cleanup: options.ProjectPath == ""})
|
||||
runner.projectFile, projectFileErr = projectfile.New(&projectfile.Options{Path: options.ProjectPath, Cleanup: utils.IsBlank(options.ProjectPath)})
|
||||
if projectFileErr != nil {
|
||||
return nil, projectFileErr
|
||||
}
|
||||
}
|
||||
|
||||
// Enable Polling
|
||||
if options.BurpCollaboratorBiid != "" {
|
||||
collaborator.DefaultCollaborator.Collab.AddBIID(options.BurpCollaboratorBiid)
|
||||
// create the resume configuration structure
|
||||
resumeCfg := types.NewResumeCfg()
|
||||
if runner.options.ShouldLoadResume() {
|
||||
gologger.Info().Msg("Resuming from save checkpoint")
|
||||
file, err := ioutil.ReadFile(types.DefaultResumeFilePath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal([]byte(file), &resumeCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resumeCfg.Compile()
|
||||
}
|
||||
|
||||
if options.RateLimit > 0 {
|
||||
runner.resumeCfg = resumeCfg
|
||||
|
||||
opts := interactsh.NewDefaultOptions(runner.output, runner.issuesClient, runner.progress)
|
||||
opts.Debug = runner.options.Debug
|
||||
if options.InteractshURL != "" {
|
||||
opts.ServerURL = options.InteractshURL
|
||||
}
|
||||
opts.Authorization = options.InteractshToken
|
||||
opts.CacheSize = int64(options.InteractionsCacheSize)
|
||||
opts.Eviction = time.Duration(options.InteractionsEviction) * time.Second
|
||||
opts.ColldownPeriod = time.Duration(options.InteractionsCoolDownPeriod) * time.Second
|
||||
opts.PollDuration = time.Duration(options.InteractionsPollDuration) * time.Second
|
||||
opts.NoInteractsh = runner.options.NoInteractsh
|
||||
opts.StopAtFirstMatch = runner.options.StopAtFirstMatch
|
||||
opts.Debug = runner.options.Debug
|
||||
opts.DebugRequest = runner.options.DebugRequests
|
||||
opts.DebugResponse = runner.options.DebugResponse
|
||||
interactshClient, err := interactsh.New(opts)
|
||||
if err != nil {
|
||||
gologger.Error().Msgf("Could not create interactsh client: %s", err)
|
||||
} else {
|
||||
runner.interactsh = interactshClient
|
||||
}
|
||||
|
||||
if options.RateLimitMinute > 0 {
|
||||
runner.ratelimiter = ratelimit.New(options.RateLimitMinute, ratelimit.Per(60*time.Second))
|
||||
} else if options.RateLimit > 0 {
|
||||
runner.ratelimiter = ratelimit.New(options.RateLimit)
|
||||
} else {
|
||||
runner.ratelimiter = ratelimit.NewUnlimited()
|
||||
@@ -208,168 +203,246 @@ func New(options *types.Options) (*Runner, error) {
|
||||
return runner, nil
|
||||
}
|
||||
|
||||
func createReportingOptions(options *types.Options) (*reporting.Options, error) {
|
||||
var reportingOptions *reporting.Options
|
||||
if options.ReportingConfig != "" {
|
||||
file, err := os.Open(options.ReportingConfig)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not open reporting config file")
|
||||
}
|
||||
|
||||
reportingOptions = &reporting.Options{}
|
||||
if err := yamlwrapper.DecodeAndValidate(file, reportingOptions); err != nil {
|
||||
file.Close()
|
||||
return nil, errors.Wrap(err, "could not parse reporting config file")
|
||||
}
|
||||
file.Close()
|
||||
}
|
||||
if options.MarkdownExportDirectory != "" {
|
||||
if reportingOptions != nil {
|
||||
reportingOptions.MarkdownExporter = &markdown.Options{Directory: options.MarkdownExportDirectory}
|
||||
} else {
|
||||
reportingOptions = &reporting.Options{}
|
||||
reportingOptions.MarkdownExporter = &markdown.Options{Directory: options.MarkdownExportDirectory}
|
||||
}
|
||||
}
|
||||
if options.SarifExport != "" {
|
||||
if reportingOptions != nil {
|
||||
reportingOptions.SarifExporter = &sarif.Options{File: options.SarifExport}
|
||||
} else {
|
||||
reportingOptions = &reporting.Options{}
|
||||
reportingOptions.SarifExporter = &sarif.Options{File: options.SarifExport}
|
||||
}
|
||||
}
|
||||
return reportingOptions, nil
|
||||
}
|
||||
|
||||
// Close releases all the resources and cleans up
|
||||
func (r *Runner) Close() {
|
||||
if r.output != nil {
|
||||
r.output.Close()
|
||||
}
|
||||
r.hostMap.Close()
|
||||
if r.projectFile != nil {
|
||||
r.projectFile.Close()
|
||||
}
|
||||
r.hmapInputProvider.Close()
|
||||
protocolinit.Close()
|
||||
}
|
||||
|
||||
// RunEnumeration sets up the input layer for giving input nuclei.
|
||||
// binary and runs the actual enumeration
|
||||
func (r *Runner) RunEnumeration() {
|
||||
func (r *Runner) RunEnumeration() error {
|
||||
defer r.Close()
|
||||
|
||||
// If we have no templates, run on whole template directory with provided tags
|
||||
if len(r.options.Templates) == 0 && len(r.options.Workflows) == 0 && !r.options.NewTemplates && (len(r.options.Tags) > 0 || len(r.options.ExcludeTags) > 0) {
|
||||
r.options.Templates = append(r.options.Templates, r.options.TemplatesDirectory)
|
||||
}
|
||||
// If user asked for new templates to be executed, collect the list from the templates' directory.
|
||||
if r.options.NewTemplates {
|
||||
templatesLoaded, err := r.readNewTemplatesFile()
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("Could not get newly added templates: %s\n", err)
|
||||
return errors.Wrap(err, "could not get newly added templates")
|
||||
}
|
||||
r.options.Templates = append(r.options.Templates, templatesLoaded...)
|
||||
}
|
||||
includedTemplates := r.catalog.GetTemplatesPath(r.options.Templates)
|
||||
excludedTemplates := r.catalog.GetTemplatesPath(r.options.ExcludedTemplates)
|
||||
// defaults to all templates
|
||||
allTemplates := includedTemplates
|
||||
// Exclude ignored file for validation
|
||||
if !r.options.Validate {
|
||||
ignoreFile := config.ReadIgnoreFile()
|
||||
r.options.ExcludeTags = append(r.options.ExcludeTags, ignoreFile.Tags...)
|
||||
r.options.ExcludedTemplates = append(r.options.ExcludedTemplates, ignoreFile.Files...)
|
||||
}
|
||||
var cache *hosterrorscache.Cache
|
||||
if r.options.MaxHostError > 0 {
|
||||
cache = hosterrorscache.New(r.options.MaxHostError, hosterrorscache.DefaultMaxHostsCount).SetVerbose(r.options.Verbose)
|
||||
}
|
||||
r.hostErrors = cache
|
||||
|
||||
if len(excludedTemplates) > 0 {
|
||||
excludedMap := make(map[string]struct{}, len(excludedTemplates))
|
||||
for _, excl := range excludedTemplates {
|
||||
excludedMap[excl] = struct{}{}
|
||||
}
|
||||
// rebuild list with only non-excluded templates
|
||||
allTemplates = []string{}
|
||||
// Create the executer options which will be used throughout the execution
|
||||
// stage by the nuclei engine modules.
|
||||
executerOpts := protocols.ExecuterOptions{
|
||||
Output: r.output,
|
||||
Options: r.options,
|
||||
Progress: r.progress,
|
||||
Catalog: r.catalog,
|
||||
IssuesClient: r.issuesClient,
|
||||
RateLimiter: r.ratelimiter,
|
||||
Interactsh: r.interactsh,
|
||||
ProjectFile: r.projectFile,
|
||||
Browser: r.browser,
|
||||
HostErrorsCache: cache,
|
||||
Colorizer: r.colorizer,
|
||||
ResumeCfg: r.resumeCfg,
|
||||
}
|
||||
engine := core.New(r.options)
|
||||
engine.SetExecuterOptions(executerOpts)
|
||||
|
||||
for _, incl := range includedTemplates {
|
||||
if _, found := excludedMap[incl]; !found {
|
||||
allTemplates = append(allTemplates, incl)
|
||||
} else {
|
||||
gologger.Warning().Msgf("Excluding '%s'", incl)
|
||||
}
|
||||
workflowLoader, err := parsers.NewLoader(&executerOpts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not create loader.")
|
||||
}
|
||||
executerOpts.WorkflowLoader = workflowLoader
|
||||
|
||||
store, err := loader.New(loader.NewConfig(r.options, r.catalog, executerOpts))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not load templates from config")
|
||||
}
|
||||
store.Load()
|
||||
|
||||
if r.options.Validate {
|
||||
if err := store.ValidateTemplates(r.options.Templates, r.options.Workflows); err != nil {
|
||||
return err
|
||||
}
|
||||
if stats.GetValue(parsers.SyntaxErrorStats) == 0 && stats.GetValue(parsers.SyntaxWarningStats) == 0 && stats.GetValue(parsers.RuntimeWarningsStats) == 0 {
|
||||
gologger.Info().Msgf("All templates validated successfully\n")
|
||||
} else {
|
||||
return errors.New("encountered errors while performing template validation")
|
||||
}
|
||||
return nil // exit
|
||||
}
|
||||
|
||||
// pre-parse all the templates, apply filters
|
||||
finalTemplates := []*templates.Template{}
|
||||
r.displayExecutionInfo(store)
|
||||
|
||||
workflowPaths := r.catalog.GetTemplatesPath(r.options.Workflows)
|
||||
availableTemplates, _ := r.getParsedTemplatesFor(allTemplates, r.options.Severity, false)
|
||||
availableWorkflows, workflowCount := r.getParsedTemplatesFor(workflowPaths, r.options.Severity, true)
|
||||
|
||||
var unclusteredRequests int64 = 0
|
||||
for _, template := range availableTemplates {
|
||||
var unclusteredRequests int64
|
||||
for _, template := range store.Templates() {
|
||||
// workflows will dynamically adjust the totals while running, as
|
||||
// it can't be know in advance which requests will be called
|
||||
// it can't be known in advance which requests will be called
|
||||
if len(template.Workflows) > 0 {
|
||||
continue
|
||||
}
|
||||
unclusteredRequests += int64(template.TotalRequests) * r.inputCount
|
||||
unclusteredRequests += int64(template.TotalRequests) * r.hmapInputProvider.Count()
|
||||
}
|
||||
|
||||
originalTemplatesCount := len(availableTemplates)
|
||||
clusterCount := 0
|
||||
clusters := clusterer.Cluster(availableTemplates)
|
||||
for _, cluster := range clusters {
|
||||
if len(cluster) > 1 && !r.options.OfflineHTTP {
|
||||
executerOpts := protocols.ExecuterOptions{
|
||||
Output: r.output,
|
||||
Options: r.options,
|
||||
Progress: r.progress,
|
||||
Catalog: r.catalog,
|
||||
RateLimiter: r.ratelimiter,
|
||||
IssuesClient: r.issuesClient,
|
||||
Browser: r.browser,
|
||||
ProjectFile: r.projectFile,
|
||||
}
|
||||
clusterID := fmt.Sprintf("cluster-%s", xid.New().String())
|
||||
|
||||
finalTemplates = append(finalTemplates, &templates.Template{
|
||||
ID: clusterID,
|
||||
RequestsHTTP: cluster[0].RequestsHTTP,
|
||||
Executer: clusterer.NewExecuter(cluster, &executerOpts),
|
||||
TotalRequests: len(cluster[0].RequestsHTTP),
|
||||
})
|
||||
clusterCount += len(cluster)
|
||||
} else {
|
||||
finalTemplates = append(finalTemplates, cluster...)
|
||||
if r.options.VerboseVerbose {
|
||||
for _, template := range store.Templates() {
|
||||
r.logAvailableTemplate(template.Path)
|
||||
}
|
||||
for _, template := range store.Workflows() {
|
||||
r.logAvailableTemplate(template.Path)
|
||||
}
|
||||
}
|
||||
for _, workflows := range availableWorkflows {
|
||||
finalTemplates = append(finalTemplates, workflows)
|
||||
}
|
||||
|
||||
var totalRequests int64 = 0
|
||||
// Cluster the templates first because we want info on how many
|
||||
// templates did we cluster for showing to user in CLI
|
||||
originalTemplatesCount := len(store.Templates())
|
||||
finalTemplates, clusterCount := templates.ClusterTemplates(store.Templates(), engine.ExecuterOptions())
|
||||
finalTemplates = append(finalTemplates, store.Workflows()...)
|
||||
|
||||
var totalRequests int64
|
||||
for _, t := range finalTemplates {
|
||||
if len(t.Workflows) > 0 {
|
||||
continue
|
||||
}
|
||||
totalRequests += int64(t.TotalRequests) * r.inputCount
|
||||
totalRequests += int64(t.Executer.Requests()) * r.hmapInputProvider.Count()
|
||||
}
|
||||
if totalRequests < unclusteredRequests {
|
||||
gologger.Info().Msgf("Reduced %d requests to %d (%d templates clustered)", unclusteredRequests, totalRequests, clusterCount)
|
||||
gologger.Info().Msgf("Templates clustered: %d (Reduced %d HTTP Requests)", clusterCount, unclusteredRequests-totalRequests)
|
||||
}
|
||||
templateCount := originalTemplatesCount + len(availableWorkflows)
|
||||
workflowCount := len(store.Workflows())
|
||||
templateCount := originalTemplatesCount + workflowCount
|
||||
|
||||
// 0 matches means no templates were found in directory
|
||||
if templateCount == 0 {
|
||||
gologger.Fatal().Msgf("Error, no templates were found.\n")
|
||||
return errors.New("no valid templates were found")
|
||||
}
|
||||
|
||||
gologger.Info().Msgf("Using %s rules (%s templates, %s workflows)",
|
||||
r.colorizer.Bold(templateCount).String(),
|
||||
r.colorizer.Bold(templateCount-workflowCount).String(),
|
||||
r.colorizer.Bold(workflowCount).String())
|
||||
|
||||
results := &atomic.Bool{}
|
||||
wgtemplates := sizedwaitgroup.New(r.options.TemplateThreads)
|
||||
// Starts polling or ignore
|
||||
collaborator.DefaultCollaborator.Poll()
|
||||
|
||||
// tracks global progress and captures stdout/stderr until p.Wait finishes
|
||||
r.progress.Init(r.inputCount, templateCount, totalRequests)
|
||||
r.progress.Init(r.hmapInputProvider.Count(), templateCount, totalRequests)
|
||||
|
||||
for _, t := range finalTemplates {
|
||||
wgtemplates.Add()
|
||||
go func(template *templates.Template) {
|
||||
defer wgtemplates.Done()
|
||||
results := engine.ExecuteWithOpts(finalTemplates, r.hmapInputProvider, true)
|
||||
|
||||
if len(template.Workflows) > 0 {
|
||||
results.CAS(false, r.processWorkflowWithList(template))
|
||||
} else {
|
||||
results.CAS(false, r.processTemplateWithList(template))
|
||||
}
|
||||
}(t)
|
||||
if r.interactsh != nil {
|
||||
matched := r.interactsh.Close()
|
||||
if matched {
|
||||
results.CAS(false, true)
|
||||
}
|
||||
}
|
||||
wgtemplates.Wait()
|
||||
r.progress.Stop()
|
||||
|
||||
if r.issuesClient != nil {
|
||||
r.issuesClient.Close()
|
||||
}
|
||||
if !results.Load() {
|
||||
if r.output != nil {
|
||||
r.output.Close()
|
||||
os.Remove(r.options.Output)
|
||||
}
|
||||
gologger.Info().Msgf("No results found. Better luck next time!")
|
||||
}
|
||||
|
||||
if r.browser != nil {
|
||||
r.browser.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// displayExecutionInfo displays misc info about the nuclei engine execution
|
||||
func (r *Runner) displayExecutionInfo(store *loader.Store) {
|
||||
// Display stats for any loaded templates' syntax warnings or errors
|
||||
stats.Display(parsers.SyntaxWarningStats)
|
||||
stats.Display(parsers.SyntaxErrorStats)
|
||||
stats.Display(parsers.RuntimeWarningsStats)
|
||||
|
||||
builder := &strings.Builder{}
|
||||
if r.templatesConfig != nil && r.templatesConfig.NucleiLatestVersion != "" {
|
||||
builder.WriteString(" (")
|
||||
|
||||
if strings.Contains(config.Version, "-dev") {
|
||||
builder.WriteString(r.colorizer.Blue("development").String())
|
||||
} else if config.Version == r.templatesConfig.NucleiLatestVersion {
|
||||
builder.WriteString(r.colorizer.Green("latest").String())
|
||||
} else {
|
||||
builder.WriteString(r.colorizer.Red("outdated").String())
|
||||
}
|
||||
builder.WriteString(")")
|
||||
}
|
||||
messageStr := builder.String()
|
||||
builder.Reset()
|
||||
|
||||
gologger.Info().Msgf("Using Nuclei Engine %s%s", config.Version, messageStr)
|
||||
|
||||
if r.templatesConfig != nil && r.templatesConfig.NucleiTemplatesLatestVersion != "" { // TODO extract duplicated logic
|
||||
builder.WriteString(" (")
|
||||
|
||||
if r.templatesConfig.TemplateVersion == r.templatesConfig.NucleiTemplatesLatestVersion {
|
||||
builder.WriteString(r.colorizer.Green("latest").String())
|
||||
} else {
|
||||
builder.WriteString(r.colorizer.Red("outdated").String())
|
||||
}
|
||||
builder.WriteString(")")
|
||||
}
|
||||
messageStr = builder.String()
|
||||
builder.Reset()
|
||||
|
||||
if r.templatesConfig != nil {
|
||||
gologger.Info().Msgf("Using Nuclei Templates %s%s", r.templatesConfig.TemplateVersion, messageStr)
|
||||
}
|
||||
if len(store.Templates()) > 0 {
|
||||
gologger.Info().Msgf("Templates added in last update: %d", r.countNewTemplates())
|
||||
gologger.Info().Msgf("Templates loaded for scan: %d", len(store.Templates()))
|
||||
}
|
||||
if len(store.Workflows()) > 0 {
|
||||
gologger.Info().Msgf("Workflows loaded for scan: %d", len(store.Workflows()))
|
||||
}
|
||||
}
|
||||
|
||||
// readNewTemplatesFile reads newly added templates from directory if it exists
|
||||
func (r *Runner) readNewTemplatesFile() ([]string, error) {
|
||||
additionsFile := path.Join(r.templatesConfig.TemplatesDirectory, ".new-additions")
|
||||
if r.templatesConfig == nil {
|
||||
return nil, nil
|
||||
}
|
||||
additionsFile := filepath.Join(r.templatesConfig.TemplatesDirectory, ".new-additions")
|
||||
file, err := os.Open(additionsFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -383,7 +456,50 @@ func (r *Runner) readNewTemplatesFile() ([]string, error) {
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
templatesList = append(templatesList, text)
|
||||
if isTemplate(text) {
|
||||
templatesList = append(templatesList, text)
|
||||
}
|
||||
}
|
||||
return templatesList, nil
|
||||
}
|
||||
|
||||
// countNewTemplates returns the number of newly added templates
|
||||
func (r *Runner) countNewTemplates() int {
|
||||
if r.templatesConfig == nil {
|
||||
return 0
|
||||
}
|
||||
additionsFile := filepath.Join(r.templatesConfig.TemplatesDirectory, ".new-additions")
|
||||
file, err := os.Open(additionsFile)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
count := 0
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if isTemplate(text) {
|
||||
count++
|
||||
}
|
||||
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func isTemplate(filename string) bool {
|
||||
return stringsutil.EqualFoldAny(filepath.Ext(filename), templates.TemplateExtension)
|
||||
}
|
||||
|
||||
// SaveResumeConfig to file
|
||||
func (r *Runner) SaveResumeConfig() error {
|
||||
resumeCfg := types.NewResumeCfg()
|
||||
resumeCfg.ResumeFrom = r.resumeCfg.Current
|
||||
data, _ := json.MarshalIndent(resumeCfg, "", "\t")
|
||||
|
||||
return os.WriteFile(types.DefaultResumeFilePath(), data, os.ModePerm)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||
)
|
||||
|
||||
func Test_createReportingOptions(t *testing.T) {
|
||||
var options types.Options
|
||||
options.ReportingConfig = "../../../integration_tests/test-issue-tracker-config1.yaml"
|
||||
resultOptions, err := createReportingOptions(&options)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, resultOptions.AllowList.Severities, severity.Severities{severity.High, severity.Critical})
|
||||
assert.Equal(t, resultOptions.DenyList.Severities, severity.Severities{severity.Low})
|
||||
|
||||
options.ReportingConfig = "../../../integration_tests/test-issue-tracker-config2.yaml"
|
||||
resultOptions2, err := createReportingOptions(&options)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, resultOptions2.AllowList.Severities, resultOptions.AllowList.Severities)
|
||||
assert.Equal(t, resultOptions2.DenyList.Severities, resultOptions.DenyList.Severities)
|
||||
}
|
||||
+31
-102
@@ -6,97 +6,52 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/karrick/godirwalk"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/parsers"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||
)
|
||||
|
||||
// getParsedTemplatesFor parse the specified templates and returns a slice of the parsable ones, optionally filtered
|
||||
// by severity, along with a flag indicating if workflows are present.
|
||||
func (r *Runner) getParsedTemplatesFor(templatePaths, severities []string, workflows bool) (parsedTemplates map[string]*templates.Template, workflowCount int) {
|
||||
filterBySeverity := len(severities) > 0
|
||||
|
||||
if !workflows {
|
||||
gologger.Info().Msgf("Loading templates...")
|
||||
} else {
|
||||
gologger.Info().Msgf("Loading workflows...")
|
||||
}
|
||||
|
||||
parsedTemplates = make(map[string]*templates.Template)
|
||||
for _, match := range templatePaths {
|
||||
t, err := r.parseTemplateFile(match)
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("Could not parse file '%s': %s\n", match, err)
|
||||
continue
|
||||
}
|
||||
if t == nil {
|
||||
continue
|
||||
}
|
||||
if len(t.Workflows) == 0 && workflows {
|
||||
continue // don't print if user only wants to run workflows
|
||||
}
|
||||
if len(t.Workflows) > 0 && !workflows {
|
||||
continue // don't print workflow if user only wants to run templates
|
||||
}
|
||||
if len(t.Workflows) > 0 {
|
||||
workflowCount++
|
||||
}
|
||||
sev := strings.ToLower(types.ToString(t.Info["severity"]))
|
||||
if !filterBySeverity || hasMatchingSeverity(sev, severities) {
|
||||
parsedTemplates[t.ID] = t
|
||||
gologger.Info().Msgf("%s\n", r.templateLogMsg(t.ID, types.ToString(t.Info["name"]), types.ToString(t.Info["author"]), sev))
|
||||
} else {
|
||||
gologger.Warning().Msgf("Excluding template %s due to severity filter (%s not in [%s])", t.ID, sev, severities)
|
||||
}
|
||||
}
|
||||
return parsedTemplates, workflowCount
|
||||
}
|
||||
|
||||
// parseTemplateFile returns the parsed template file
|
||||
func (r *Runner) parseTemplateFile(file string) (*templates.Template, error) {
|
||||
executerOpts := protocols.ExecuterOptions{
|
||||
Output: r.output,
|
||||
Options: r.options,
|
||||
Progress: r.progress,
|
||||
Catalog: r.catalog,
|
||||
IssuesClient: r.issuesClient,
|
||||
RateLimiter: r.ratelimiter,
|
||||
ProjectFile: r.projectFile,
|
||||
Browser: r.browser,
|
||||
}
|
||||
template, err := templates.Parse(file, executerOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if template == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return template, nil
|
||||
}
|
||||
|
||||
func (r *Runner) templateLogMsg(id, name, author, severity string) string {
|
||||
func (r *Runner) templateLogMsg(id, name string, authors []string, templateSeverity severity.Severity) string {
|
||||
// Display the message for the template
|
||||
message := fmt.Sprintf("[%s] %s (%s)",
|
||||
return fmt.Sprintf("[%s] %s (%s) [%s]",
|
||||
r.colorizer.BrightBlue(id).String(),
|
||||
r.colorizer.Bold(name).String(),
|
||||
r.colorizer.BrightYellow("@"+author).String())
|
||||
if severity != "" {
|
||||
message += " [" + r.severityColors.Data[severity] + "]"
|
||||
r.colorizer.BrightYellow(appendAtSignToAuthors(authors)).String(),
|
||||
r.addColor(templateSeverity))
|
||||
}
|
||||
|
||||
// appendAtSignToAuthors appends @ before each author and returns the final string
|
||||
func appendAtSignToAuthors(authors []string) string {
|
||||
if len(authors) == 0 {
|
||||
return "@none"
|
||||
}
|
||||
return message
|
||||
|
||||
values := make([]string, 0, len(authors))
|
||||
for _, k := range authors {
|
||||
if !strings.HasPrefix(k, "@") {
|
||||
values = append(values, fmt.Sprintf("@%s", k))
|
||||
} else {
|
||||
values = append(values, k)
|
||||
}
|
||||
}
|
||||
return strings.Join(values, ",")
|
||||
}
|
||||
|
||||
func (r *Runner) logAvailableTemplate(tplPath string) {
|
||||
t, err := r.parseTemplateFile(tplPath)
|
||||
t, err := parsers.ParseTemplate(tplPath)
|
||||
if err != nil {
|
||||
gologger.Error().Msgf("Could not parse file '%s': %s\n", tplPath, err)
|
||||
} else {
|
||||
gologger.Print().Msgf("%s\n", r.templateLogMsg(t.ID, types.ToString(t.Info["name"]), types.ToString(t.Info["author"]), types.ToString(t.Info["severity"])))
|
||||
gologger.Print().Msgf("%s\n", r.templateLogMsg(t.ID,
|
||||
types.ToString(t.Info.Name),
|
||||
t.Info.Authors.ToSlice(),
|
||||
t.Info.SeverityHolder.Severity))
|
||||
}
|
||||
}
|
||||
|
||||
// ListAvailableTemplates prints available templates to stdout
|
||||
// listAvailableTemplates prints available templates to stdout
|
||||
func (r *Runner) listAvailableTemplates() {
|
||||
if r.templatesConfig == nil {
|
||||
return
|
||||
@@ -109,7 +64,7 @@ func (r *Runner) listAvailableTemplates() {
|
||||
|
||||
gologger.Print().Msgf(
|
||||
"\nListing available v.%s nuclei templates for %s",
|
||||
r.templatesConfig.CurrentVersion,
|
||||
r.templatesConfig.TemplateVersion,
|
||||
r.templatesConfig.TemplatesDirectory,
|
||||
)
|
||||
err := directoryWalker(
|
||||
@@ -129,38 +84,12 @@ func (r *Runner) listAvailableTemplates() {
|
||||
}
|
||||
}
|
||||
|
||||
func hasMatchingSeverity(templateSeverity string, allowedSeverities []string) bool {
|
||||
for _, s := range allowedSeverities {
|
||||
finalSeverities := []string{}
|
||||
if strings.Contains(s, ",") {
|
||||
finalSeverities = strings.Split(s, ",")
|
||||
} else {
|
||||
finalSeverities = append(finalSeverities, s)
|
||||
}
|
||||
|
||||
for _, sev := range finalSeverities {
|
||||
sev = strings.ToLower(sev)
|
||||
if sev != "" && strings.HasPrefix(templateSeverity, sev) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func directoryWalker(fsPath string, callback func(fsPath string, d *godirwalk.Dirent) error) error {
|
||||
err := godirwalk.Walk(fsPath, &godirwalk.Options{
|
||||
return godirwalk.Walk(fsPath, &godirwalk.Options{
|
||||
Callback: callback,
|
||||
ErrorCallback: func(fsPath string, err error) godirwalk.ErrorAction {
|
||||
return godirwalk.SkipNode
|
||||
},
|
||||
Unsorted: true,
|
||||
})
|
||||
|
||||
// directory couldn't be walked
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package runner
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_appendAtSignToAuthors(t *testing.T) {
|
||||
result := appendAtSignToAuthors([]string{"user1", "user2", "user3"})
|
||||
assert.Equal(t, result, "@user1,@user2,@user3")
|
||||
}
|
||||
|
||||
func Test_appendAtSignToMissingAuthors(t *testing.T) {
|
||||
result := appendAtSignToAuthors([]string{})
|
||||
assert.Equal(t, result, "@none")
|
||||
|
||||
result = appendAtSignToAuthors(nil)
|
||||
assert.Equal(t, result, "@none")
|
||||
}
|
||||
|
||||
func Test_appendAtSignToOneAuthor(t *testing.T) {
|
||||
result := appendAtSignToAuthors([]string{"user1"})
|
||||
assert.Equal(t, result, "@user1")
|
||||
}
|
||||
+355
-243
@@ -12,231 +12,239 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/blang/semver"
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/google/go-github/github"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/projectdiscovery/folderutil"
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei-updatecheck-api/client"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
|
||||
"github.com/tj/go-update"
|
||||
"github.com/tj/go-update/progress"
|
||||
githubUpdateStore "github.com/tj/go-update/stores/github"
|
||||
)
|
||||
|
||||
const (
|
||||
userName = "projectdiscovery"
|
||||
repoName = "nuclei-templates"
|
||||
userName = "projectdiscovery"
|
||||
repoName = "nuclei-templates"
|
||||
nucleiIgnoreFile = ".nuclei-ignore"
|
||||
nucleiConfigFilename = ".templates-config.json"
|
||||
)
|
||||
|
||||
var reVersion = regexp.MustCompile(`\d+\.\d+\.\d+`)
|
||||
|
||||
// updateTemplates checks if the default list of nuclei-templates
|
||||
// exist in the users home directory, if not the latest revision
|
||||
// is downloaded from github.
|
||||
// exist in the user's home directory, if not the latest revision
|
||||
// is downloaded from GitHub.
|
||||
//
|
||||
// If the path exists but is not latest, the new version is downloaded
|
||||
// from github and replaced with the templates directory.
|
||||
func (r *Runner) updateTemplates() error {
|
||||
// If the path exists but does not contain the latest version of public templates,
|
||||
// the new version is downloaded from GitHub to the templates' directory, overwriting the old content.
|
||||
func (r *Runner) updateTemplates() error { // TODO this method does more than just update templates. Should be refactored.
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configDir := path.Join(home, "/.config", "/nuclei")
|
||||
_ = os.MkdirAll(configDir, os.ModePerm)
|
||||
configDir := filepath.Join(home, ".config", "nuclei")
|
||||
_ = os.MkdirAll(configDir, 0755)
|
||||
|
||||
templatesConfigFile := path.Join(home, nucleiConfigFilename)
|
||||
if _, statErr := os.Stat(templatesConfigFile); !os.IsNotExist(statErr) {
|
||||
config, readErr := readConfiguration()
|
||||
if err != nil {
|
||||
return readErr
|
||||
}
|
||||
r.templatesConfig = config
|
||||
if err := r.readInternalConfigurationFile(home, configDir); err != nil {
|
||||
return errors.Wrap(err, "could not read configuration file")
|
||||
}
|
||||
|
||||
ignoreURL := "https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/master/.nuclei-ignore"
|
||||
// If the config doesn't exist, create it now.
|
||||
if r.templatesConfig == nil {
|
||||
currentConfig := &nucleiConfig{
|
||||
TemplatesDirectory: path.Join(home, "nuclei-templates"),
|
||||
IgnoreURL: ignoreURL,
|
||||
NucleiVersion: Version,
|
||||
currentConfig := &config.Config{
|
||||
TemplatesDirectory: filepath.Join(home, "nuclei-templates"),
|
||||
NucleiVersion: config.Version,
|
||||
}
|
||||
if writeErr := r.writeConfiguration(currentConfig); writeErr != nil {
|
||||
if writeErr := config.WriteConfiguration(currentConfig); writeErr != nil {
|
||||
return errors.Wrap(writeErr, "could not write template configuration")
|
||||
}
|
||||
r.templatesConfig = currentConfig
|
||||
}
|
||||
// Check if last checked for nuclei-ignore is more than 1 hours.
|
||||
// and if true, run the check.
|
||||
if r.templatesConfig == nil || time.Since(r.templatesConfig.LastCheckedIgnore) > 1*time.Hour || r.options.UpdateTemplates {
|
||||
if r.templatesConfig != nil && r.templatesConfig.IgnoreURL != "" {
|
||||
ignoreURL = r.templatesConfig.IgnoreURL
|
||||
}
|
||||
gologger.Verbose().Msgf("Downloading config file from %s", ignoreURL)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
req, reqErr := http.NewRequestWithContext(ctx, http.MethodGet, ignoreURL, nil)
|
||||
if reqErr == nil {
|
||||
resp, httpGet := http.DefaultClient.Do(req)
|
||||
if httpGet != nil {
|
||||
if resp != nil && resp.Body != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
gologger.Warning().Msgf("Could not get ignore-file from %s: %s", ignoreURL, err)
|
||||
} else {
|
||||
data, _ := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
|
||||
if len(data) > 0 {
|
||||
_ = ioutil.WriteFile(path.Join(configDir, nucleiIgnoreFile), data, 0644)
|
||||
}
|
||||
if r.templatesConfig != nil {
|
||||
r.templatesConfig.LastCheckedIgnore = time.Now()
|
||||
}
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
if r.options.NoUpdateTemplates && !r.options.UpdateTemplates {
|
||||
return nil
|
||||
}
|
||||
|
||||
client.InitNucleiVersion(config.Version)
|
||||
r.fetchLatestVersionsFromGithub(configDir) // also fetch the latest versions
|
||||
|
||||
ctx := context.Background()
|
||||
if r.templatesConfig.CurrentVersion == "" || (r.options.TemplatesDirectory != "" && r.templatesConfig.TemplatesDirectory != r.options.TemplatesDirectory) {
|
||||
if !r.options.UpdateTemplates {
|
||||
gologger.Warning().Msgf("nuclei-templates are not installed (or indexed), use update-templates flag.\n")
|
||||
return nil
|
||||
|
||||
var noTemplatesFound bool
|
||||
if _, err := os.Stat(r.templatesConfig.TemplatesDirectory); os.IsNotExist(err) {
|
||||
noTemplatesFound = true
|
||||
}
|
||||
|
||||
if r.templatesConfig.TemplateVersion == "" || (r.options.TemplatesDirectory != "" && r.templatesConfig.TemplatesDirectory != r.options.TemplatesDirectory) || noTemplatesFound {
|
||||
gologger.Info().Msgf("nuclei-templates are not installed, installing...\n")
|
||||
|
||||
// Use the custom location if the user has given a template directory
|
||||
r.templatesConfig = &config.Config{
|
||||
TemplatesDirectory: filepath.Join(home, "nuclei-templates"),
|
||||
}
|
||||
if r.options.TemplatesDirectory != "" && r.options.TemplatesDirectory != filepath.Join(home, "nuclei-templates") {
|
||||
r.templatesConfig.TemplatesDirectory, _ = filepath.Abs(r.options.TemplatesDirectory)
|
||||
}
|
||||
r.fetchLatestVersionsFromGithub(configDir) // also fetch the latest versions
|
||||
|
||||
version, err := semver.Parse(r.templatesConfig.NucleiTemplatesLatestVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use custom location if user has given a template directory
|
||||
r.templatesConfig = &nucleiConfig{
|
||||
TemplatesDirectory: path.Join(home, "nuclei-templates"),
|
||||
}
|
||||
if r.options.TemplatesDirectory != "" && r.options.TemplatesDirectory != path.Join(home, "nuclei-templates") {
|
||||
r.templatesConfig.TemplatesDirectory = r.options.TemplatesDirectory
|
||||
}
|
||||
|
||||
// Download the repository and also write the revision to a HEAD file.
|
||||
version, asset, getErr := r.getLatestReleaseFromGithub()
|
||||
// Download the repository and write the revision to a HEAD file.
|
||||
asset, getErr := r.getLatestReleaseFromGithub(r.templatesConfig.NucleiTemplatesLatestVersion)
|
||||
if getErr != nil {
|
||||
return getErr
|
||||
}
|
||||
gologger.Verbose().Msgf("Downloading nuclei-templates (v%s) to %s\n", version.String(), r.templatesConfig.TemplatesDirectory)
|
||||
|
||||
_, err = r.downloadReleaseAndUnzip(ctx, version.String(), asset.GetZipballURL())
|
||||
if err != nil {
|
||||
if _, err := r.downloadReleaseAndUnzip(ctx, version.String(), asset.GetZipballURL()); err != nil {
|
||||
return err
|
||||
}
|
||||
r.templatesConfig.CurrentVersion = version.String()
|
||||
r.templatesConfig.TemplateVersion = version.String()
|
||||
|
||||
err = r.writeConfiguration(r.templatesConfig)
|
||||
if err != nil {
|
||||
if err := config.WriteConfiguration(r.templatesConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
gologger.Info().Msgf("Successfully downloaded nuclei-templates (v%s). Enjoy!\n", version.String())
|
||||
gologger.Info().Msgf("Successfully downloaded nuclei-templates (v%s) to %s. GoodLuck!\n", version.String(), r.templatesConfig.TemplatesDirectory)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if last checked is more than 24 hours.
|
||||
// If not, return since we don't want to do anything now.
|
||||
if time.Since(r.templatesConfig.LastChecked) < 24*time.Hour && !r.options.UpdateTemplates {
|
||||
return nil
|
||||
latestVersion, currentVersion, err := getVersions(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if latestVersion.EQ(currentVersion) {
|
||||
if r.options.UpdateTemplates {
|
||||
gologger.Info().Msgf("No new updates found for nuclei templates")
|
||||
}
|
||||
return config.WriteConfiguration(r.templatesConfig)
|
||||
}
|
||||
|
||||
if err := r.updateTemplatesWithVersion(latestVersion, currentVersion, r, ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) updateTemplatesWithVersion(latestVersion semver.Version, currentVersion semver.Version, runner *Runner, ctx context.Context) error {
|
||||
if latestVersion.GT(currentVersion) {
|
||||
gologger.Info().Msgf("Your current nuclei-templates v%s are outdated. Latest is v%s\n", currentVersion, latestVersion.String())
|
||||
gologger.Info().Msgf("Downloading latest release...")
|
||||
|
||||
if runner.options.TemplatesDirectory != "" {
|
||||
runner.templatesConfig.TemplatesDirectory = runner.options.TemplatesDirectory
|
||||
}
|
||||
runner.templatesConfig.TemplateVersion = latestVersion.String()
|
||||
|
||||
gologger.Verbose().Msgf("Downloading nuclei-templates (v%s) to %s\n", latestVersion.String(), runner.templatesConfig.TemplatesDirectory)
|
||||
|
||||
asset, err := runner.getLatestReleaseFromGithub(runner.templatesConfig.NucleiTemplatesLatestVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := runner.downloadReleaseAndUnzip(ctx, latestVersion.String(), asset.GetZipballURL()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := config.WriteConfiguration(runner.templatesConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
gologger.Info().Msgf("Successfully updated nuclei-templates (v%s) to %s. GoodLuck!\n", latestVersion.String(), r.templatesConfig.TemplatesDirectory)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getVersions(runner *Runner) (semver.Version, semver.Version, error) {
|
||||
// Get the configuration currently on disk.
|
||||
verText := r.templatesConfig.CurrentVersion
|
||||
verText := runner.templatesConfig.TemplateVersion
|
||||
indices := reVersion.FindStringIndex(verText)
|
||||
if indices == nil {
|
||||
return fmt.Errorf("invalid release found with tag %s", err)
|
||||
return semver.Version{}, semver.Version{}, fmt.Errorf("invalid release found with tag %s", verText)
|
||||
}
|
||||
if indices[0] > 0 {
|
||||
verText = verText[indices[0]:]
|
||||
}
|
||||
|
||||
oldVersion, err := semver.Make(verText)
|
||||
currentVersion, err := semver.Make(verText)
|
||||
if err != nil {
|
||||
return err
|
||||
return semver.Version{}, semver.Version{}, err
|
||||
}
|
||||
|
||||
version, asset, err := r.getLatestReleaseFromGithub()
|
||||
latestVersion, err := semver.Parse(runner.templatesConfig.NucleiTemplatesLatestVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
return semver.Version{}, semver.Version{}, err
|
||||
}
|
||||
return latestVersion, currentVersion, nil
|
||||
}
|
||||
|
||||
if version.EQ(oldVersion) {
|
||||
gologger.Info().Msgf("Your nuclei-templates are up to date: v%s\n", oldVersion.String())
|
||||
return r.writeConfiguration(r.templatesConfig)
|
||||
}
|
||||
|
||||
if version.GT(oldVersion) {
|
||||
if !r.options.UpdateTemplates {
|
||||
gologger.Warning().Msgf("Your current nuclei-templates v%s are outdated. Latest is v%s\n", oldVersion, version.String())
|
||||
return r.writeConfiguration(r.templatesConfig)
|
||||
// readInternalConfigurationFile reads the internal configuration file for nuclei
|
||||
func (r *Runner) readInternalConfigurationFile(home, configDir string) error {
|
||||
templatesConfigFile := filepath.Join(configDir, nucleiConfigFilename)
|
||||
if _, statErr := os.Stat(templatesConfigFile); !os.IsNotExist(statErr) {
|
||||
configuration, readErr := config.ReadConfiguration()
|
||||
if readErr != nil {
|
||||
return readErr
|
||||
}
|
||||
|
||||
if r.options.TemplatesDirectory != "" {
|
||||
r.templatesConfig.TemplatesDirectory = r.options.TemplatesDirectory
|
||||
}
|
||||
r.templatesConfig.CurrentVersion = version.String()
|
||||
|
||||
gologger.Verbose().Msgf("Downloading nuclei-templates (v%s) to %s\n", version.String(), r.templatesConfig.TemplatesDirectory)
|
||||
_, err = r.downloadReleaseAndUnzip(ctx, version.String(), asset.GetZipballURL())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = r.writeConfiguration(r.templatesConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gologger.Info().Msgf("Successfully updated nuclei-templates (v%s). Enjoy!\n", version.String())
|
||||
r.templatesConfig = configuration
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getLatestReleaseFromGithub returns the latest release from github
|
||||
func (r *Runner) getLatestReleaseFromGithub() (semver.Version, *github.RepositoryRelease, error) {
|
||||
client := github.NewClient(nil)
|
||||
|
||||
rels, _, err := client.Repositories.ListReleases(context.Background(), userName, repoName, nil)
|
||||
// checkNucleiIgnoreFileUpdates checks .nuclei-ignore file for updates from GitHub
|
||||
func (r *Runner) checkNucleiIgnoreFileUpdates(configDir string) bool {
|
||||
data, err := client.GetLatestIgnoreFile()
|
||||
if err != nil {
|
||||
return semver.Version{}, nil, err
|
||||
return false
|
||||
}
|
||||
|
||||
// Find the most recent version based on semantic versioning.
|
||||
var latestRelease semver.Version
|
||||
var latestPublish *github.RepositoryRelease
|
||||
for _, release := range rels {
|
||||
verText := release.GetTagName()
|
||||
indices := reVersion.FindStringIndex(verText)
|
||||
if indices == nil {
|
||||
return semver.Version{}, nil, fmt.Errorf("invalid release found with tag %s", err)
|
||||
}
|
||||
if indices[0] > 0 {
|
||||
verText = verText[indices[0]:]
|
||||
}
|
||||
|
||||
ver, err := semver.Make(verText)
|
||||
if err != nil {
|
||||
return semver.Version{}, nil, err
|
||||
}
|
||||
|
||||
if latestPublish == nil || ver.GTE(latestRelease) {
|
||||
latestRelease = ver
|
||||
latestPublish = release
|
||||
if len(data) > 0 {
|
||||
_ = ioutil.WriteFile(filepath.Join(configDir, nucleiIgnoreFile), data, 0644)
|
||||
}
|
||||
if r.templatesConfig != nil {
|
||||
if err := config.WriteConfiguration(r.templatesConfig); err != nil {
|
||||
gologger.Warning().Msgf("Could not get ignore-file from server: %s", err)
|
||||
}
|
||||
}
|
||||
if latestPublish == nil {
|
||||
return semver.Version{}, nil, errors.New("no version found for the templates")
|
||||
return true
|
||||
}
|
||||
|
||||
// getLatestReleaseFromGithub returns the latest release from GitHub
|
||||
func (r *Runner) getLatestReleaseFromGithub(latestTag string) (*github.RepositoryRelease, error) {
|
||||
gitHubClient := github.NewClient(nil)
|
||||
|
||||
release, _, err := gitHubClient.Repositories.GetReleaseByTag(context.Background(), userName, repoName, "v"+latestTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return latestRelease, latestPublish, nil
|
||||
if release == nil {
|
||||
return nil, errors.New("no version found for the templates")
|
||||
}
|
||||
return release, nil
|
||||
}
|
||||
|
||||
// downloadReleaseAndUnzip downloads and unzips the release in a directory
|
||||
func (r *Runner) downloadReleaseAndUnzip(ctx context.Context, version, downloadURL string) (*templateUpdateResults, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create HTTP request to %s: %s", downloadURL, err)
|
||||
return nil, fmt.Errorf("failed to create HTTP request to %s: %w", downloadURL, err)
|
||||
}
|
||||
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to download a release file from %s: %s", downloadURL, err)
|
||||
return nil, fmt.Errorf("failed to download a release file from %s: %w", downloadURL, err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
@@ -245,44 +253,33 @@ func (r *Runner) downloadReleaseAndUnzip(ctx context.Context, version, downloadU
|
||||
|
||||
buf, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create buffer for zip file: %s", err)
|
||||
return nil, fmt.Errorf("failed to create buffer for zip file: %w", err)
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(buf)
|
||||
z, err := zip.NewReader(reader, reader.Size())
|
||||
zipReader, err := zip.NewReader(reader, reader.Size())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to uncompress zip file: %s", err)
|
||||
return nil, fmt.Errorf("failed to uncompress zip file: %w", err)
|
||||
}
|
||||
|
||||
// Create the template folder if it doesn't exists
|
||||
err = os.MkdirAll(r.templatesConfig.TemplatesDirectory, os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create template base folder: %s", err)
|
||||
// Create the template folder if it doesn't exist
|
||||
if err := os.MkdirAll(r.templatesConfig.TemplatesDirectory, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create template base folder: %w", err)
|
||||
}
|
||||
|
||||
results, err := r.compareAndWriteTemplates(z)
|
||||
results, err := r.compareAndWriteTemplates(zipReader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to write templates: %s", err)
|
||||
return nil, fmt.Errorf("failed to write templates: %w", err)
|
||||
}
|
||||
|
||||
r.printUpdateChangelog(results, version)
|
||||
checksumFile := path.Join(r.templatesConfig.TemplatesDirectory, ".checksum")
|
||||
err = writeTemplatesChecksum(checksumFile, results.checksums)
|
||||
if err != nil {
|
||||
if r.options.Verbose {
|
||||
r.printUpdateChangelog(results, version)
|
||||
}
|
||||
checksumFile := filepath.Join(r.templatesConfig.TemplatesDirectory, ".checksum")
|
||||
if err := writeTemplatesChecksum(checksumFile, results.checksums); err != nil {
|
||||
return nil, errors.Wrap(err, "could not write checksum")
|
||||
}
|
||||
|
||||
// Write the additions to a cached file for new runs.
|
||||
additionsFile := path.Join(r.templatesConfig.TemplatesDirectory, ".new-additions")
|
||||
buffer := &bytes.Buffer{}
|
||||
for _, addition := range results.additions {
|
||||
buffer.WriteString(addition)
|
||||
buffer.WriteString("\n")
|
||||
}
|
||||
err = ioutil.WriteFile(additionsFile, buffer.Bytes(), os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not write new additions file")
|
||||
}
|
||||
return results, err
|
||||
}
|
||||
|
||||
@@ -294,9 +291,8 @@ type templateUpdateResults struct {
|
||||
checksums map[string]string
|
||||
}
|
||||
|
||||
// compareAndWriteTemplates compares and returns the stats of a template
|
||||
// update operations.
|
||||
func (r *Runner) compareAndWriteTemplates(z *zip.Reader) (*templateUpdateResults, error) {
|
||||
// compareAndWriteTemplates compares and returns the stats of a template update operations.
|
||||
func (r *Runner) compareAndWriteTemplates(zipReader *zip.Reader) (*templateUpdateResults, error) {
|
||||
results := &templateUpdateResults{
|
||||
checksums: make(map[string]string),
|
||||
}
|
||||
@@ -306,115 +302,157 @@ func (r *Runner) compareAndWriteTemplates(z *zip.Reader) (*templateUpdateResults
|
||||
// If the path isn't found in new update after being read from the previous checksum,
|
||||
// it is removed. This allows us fine-grained control over the download process
|
||||
// as well as solves a long problem with nuclei-template updates.
|
||||
checksumFile := path.Join(r.templatesConfig.TemplatesDirectory, ".checksum")
|
||||
previousChecksum, _ := readPreviousTemplatesChecksum(checksumFile)
|
||||
for _, file := range z.File {
|
||||
directory, name := filepath.Split(file.Name)
|
||||
if name == "" {
|
||||
configuredTemplateDirectory := r.templatesConfig.TemplatesDirectory
|
||||
checksumFile := filepath.Join(configuredTemplateDirectory, ".checksum")
|
||||
templateChecksumsMap, _ := createTemplateChecksumsMap(checksumFile)
|
||||
for _, zipTemplateFile := range zipReader.File {
|
||||
templateAbsolutePath, skipFile, err := calculateTemplateAbsolutePath(zipTemplateFile.Name, configuredTemplateDirectory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if skipFile {
|
||||
continue
|
||||
}
|
||||
paths := strings.Split(directory, "/")
|
||||
finalPath := strings.Join(paths[1:], "/")
|
||||
|
||||
if (!strings.EqualFold(name, ".nuclei-ignore") && strings.HasPrefix(name, ".")) || strings.HasPrefix(finalPath, ".") || strings.EqualFold(name, "README.md") {
|
||||
continue
|
||||
newTemplateChecksum, err := writeUnZippedTemplateFile(templateAbsolutePath, zipTemplateFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldTemplateChecksum, checksumOk := templateChecksumsMap[templateAbsolutePath]
|
||||
|
||||
relativeTemplatePath, err := filepath.Rel(configuredTemplateDirectory, templateAbsolutePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not calculate relative path for template: %s. %w", templateAbsolutePath, err)
|
||||
}
|
||||
|
||||
if checksumOk && oldTemplateChecksum[0] != newTemplateChecksum {
|
||||
results.modifications = append(results.modifications, relativeTemplatePath)
|
||||
}
|
||||
results.checksums[templateAbsolutePath] = newTemplateChecksum
|
||||
results.totalCount++
|
||||
templateDirectory := path.Join(r.templatesConfig.TemplatesDirectory, finalPath)
|
||||
err := os.MkdirAll(templateDirectory, os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create template folder %s : %s", templateDirectory, err)
|
||||
}
|
||||
|
||||
templatePath := path.Join(templateDirectory, name)
|
||||
|
||||
isAddition := false
|
||||
if _, statErr := os.Stat(templatePath); os.IsNotExist(statErr) {
|
||||
isAddition = true
|
||||
}
|
||||
f, err := os.OpenFile(templatePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0777)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("could not create uncompressed file: %s", err)
|
||||
}
|
||||
|
||||
reader, err := file.Open()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("could not open archive to extract file: %s", err)
|
||||
}
|
||||
hasher := md5.New()
|
||||
|
||||
// Save file and also read into hasher for md5
|
||||
_, err = io.Copy(f, io.TeeReader(reader, hasher))
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("could not write template file: %s", err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
oldChecksum, checksumOK := previousChecksum[templatePath]
|
||||
|
||||
checksum := hex.EncodeToString(hasher.Sum(nil))
|
||||
if isAddition {
|
||||
results.additions = append(results.additions, path.Join(finalPath, name))
|
||||
} else if checksumOK && oldChecksum[0] != checksum {
|
||||
results.modifications = append(results.modifications, path.Join(finalPath, name))
|
||||
}
|
||||
results.checksums[templatePath] = checksum
|
||||
}
|
||||
|
||||
// If we don't find a previous file in new download and it hasn't been
|
||||
// changed on the disk, delete it.
|
||||
for k, v := range previousChecksum {
|
||||
_, ok := results.checksums[k]
|
||||
if !ok && v[0] == v[1] {
|
||||
os.Remove(k)
|
||||
results.deletions = append(results.deletions, strings.TrimPrefix(strings.TrimPrefix(k, r.templatesConfig.TemplatesDirectory), "/"))
|
||||
var err error
|
||||
results.additions, err = r.readNewTemplatesFile()
|
||||
if err != nil {
|
||||
results.additions = []string{}
|
||||
}
|
||||
|
||||
// If we don't find the previous file in the newly downloaded list,
|
||||
// and it hasn't been changed on the disk, delete it.
|
||||
for templatePath, templateChecksums := range templateChecksumsMap {
|
||||
_, ok := results.checksums[templatePath]
|
||||
if !ok && templateChecksums[0] == templateChecksums[1] {
|
||||
_ = os.Remove(templatePath)
|
||||
results.deletions = append(results.deletions, strings.TrimPrefix(strings.TrimPrefix(templatePath, configuredTemplateDirectory), string(os.PathSeparator)))
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// readPreviousTemplatesChecksum reads the previous checksum file from the disk.
|
||||
//
|
||||
// It reads two checksums, the first checksum is what we expect and the second is
|
||||
// the actual checksum of the file on disk currently.
|
||||
func readPreviousTemplatesChecksum(file string) (map[string][2]string, error) {
|
||||
f, err := os.Open(file)
|
||||
func writeUnZippedTemplateFile(templateAbsolutePath string, zipTemplateFile *zip.File) (string, error) {
|
||||
templateFile, err := os.OpenFile(templateAbsolutePath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not create template file: %w", err)
|
||||
}
|
||||
|
||||
zipTemplateFileReader, err := zipTemplateFile.Open()
|
||||
if err != nil {
|
||||
_ = templateFile.Close()
|
||||
return "", fmt.Errorf("could not open archive to extract file: %w", err)
|
||||
}
|
||||
|
||||
md5Hash := md5.New()
|
||||
|
||||
// Save file and also read into hash.Hash for md5
|
||||
if _, err := io.Copy(templateFile, io.TeeReader(zipTemplateFileReader, md5Hash)); err != nil {
|
||||
_ = templateFile.Close()
|
||||
return "", fmt.Errorf("could not write template file: %w", err)
|
||||
}
|
||||
|
||||
if err := templateFile.Close(); err != nil {
|
||||
return "", fmt.Errorf("could not close file newly created template file: %w", err)
|
||||
}
|
||||
|
||||
checksum := hex.EncodeToString(md5Hash.Sum(nil))
|
||||
return checksum, nil
|
||||
}
|
||||
|
||||
func calculateTemplateAbsolutePath(zipFilePath, configuredTemplateDirectory string) (string, bool, error) {
|
||||
directory, fileName := filepath.Split(zipFilePath)
|
||||
|
||||
if !strings.EqualFold(fileName, ".new-additions") {
|
||||
if strings.TrimSpace(fileName) == "" || strings.HasPrefix(fileName, ".") || strings.EqualFold(fileName, "README.md") {
|
||||
return "", true, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
directoryPathChunks []string
|
||||
relativeDirectoryPathWithoutZipRoot string
|
||||
)
|
||||
if folderutil.IsUnixOS() {
|
||||
directoryPathChunks = strings.Split(directory, string(os.PathSeparator))
|
||||
} else if folderutil.IsWindowsOS() {
|
||||
pathInfo, _ := folderutil.NewPathInfo(directory)
|
||||
directoryPathChunks = pathInfo.Parts
|
||||
}
|
||||
relativeDirectoryPathWithoutZipRoot = filepath.Join(directoryPathChunks[1:]...)
|
||||
|
||||
if strings.HasPrefix(relativeDirectoryPathWithoutZipRoot, ".") {
|
||||
return "", true, nil
|
||||
}
|
||||
|
||||
templateDirectory := filepath.Join(configuredTemplateDirectory, relativeDirectoryPathWithoutZipRoot)
|
||||
|
||||
if err := os.MkdirAll(templateDirectory, 0755); err != nil {
|
||||
return "", false, fmt.Errorf("failed to create template folder: %s. %w", templateDirectory, err)
|
||||
}
|
||||
|
||||
return filepath.Join(templateDirectory, fileName), false, nil
|
||||
}
|
||||
|
||||
// createTemplateChecksumsMap reads the previous checksum file from the disk.
|
||||
// Creates a map of template paths and their previous and currently calculated checksums as values.
|
||||
func createTemplateChecksumsMap(checksumsFilePath string) (map[string][2]string, error) {
|
||||
checksumFile, err := os.Open(checksumsFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
scanner := bufio.NewScanner(f)
|
||||
defer checksumFile.Close()
|
||||
scanner := bufio.NewScanner(checksumFile)
|
||||
|
||||
checksum := make(map[string][2]string)
|
||||
templatePathChecksumsMap := make(map[string][2]string)
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Split(text, ",")
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
values := [2]string{parts[1]}
|
||||
templatePath := parts[0]
|
||||
expectedTemplateChecksum := parts[1]
|
||||
|
||||
f, err := os.Open(parts[0])
|
||||
templateFile, err := os.Open(templatePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasher := md5.New()
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
if _, err := io.Copy(hasher, templateFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Close()
|
||||
templateFile.Close()
|
||||
|
||||
values := [2]string{expectedTemplateChecksum}
|
||||
values[1] = hex.EncodeToString(hasher.Sum(nil))
|
||||
checksum[parts[0]] = values
|
||||
templatePathChecksumsMap[templatePath] = values
|
||||
}
|
||||
return checksum, nil
|
||||
return templatePathChecksumsMap, nil
|
||||
}
|
||||
|
||||
// writeTemplatesChecksum writes the nuclei-templates checksum data to disk.
|
||||
@@ -441,7 +479,7 @@ func writeTemplatesChecksum(file string, checksum map[string]string) error {
|
||||
}
|
||||
|
||||
func (r *Runner) printUpdateChangelog(results *templateUpdateResults, version string) {
|
||||
if len(results.additions) > 0 {
|
||||
if len(results.additions) > 0 && r.options.Verbose {
|
||||
gologger.Print().Msgf("\nNewly added templates: \n\n")
|
||||
|
||||
for _, addition := range results.additions {
|
||||
@@ -460,3 +498,77 @@ func (r *Runner) printUpdateChangelog(results *templateUpdateResults, version st
|
||||
}
|
||||
table.Render()
|
||||
}
|
||||
|
||||
// fetchLatestVersionsFromGithub fetches the latest versions of nuclei repos from GitHub
|
||||
//
|
||||
// This fetches the latest nuclei/templates/ignore from https://version-check.nuclei.sh/versions
|
||||
// If you want to disable this automatic update check, use -nut flag.
|
||||
func (r *Runner) fetchLatestVersionsFromGithub(configDir string) {
|
||||
versions, err := client.GetLatestNucleiTemplatesVersion()
|
||||
if err != nil {
|
||||
gologger.Warning().Msgf("Could not fetch latest releases: %s", err)
|
||||
return
|
||||
}
|
||||
if r.templatesConfig != nil {
|
||||
r.templatesConfig.NucleiLatestVersion = versions.Nuclei
|
||||
r.templatesConfig.NucleiTemplatesLatestVersion = versions.Templates
|
||||
|
||||
// If the fetch has resulted in new version of ignore file, update.
|
||||
if r.templatesConfig.NucleiIgnoreHash == "" || r.templatesConfig.NucleiIgnoreHash != versions.IgnoreHash {
|
||||
r.templatesConfig.NucleiIgnoreHash = versions.IgnoreHash
|
||||
r.checkNucleiIgnoreFileUpdates(configDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// updateNucleiVersionToLatest implements nuclei auto-update using GitHub Releases.
|
||||
func updateNucleiVersionToLatest(verbose bool) error {
|
||||
if verbose {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
var command string
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
command = "nuclei.exe"
|
||||
default:
|
||||
command = "nuclei"
|
||||
}
|
||||
m := &update.Manager{
|
||||
Command: command,
|
||||
Store: &githubUpdateStore.Store{
|
||||
Owner: "projectdiscovery",
|
||||
Repo: "nuclei",
|
||||
Version: config.Version,
|
||||
},
|
||||
}
|
||||
releases, err := m.LatestReleases()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not fetch latest release")
|
||||
}
|
||||
if len(releases) == 0 {
|
||||
gologger.Info().Msgf("No new updates found for nuclei engine!")
|
||||
return nil
|
||||
}
|
||||
|
||||
latest := releases[0]
|
||||
var currentOS string
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
currentOS = "macOS"
|
||||
default:
|
||||
currentOS = runtime.GOOS
|
||||
}
|
||||
final := latest.FindZip(currentOS, runtime.GOARCH)
|
||||
if final == nil {
|
||||
return fmt.Errorf("no compatible binary found for %s/%s", currentOS, runtime.GOARCH)
|
||||
}
|
||||
tarball, err := final.DownloadProxy(progress.Reader)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not download latest release")
|
||||
}
|
||||
if err := m.Install(tarball); err != nil {
|
||||
return errors.Wrap(err, "could not install latest release")
|
||||
}
|
||||
gologger.Info().Msgf("Successfully updated to Nuclei %s\n", latest.Version)
|
||||
return nil
|
||||
}
|
||||
@@ -8,25 +8,63 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v2/internal/testutils"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/projectdiscovery/gologger"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
|
||||
"github.com/projectdiscovery/nuclei/v2/pkg/testutils"
|
||||
)
|
||||
|
||||
func TestDownloadReleaseAndUnzipAddition(t *testing.T) {
|
||||
gologger.DefaultLogger.SetWriter(&testutils.NoopWriter{})
|
||||
|
||||
templatesDirectory, err := ioutil.TempDir("", "template-*")
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(templatesDirectory)
|
||||
|
||||
r := &Runner{templatesConfig: &config.Config{TemplatesDirectory: templatesDirectory}, options: testutils.DefaultOptions}
|
||||
|
||||
newTempDir, err := ioutil.TempDir("", "new-tmp-*")
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(newTempDir)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(newTempDir, "base.yaml"), []byte("id: test"), os.ModePerm)
|
||||
require.Nil(t, err, "could not create base file")
|
||||
err = ioutil.WriteFile(filepath.Join(newTempDir, "new.yaml"), []byte("id: test"), os.ModePerm)
|
||||
require.Nil(t, err, "could not create new file")
|
||||
err = ioutil.WriteFile(filepath.Join(newTempDir, ".new-additions"), []byte("new.yaml"), os.ModePerm)
|
||||
require.Nil(t, err, "could not create new file")
|
||||
|
||||
err = zipFromDirectory("new.zip", newTempDir)
|
||||
require.Nil(t, err, "could not create new zip from directory")
|
||||
defer os.Remove("new.zip")
|
||||
|
||||
ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "new.zip")
|
||||
}))
|
||||
defer ts2.Close()
|
||||
|
||||
results, err := r.downloadReleaseAndUnzip(context.Background(), "1.0.1", ts2.URL)
|
||||
require.Nil(t, err, "could not download release and unzip")
|
||||
|
||||
require.Equal(t, "new.yaml", results.additions[0], "could not get correct new addition")
|
||||
}
|
||||
|
||||
func TestDownloadReleaseAndUnzipDeletion(t *testing.T) {
|
||||
gologger.DefaultLogger.SetWriter(&testutils.NoopWriter{})
|
||||
|
||||
baseTemplates, err := ioutil.TempDir("", "old-temp-*")
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(baseTemplates)
|
||||
|
||||
err = ioutil.WriteFile(path.Join(baseTemplates, "base.yaml"), []byte("id: test"), 0777)
|
||||
err = ioutil.WriteFile(filepath.Join(baseTemplates, "base.yaml"), []byte("id: test"), os.ModePerm)
|
||||
require.Nil(t, err, "could not create write base file")
|
||||
err = ioutil.WriteFile(filepath.Join(baseTemplates, ".new-additions"), []byte("base.yaml"), os.ModePerm)
|
||||
require.Nil(t, err, "could not create new file")
|
||||
|
||||
err = zipFromDirectory("base.zip", baseTemplates)
|
||||
require.Nil(t, err, "could not create zip from directory")
|
||||
@@ -41,7 +79,7 @@ func TestDownloadReleaseAndUnzipAddition(t *testing.T) {
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(templatesDirectory)
|
||||
|
||||
r := &Runner{templatesConfig: &nucleiConfig{TemplatesDirectory: templatesDirectory}}
|
||||
r := &Runner{templatesConfig: &config.Config{TemplatesDirectory: templatesDirectory}, options: testutils.DefaultOptions}
|
||||
|
||||
results, err := r.downloadReleaseAndUnzip(context.Background(), "1.0.0", ts.URL)
|
||||
require.Nil(t, err, "could not download release and unzip")
|
||||
@@ -51,9 +89,7 @@ func TestDownloadReleaseAndUnzipAddition(t *testing.T) {
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(newTempDir)
|
||||
|
||||
err = ioutil.WriteFile(path.Join(newTempDir, "base.yaml"), []byte("id: test"), 0777)
|
||||
require.Nil(t, err, "could not create base file")
|
||||
err = ioutil.WriteFile(path.Join(newTempDir, "new.yaml"), []byte("id: test"), 0777)
|
||||
err = ioutil.WriteFile(filepath.Join(newTempDir, ".new-additions"), []byte(""), os.ModePerm)
|
||||
require.Nil(t, err, "could not create new file")
|
||||
|
||||
err = zipFromDirectory("new.zip", newTempDir)
|
||||
@@ -68,55 +104,26 @@ func TestDownloadReleaseAndUnzipAddition(t *testing.T) {
|
||||
results, err = r.downloadReleaseAndUnzip(context.Background(), "1.0.1", ts2.URL)
|
||||
require.Nil(t, err, "could not download release and unzip")
|
||||
|
||||
require.Equal(t, "new.yaml", results.additions[0], "could not get correct new addition")
|
||||
require.Equal(t, "base.yaml", results.deletions[0], "could not get correct new deletions")
|
||||
}
|
||||
|
||||
func TestDownloadReleaseAndUnzipDeletion(t *testing.T) {
|
||||
gologger.DefaultLogger.SetWriter(&testutils.NoopWriter{})
|
||||
func TestCalculateTemplateAbsolutePathPositiveScenario(t *testing.T) {
|
||||
configuredTemplateDirectory := filepath.Join(os.TempDir(), "templates")
|
||||
defer os.RemoveAll(configuredTemplateDirectory)
|
||||
|
||||
baseTemplates, err := ioutil.TempDir("", "old-temp-*")
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(baseTemplates)
|
||||
t.Run("positive scenarios", func(t *testing.T) {
|
||||
zipFilePathsExpectedPathsMap := map[string]string{
|
||||
"nuclei-templates/cve/test.yaml": filepath.Join(configuredTemplateDirectory, "cve/test.yaml"),
|
||||
"nuclei-templates/cve/test/test.yaml": filepath.Join(configuredTemplateDirectory, "cve/test/test.yaml"),
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(path.Join(baseTemplates, "base.yaml"), []byte("id: test"), 0777)
|
||||
require.Nil(t, err, "could not create write base file")
|
||||
|
||||
err = zipFromDirectory("base.zip", baseTemplates)
|
||||
require.Nil(t, err, "could not create zip from directory")
|
||||
defer os.Remove("base.zip")
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "base.zip")
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
templatesDirectory, err := ioutil.TempDir("", "template-*")
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(templatesDirectory)
|
||||
|
||||
r := &Runner{templatesConfig: &nucleiConfig{TemplatesDirectory: templatesDirectory}}
|
||||
|
||||
results, err := r.downloadReleaseAndUnzip(context.Background(), "1.0.0", ts.URL)
|
||||
require.Nil(t, err, "could not download release and unzip")
|
||||
require.Equal(t, "base.yaml", results.additions[0], "could not get correct base addition")
|
||||
|
||||
newTempDir, err := ioutil.TempDir("", "new-tmp-*")
|
||||
require.Nil(t, err, "could not create temp directory")
|
||||
defer os.RemoveAll(newTempDir)
|
||||
|
||||
err = zipFromDirectory("new.zip", newTempDir)
|
||||
require.Nil(t, err, "could not create new zip from directory")
|
||||
defer os.Remove("new.zip")
|
||||
|
||||
ts2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "new.zip")
|
||||
}))
|
||||
defer ts2.Close()
|
||||
|
||||
results, err = r.downloadReleaseAndUnzip(context.Background(), "1.0.1", ts2.URL)
|
||||
require.Nil(t, err, "could not download release and unzip")
|
||||
|
||||
require.Equal(t, "base.yaml", results.deletions[0], "could not get correct new deletions")
|
||||
for filePathFromZip, expectedTemplateAbsPath := range zipFilePathsExpectedPathsMap {
|
||||
calculatedTemplateAbsPath, skipFile, err := calculateTemplateAbsolutePath(filePathFromZip, configuredTemplateDirectory)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, expectedTemplateAbsPath, calculatedTemplateAbsPath)
|
||||
require.False(t, skipFile)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func zipFromDirectory(zipPath, directory string) error {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//go:build !windows
|
||||
|
||||
package runner
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCalculateTemplateAbsolutePathNegativeScenario(t *testing.T) {
|
||||
configuredTemplateDirectory := filepath.Join(os.TempDir(), "templates")
|
||||
defer os.RemoveAll(configuredTemplateDirectory)
|
||||
|
||||
t.Run("negative scenarios", func(t *testing.T) {
|
||||
filePathsFromZip := []string{
|
||||
"./../nuclei-templates/../cve/test.yaml",
|
||||
"nuclei-templates/../cve/test.yaml",
|
||||
"nuclei-templates/cve/../test.yaml",
|
||||
"nuclei-templates/././../cve/test.yaml",
|
||||
"nuclei-templates/.././../cve/test.yaml",
|
||||
"nuclei-templates/.././../cve/../test.yaml",
|
||||
}
|
||||
|
||||
for _, filePathFromZip := range filePathsFromZip {
|
||||
calculatedTemplateAbsPath, skipFile, err := calculateTemplateAbsolutePath(filePathFromZip, configuredTemplateDirectory)
|
||||
require.Nil(t, err)
|
||||
require.True(t, skipFile)
|
||||
require.Equal(t, "", calculatedTemplateAbsPath)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RunNucleiAndGetResults returns a list of results for a template
|
||||
func RunNucleiAndGetResults(template, url string, debug bool, extra ...string) ([]string, error) {
|
||||
cmd := exec.Command("./nuclei", "-t", template, "-target", url)
|
||||
if debug {
|
||||
cmd = exec.Command("./nuclei", "-t", template, "-target", url, "-debug")
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
cmd.Args = append(cmd.Args, extra...)
|
||||
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts := []string{}
|
||||
items := strings.Split(string(data), "\n")
|
||||
for _, i := range items {
|
||||
if i != "" {
|
||||
parts = append(parts, i)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
// RunNucleiWorkflowAndGetResults returns a list of results for a workflow
|
||||
func RunNucleiWorkflowAndGetResults(template, url string, debug bool, extra ...string) ([]string, error) {
|
||||
cmd := exec.Command("./nuclei", "-w", template, "-target", url)
|
||||
if debug {
|
||||
cmd = exec.Command("./nuclei", "-w", template, "-target", url, "-debug")
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
cmd.Args = append(cmd.Args, extra...)
|
||||
|
||||
data, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts := []string{}
|
||||
items := strings.Split(string(data), "\n")
|
||||
for _, i := range items {
|
||||
if i != "" {
|
||||
parts = append(parts, i)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
// TestCase is a single integration test case
|
||||
type TestCase interface {
|
||||
// Execute executes a test case and returns any errors if occurred
|
||||
Execute(filePath string) error
|
||||
}
|
||||
|
||||
// TCPServer creates a new tcp server that returns a response
|
||||
type TCPServer struct {
|
||||
URL string
|
||||
listener net.Listener
|
||||
}
|
||||
|
||||
// NewTCPServer creates a new TCP server from a handler
|
||||
func NewTCPServer(handler func(conn net.Conn)) *TCPServer {
|
||||
server := &TCPServer{}
|
||||
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
server.URL = l.Addr().String()
|
||||
server.listener = l
|
||||
|
||||
go func() {
|
||||
for {
|
||||
// Listen for an incoming connection.
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Handle connections in a new goroutine.
|
||||
go handler(conn)
|
||||
}
|
||||
}()
|
||||
return server
|
||||
}
|
||||
|
||||
// Close closes the TCP server
|
||||
func (s *TCPServer) Close() {
|
||||
s.listener.Close()
|
||||
}
|
||||
Loaded 100 of 302 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user