Skip to content

Commit 8d0d288

Browse files
authored
Merge pull request #5745 from projectdiscovery/dev
Nuclei v3.3.5
2 parents 9c71f6e + 44f398c commit 8d0d288

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1121
-236
lines changed

.github/auto_assign.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
addReviewers: true
22
reviewers:
33
- dogancanbakir
4+
- dwisiswant0
45

56
numberOfReviewers: 1
67
skipKeywords:

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,9 @@ pkg/protocols/common/helpers/deserialization/testdata/ValueObject2.ser
4242
vendor
4343

4444
# Headless `screenshot` action
45-
*.png
45+
*.png
46+
47+
# Profiling & tracing
48+
*.prof
49+
*.pprof
50+
*.trace

DESIGN.md

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -457,26 +457,49 @@ func (template *Template) compileProtocolRequests(options protocols.ExecuterOpti
457457
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.
458458

459459

460-
## Profiling Instructions
460+
## Profiling and Tracing
461461

462-
To enable dumping of Memory profiling data, `-profile-mem` flag can be used along with path to a file. This writes a pprof formatted file which can be used for investigate resource usage with `pprof` tool.
462+
To analyze Nuclei's performance and resource usage, you can generate memory profiles and trace files using the `-profile-mem` flag:
463463

464-
```console
465-
$ nuclei -t nuclei-templates/ -u https://example.com -profile-mem mem.pprof
464+
```bash
465+
nuclei -t nuclei-templates/ -u https://example.com -profile-mem=nuclei-$(git describe --tags)
466466
```
467467

468-
To view profile data in pprof, first install pprof. Then run the below command -
468+
This command creates two files:
469469

470-
```console
471-
$ go tool pprof mem.pprof
470+
* `nuclei.prof`: Memory (heap) profile
471+
* `nuclei.trace`: Execution trace
472+
473+
### Analyzing the Memory Profile
474+
475+
1. View the profile in the terminal:
476+
477+
```bash
478+
go tool pprof nuclei.prof
479+
```
480+
481+
2. Display top memory consumers:
482+
483+
```bash
484+
go tool pprof -top nuclei.prof | grep "$(go list -m)" | head -10
472485
```
473486

474-
To open a web UI on a port to visualize debug data, the below command can be used.
487+
3. Visualize the profile in a web browser:
475488

476-
```console
477-
$ go tool pprof -http=:8081 mem.pprof
489+
```bash
490+
go tool pprof -http=:$(shuf -i 1000-99999 -n 1) nuclei.prof
478491
```
479492

493+
### Analyzing the Trace File
494+
495+
To examine the execution trace:
496+
497+
```bash
498+
go tool trace nuclei.trace
499+
```
500+
501+
These tools help identify performance bottlenecks and memory leaks, allowing for targeted optimizations of Nuclei's codebase.
502+
480503
## Project Structure
481504

482505
- [pkg/reporting](./pkg/reporting) - Reporting modules for nuclei.

README.md

Lines changed: 252 additions & 120 deletions
Large diffs are not rendered by default.

SYNTAX-REFERENCE.md

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,19 @@ FuzzPreConditionOperator is the operator between multiple PreConditions for fuzz
16511651

16521652
<hr />
16531653

1654+
<div class="dd">
1655+
1656+
<code>global-matchers</code> <i>bool</i>
1657+
1658+
</div>
1659+
<div class="dt">
1660+
1661+
GlobalMatchers marks matchers as static and applies globally to all result events from other templates
1662+
1663+
</div>
1664+
1665+
<hr />
1666+
16541667

16551668

16561669

@@ -3210,6 +3223,19 @@ read-all: false
32103223

32113224
<hr />
32123225

3226+
<div class="dd">
3227+
3228+
<code>stop-at-first-match</code> <i>bool</i>
3229+
3230+
</div>
3231+
<div class="dt">
3232+
3233+
StopAtFirstMatch stops the execution of the requests and template as soon as a match is found.
3234+
3235+
</div>
3236+
3237+
<hr />
3238+
32133239

32143240

32153241

@@ -3764,11 +3790,33 @@ Appears in:
37643790
Part Definitions:
37653791

37663792

3793+
- <code>template-id</code> - ID of the template executed
3794+
- <code>template-info</code> - Info Block of the template executed
3795+
- <code>template-path</code> - Path of the template executed
3796+
- <code>host</code> - Host is the input to the template
3797+
- <code>port</code> - Port is the port of the host
3798+
- <code>matched</code> - Matched is the input which was matched upon
37673799
- <code>type</code> - Type is the type of request made
3800+
- <code>timestamp</code> - Timestamp is the time when the request was made
37683801
- <code>response</code> - JSON SSL protocol handshake details
3802+
- <code>cipher</code> - Cipher is the encryption algorithm used
3803+
- <code>domains</code> - Domains are the list of domain names in the certificate
3804+
- <code>fingerprint_hash</code> - Fingerprint hash is the unique identifier of the certificate
3805+
- <code>ip</code> - IP is the IP address of the server
3806+
- <code>issuer_cn</code> - Issuer CN is the common name of the certificate issuer
3807+
- <code>issuer_dn</code> - Issuer DN is the distinguished name of the certificate issuer
3808+
- <code>issuer_org</code> - Issuer organization is the organization of the certificate issuer
37693809
- <code>not_after</code> - Timestamp after which the remote cert expires
3770-
- <code>host</code> - Host is the input to the template
3771-
- <code>matched</code> - Matched is the input which was matched upon
3810+
- <code>not_before</code> - Timestamp before which the certificate is not valid
3811+
- <code>probe_status</code> - Probe status indicates if the probe was successful
3812+
- <code>serial</code> - Serial is the serial number of the certificate
3813+
- <code>sni</code> - SNI is the server name indication used in the handshake
3814+
- <code>subject_an</code> - Subject AN is the list of subject alternative names
3815+
- <code>subject_cn</code> - Subject CN is the common name of the certificate subject
3816+
- <code>subject_dn</code> - Subject DN is the distinguished name of the certificate subject
3817+
- <code>subject_org</code> - Subject organization is the organization of the certificate subject
3818+
- <code>tls_connection</code> - TLS connection is the type of TLS connection used
3819+
- <code>tls_version</code> - TLS version is the version of the TLS protocol used
37723820

37733821
<hr />
37743822

cmd/nuclei/issue-tracker-config.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,14 @@
162162
# duplicate-issue-check: false
163163
# # open-state-id is the ID of the open state in Linear
164164
# open-state-id: ""
165+
#mongodb:
166+
# # the connection string to the MongoDB database
167+
# # (e.g., mongodb://root:example@localhost:27017/nuclei?ssl=false&authSource=admin)
168+
# connection-string: ""
169+
# # the name of the collection to store the issues
170+
# collection-name: ""
171+
# # excludes the Request and Response from the results (helps with filesize)
172+
# omit-raw: false
173+
# # determines the number of results to be kept in memory before writing it to the database or 0 to
174+
# # persist all in memory and write all results at the end (default)
175+
# batch-size: 0

cmd/nuclei/main.go

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"path/filepath"
1010
"runtime"
1111
"runtime/pprof"
12+
"runtime/trace"
1213
"strings"
1314
"time"
1415

@@ -103,21 +104,40 @@ func main() {
103104
return
104105
}
105106

106-
// Profiling related code
107+
// Profiling & tracing related code
107108
if memProfile != "" {
108-
f, err := os.Create(memProfile)
109+
memProfile = strings.TrimSuffix(memProfile, filepath.Ext(memProfile)) + ".prof"
110+
memProfileFile, err := os.Create(memProfile)
109111
if err != nil {
110-
gologger.Fatal().Msgf("profile: could not create memory profile %q: %v", memProfile, err)
112+
gologger.Fatal().Msgf("profile: could not create memory profile %q file: %v", memProfile, err)
111113
}
112-
old := runtime.MemProfileRate
114+
115+
traceFilepath := strings.TrimSuffix(memProfile, filepath.Ext(memProfile)) + ".trace"
116+
traceFile, err := os.Create(traceFilepath)
117+
if err != nil {
118+
gologger.Fatal().Msgf("profile: could not create trace %q file: %v", traceFilepath, err)
119+
}
120+
121+
oldMemProfileRate := runtime.MemProfileRate
113122
runtime.MemProfileRate = 4096
114-
gologger.Print().Msgf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, memProfile)
123+
124+
// Start tracing
125+
if err := trace.Start(traceFile); err != nil {
126+
gologger.Fatal().Msgf("profile: could not start trace: %v", err)
127+
}
115128

116129
defer func() {
117-
_ = pprof.Lookup("heap").WriteTo(f, 0)
118-
f.Close()
119-
runtime.MemProfileRate = old
120-
gologger.Print().Msgf("profile: memory profiling disabled, %s", memProfile)
130+
// Start CPU profiling
131+
if err := pprof.WriteHeapProfile(memProfileFile); err != nil {
132+
gologger.Fatal().Msgf("profile: could not start CPU profile: %v", err)
133+
}
134+
memProfileFile.Close()
135+
traceFile.Close()
136+
trace.Stop()
137+
runtime.MemProfileRate = oldMemProfileRate
138+
139+
gologger.Info().Msgf("Memory profile saved at %q", memProfile)
140+
gologger.Info().Msgf("Traced at %q", traceFilepath)
121141
}()
122142
}
123143

@@ -402,9 +422,10 @@ on extensive configurability, massive extensibility and ease of use.`)
402422
flagSet.CallbackVar(printVersion, "version", "show nuclei version"),
403423
flagSet.BoolVarP(&options.HangMonitor, "hang-monitor", "hm", false, "enable nuclei hang monitoring"),
404424
flagSet.BoolVarP(&options.Verbose, "verbose", "v", false, "show verbose output"),
405-
flagSet.StringVar(&memProfile, "profile-mem", "", "optional nuclei memory profile dump file"),
425+
flagSet.StringVar(&memProfile, "profile-mem", "", "generate memory (heap) profile & trace files"),
406426
flagSet.BoolVar(&options.VerboseVerbose, "vv", false, "display templates loaded for scan"),
407427
flagSet.BoolVarP(&options.ShowVarDump, "show-var-dump", "svd", false, "show variables dump for debugging"),
428+
flagSet.IntVarP(&options.VarDumpLimit, "var-dump-limit", "vdl", 255, "limit the number of characters displayed in var dump"),
408429
flagSet.BoolVarP(&options.EnablePprof, "enable-pprof", "ep", false, "enable pprof debugging server"),
409430
flagSet.CallbackVarP(printTemplateVersion, "templates-version", "tv", "shows the version of the installed nuclei-templates"),
410431
flagSet.BoolVarP(&options.HealthCheck, "health-check", "hc", false, "run diagnostic check up"),

gh_retry.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ WORKFLOW="Build Test"
2121
GREP_ERROR_PATTERN='Test "http/interactsh.yaml" failed'
2222

2323
#Set fonts for Help.
24-
NORM=`tput sgr0`
25-
BOLD=`tput bold`
26-
REV=`tput smso`
24+
NORM=$(tput sgr0)
25+
BOLD=$(tput bold)
26+
REV=$(tput smso)
2727

2828
HELP()
2929
{
@@ -73,7 +73,7 @@ function print_bold() {
7373
function retry_failed_jobs() {
7474
print_bold "Checking failed workflows for branch $BRANCH before $BEFORE"
7575

76-
date=`date +%Y-%m-%d'T'%H:%M'Z' -d "$BEFORE"`
76+
date=$(date +%Y-%m-%d'T'%H:%M'Z' -d "$BEFORE")
7777

7878
workflowIds=$(gh run list --limit "$LIMIT" --json headBranch,status,name,conclusion,databaseId,updatedAt | jq -c '.[] |
7979
select ( .headBranch==$branch ) |

go.mod

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/projectdiscovery/nuclei/v3
22

3-
go 1.21
3+
go 1.21.0
44

55
require (
66
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
@@ -104,7 +104,9 @@ require (
104104
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466
105105
github.com/stretchr/testify v1.9.0
106106
github.com/tarunKoyalwar/goleak v0.0.0-20240429141123-0efa90dbdcf9
107+
github.com/yassinebenaid/godump v0.10.0
107108
github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706
109+
go.mongodb.org/mongo-driver v1.17.0
108110
golang.org/x/term v0.24.0
109111
gopkg.in/yaml.v3 v3.0.1
110112
moul.io/http2curl v1.0.0
@@ -195,6 +197,7 @@ require (
195197
github.com/mitchellh/mapstructure v1.5.0 // indirect
196198
github.com/moby/term v0.5.0 // indirect
197199
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
200+
github.com/montanaflynn/stats v0.7.1 // indirect
198201
github.com/muesli/reflow v0.3.0 // indirect
199202
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
200203
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -228,9 +231,13 @@ require (
228231
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
229232
github.com/ugorji/go/codec v1.2.11 // indirect
230233
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
234+
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
235+
github.com/xdg-go/scram v1.1.2 // indirect
236+
github.com/xdg-go/stringprep v1.0.4 // indirect
231237
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
232238
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
233239
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
240+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
234241
github.com/ysmood/fetchup v0.2.3 // indirect
235242
github.com/ysmood/got v0.34.1 // indirect
236243
github.com/yuin/goldmark v1.7.4 // indirect

go.sum

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
755755
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
756756
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
757757
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
758+
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
759+
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
758760
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
759761
github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
760762
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
@@ -1085,6 +1087,12 @@ github.com/xanzy/go-gitlab v0.107.0 h1:P2CT9Uy9yN9lJo3FLxpMZ4xj6uWcpnigXsjvqJ6nd
10851087
github.com/xanzy/go-gitlab v0.107.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY=
10861088
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
10871089
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
1090+
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
1091+
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
1092+
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
1093+
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
1094+
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
1095+
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
10881096
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
10891097
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
10901098
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1096,8 +1104,12 @@ github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1
10961104
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
10971105
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
10981106
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
1107+
github.com/yassinebenaid/godump v0.10.0 h1:FolBA+Ix5uwUiXYBBYOsf1VkT5+0f4gtFNTkYTiIR08=
1108+
github.com/yassinebenaid/godump v0.10.0/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44=
10991109
github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
11001110
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
1111+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
1112+
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
11011113
github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=
11021114
github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=
11031115
github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
@@ -1150,6 +1162,8 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
11501162
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
11511163
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
11521164
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
1165+
go.mongodb.org/mongo-driver v1.17.0 h1:Hp4q2MCjvY19ViwimTs00wHi7G4yzxh4/2+nTx8r40k=
1166+
go.mongodb.org/mongo-driver v1.17.0/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
11531167
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
11541168
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
11551169
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=

0 commit comments

Comments
 (0)