Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added initial live DAST server implementation #5772

Merged
merged 38 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0db2332
feat: added initial live DAST server implementation
Ice3man543 Oct 26, 2024
64ef60e
feat: more logging + misc additions
Ice3man543 Oct 30, 2024
efd8ab9
feat: auth file support enhancements for more complex scenarios + misc
Ice3man543 Nov 7, 2024
0da731c
Merge remote-tracking branch 'origin' into nuclei-dast-server
ehsandeep Nov 19, 2024
ae870e6
feat: added io.Reader support to input providers for http
Ice3man543 Nov 20, 2024
50d0952
feat: added stats db to fuzzing + use sdk for dast server + misc
Ice3man543 Nov 20, 2024
0395951
feat: more additions and enhancements
Ice3man543 Nov 21, 2024
7c27c22
misc changes to live server
Ice3man543 Nov 22, 2024
78ad4e3
Merge branch 'dev' of https://github.com/projectdiscovery/nuclei into…
Ice3man543 Nov 22, 2024
ce023d0
Merge branch 'auth-file-enhancements' of https://github.com/projectdi…
Ice3man543 Nov 22, 2024
090cadb
misc
Ice3man543 Nov 26, 2024
727ff90
use utils pprof server
Ice3man543 Nov 29, 2024
a105306
feat: added simpler stats tracking system
Ice3man543 Dec 1, 2024
38f25f5
feat: fixed analyzer timeout issue + missing case fix
Ice3man543 Dec 2, 2024
2fc1b3a
Merge branch 'time-analyzer-bugfixes' of https://github.com/projectdi…
Ice3man543 Dec 2, 2024
fda6165
misc changes fix
Ice3man543 Dec 2, 2024
7f55f01
feat: changed the logics a bit + misc changes and additions
Ice3man543 Dec 10, 2024
1fa4540
Merge branch 'dev' of https://github.com/projectdiscovery/nuclei into…
Ice3man543 Dec 11, 2024
ad5ec96
feat: re-added slope checks + misc
Ice3man543 Dec 13, 2024
70bd93a
feat: added baseline measurements for time based checks
Ice3man543 Dec 13, 2024
98646e6
chore(server): fix typos
dwisiswant0 Dec 13, 2024
f31e963
fix(templates): potential DOM XSS
dwisiswant0 Dec 13, 2024
1d2a1dc
fix(authx): potential NIL deref
dwisiswant0 Dec 13, 2024
9f4b89a
feat: misc review changes
Ice3man543 Dec 16, 2024
ab2ce86
Merge branch 'dev' of https://github.com/projectdiscovery/nuclei into…
Ice3man543 Dec 16, 2024
0c4645b
removed debug logging
Ice3man543 Dec 16, 2024
c1a2903
feat: remove existing cookies only
Ice3man543 Dec 19, 2024
78320d8
feat: lint fixes
Ice3man543 Dec 19, 2024
952a887
misc
Ice3man543 Dec 19, 2024
6684f38
misc text update
ehsandeep Dec 24, 2024
f6fdffe
request endpoint update
ehsandeep Feb 1, 2025
a2c8f1e
feat: added tracking for status code, waf-detection & grouped errors …
Ice3man543 Feb 13, 2025
3c825e8
fix var dump (#5921)
dogancanbakir Feb 13, 2025
ef11565
Added filename length restriction for debug mode (-srd flag) (#5931)
Lercas Feb 13, 2025
6e55c57
more updates
ehsandeep Feb 13, 2025
c6a0dd2
Merge branch 'dev' of https://github.com/projectdiscovery/nuclei into…
Ice3man543 Feb 13, 2025
d7156dc
Merge branch 'nuclei-dast-server' of https://github.com/projectdiscov…
ehsandeep Feb 13, 2025
a62fd8d
Update pkg/output/stats/waf/waf.go
ehsandeep Feb 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions cmd/nuclei/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ func main() {
go func() {
for range c {
gologger.Info().Msgf("CTRL+C pressed: Exiting\n")
if options.DASTServer {
nucleiRunner.Close()
os.Exit(1)
}

gologger.Info().Msgf("Attempting graceful shutdown...")
if options.EnableCloudUpload {
gologger.Info().Msgf("Uploading scan results to cloud...")
Expand Down Expand Up @@ -358,9 +363,15 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.FuzzingMode, "fuzzing-mode", "fm", "", "overrides fuzzing mode set in template (multiple, single)"),
flagSet.BoolVar(&fuzzFlag, "fuzz", false, "enable loading fuzzing templates (Deprecated: use -dast instead)"),
flagSet.BoolVar(&options.DAST, "dast", false, "enable / run dast (fuzz) nuclei templates"),
flagSet.BoolVarP(&options.DASTServer, "dast-server", "dts", false, "enable dast server mode (live fuzzing)"),
flagSet.BoolVarP(&options.DASTReport, "dast-report", "dtr", false, "write dast scan report to file"),
flagSet.StringVarP(&options.DASTServerToken, "dast-server-token", "dtst", "", "dast server token (optional)"),
flagSet.StringVarP(&options.DASTServerAddress, "dast-server-address", "dtsa", "localhost:9055", "dast server address"),
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved
flagSet.BoolVarP(&options.DisplayFuzzPoints, "display-fuzz-points", "dfp", false, "display fuzz points in the output for debugging"),
flagSet.IntVar(&options.FuzzParamFrequency, "fuzz-param-frequency", 10, "frequency of uninteresting parameters for fuzzing before skipping"),
flagSet.StringVarP(&options.FuzzAggressionLevel, "fuzz-aggression", "fa", "low", "fuzzing aggression level controls payload count for fuzz (low, medium, high)"),
flagSet.StringSliceVarP(&options.Scope, "fuzz-scope", "cs", nil, "in scope url regex to be followed by fuzzer", goflags.FileCommaSeparatedStringSliceOptions),
flagSet.StringSliceVarP(&options.OutOfScope, "fuzz-out-scope", "cos", nil, "out of scope url regex to be excluded by fuzzer", goflags.FileCommaSeparatedStringSliceOptions),
)

flagSet.CreateGroup("uncover", "Uncover",
Expand Down Expand Up @@ -447,6 +458,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.StatsJSON, "stats-json", "sj", false, "display statistics in JSONL(ines) format"),
flagSet.IntVarP(&options.StatsInterval, "stats-interval", "si", 5, "number of seconds to wait between showing a statistics update"),
flagSet.IntVarP(&options.MetricsPort, "metrics-port", "mp", 9092, "port to expose nuclei metrics on"),
flagSet.BoolVarP(&options.HTTPStats, "http-stats", "hps", false, "enable http status capturing (experimental)"),
)

flagSet.CreateGroup("cloud", "Cloud",
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ require (
github.com/DataDog/gostackparse v0.6.0
github.com/Masterminds/semver/v3 v3.2.1
github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057
github.com/alitto/pond v1.9.2
github.com/antchfx/xmlquery v1.3.17
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
github.com/aws/aws-sdk-go-v2 v1.19.0
Expand All @@ -75,7 +76,7 @@ require (
github.com/h2non/filetype v1.1.3
github.com/invopop/yaml v0.3.1
github.com/kitabisa/go-ci v1.0.3
github.com/labstack/echo/v4 v4.10.2
github.com/labstack/echo/v4 v4.12.0
github.com/leslie-qiwa/flat v0.0.0-20230424180412-f9d1cf014baa
github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.22
Expand Down Expand Up @@ -359,7 +360,7 @@ require (
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
Expand Down
17 changes: 6 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alitto/pond v1.9.2 h1:9Qb75z/scEZVCoSU+osVmQ0I0JOeLfdTDafrbcJ8CLs=
github.com/alitto/pond v1.9.2/go.mod h1:xQn3P/sHTYcU/1BR3i86IGIrilcrGC2LiS+E2+CJWsI=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
Expand Down Expand Up @@ -692,10 +694,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
Expand Down Expand Up @@ -723,12 +725,10 @@ github.com/mackerelio/go-osstat v0.2.4/go.mod h1:Zy+qzGdZs3A9cuIqmgbJvwbmLQH9dJv
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
Expand Down Expand Up @@ -1104,7 +1104,6 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
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/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/weppos/publicsuffix-go v0.12.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
Expand Down Expand Up @@ -1420,10 +1419,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-20210616094352-59db8d763f22/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-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down Expand Up @@ -1662,7 +1658,6 @@ 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-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
Expand Down
9 changes: 7 additions & 2 deletions internal/runner/lazy.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,13 @@ func GetLazyAuthFetchCallback(opts *AuthLazyFetchOptions) authx.LazyFetchSecret
}
// dynamic values
for k, v := range e.OperatorsResult.DynamicValues {
if len(v) > 0 {
data[k] = v[0]
// Iterate through all the values and choose the
// largest value as the extracted value
for _, value := range v {
oldVal, ok := data[k]
if !ok || len(value) > len(oldVal.(string)) {
data[k] = value
}
}
}
// named extractors
Expand Down
13 changes: 13 additions & 0 deletions internal/runner/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ func ValidateOptions(options *types.Options) error {
if options.Validate {
validateTemplatePaths(config.DefaultConfig.TemplatesDirectory, options.Templates, options.Workflows)
}
if options.DAST {
if err := validateDASTOptions(options); err != nil {
return err
}
}

// Verify if any of the client certificate options were set since it requires all three to work properly
if options.HasClientCertificates() {
Expand Down Expand Up @@ -274,6 +279,14 @@ func validateMissingGitLabOptions(options *types.Options) []string {
return missing
}

func validateDASTOptions(options *types.Options) error {
// Ensure the DAST server token meets minimum length requirement
if len(options.DASTServerToken) > 0 && len(options.DASTServerToken) < 16 {
return fmt.Errorf("DAST server token must be at least 16 characters long")
}
return nil
}
coderabbitai[bot] marked this conversation as resolved.
Show resolved Hide resolved

func createReportingOptions(options *types.Options) (*reporting.Options, error) {
var reportingOptions = &reporting.Options{}
if options.ReportingConfig != "" {
Expand Down
114 changes: 99 additions & 15 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package runner
import (
"context"
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"path/filepath"
"reflect"
Expand All @@ -13,18 +11,21 @@ import (
"time"

"github.com/projectdiscovery/nuclei/v3/internal/pdcp"
"github.com/projectdiscovery/nuclei/v3/internal/server"
"github.com/projectdiscovery/nuclei/v3/pkg/authprovider"
"github.com/projectdiscovery/nuclei/v3/pkg/fuzz/frequency"
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
"github.com/projectdiscovery/nuclei/v3/pkg/loader/parser"
outputstats "github.com/projectdiscovery/nuclei/v3/pkg/output/stats"
"github.com/projectdiscovery/nuclei/v3/pkg/scan/events"
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
uncoverlib "github.com/projectdiscovery/uncover"
pdcpauth "github.com/projectdiscovery/utils/auth/pdcp"
"github.com/projectdiscovery/utils/env"
fileutil "github.com/projectdiscovery/utils/file"
permissionutil "github.com/projectdiscovery/utils/permission"
pprofutil "github.com/projectdiscovery/utils/pprof"
updateutils "github.com/projectdiscovery/utils/update"

"github.com/logrusorgru/aurora"
Expand All @@ -40,6 +41,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
"github.com/projectdiscovery/nuclei/v3/pkg/external/customtemplates"
fuzzStats "github.com/projectdiscovery/nuclei/v3/pkg/fuzz/stats"
"github.com/projectdiscovery/nuclei/v3/pkg/input"
parsers "github.com/projectdiscovery/nuclei/v3/pkg/loader/workflow"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
Expand Down Expand Up @@ -88,18 +90,20 @@ type Runner struct {
rateLimiter *ratelimit.Limiter
hostErrors hosterrorscache.CacheInterface
resumeCfg *types.ResumeCfg
pprofServer *http.Server
pprofServer *pprofutil.PprofServer
pdcpUploadErrMsg string
inputProvider provider.InputProvider
fuzzFrequencyCache *frequency.Tracker
httpStats *outputstats.Tracker

//general purpose temporary directory
tmpDir string
parser parser.Parser
httpApiEndpoint *httpapi.Server
fuzzStats *fuzzStats.Tracker
dastServer *server.DASTServer
}

const pprofServerAddress = "127.0.0.1:8086"

// New creates a new client for running the enumeration process.
func New(options *types.Options) (*Runner, error) {
runner := &Runner{
Expand Down Expand Up @@ -216,15 +220,8 @@ func New(options *types.Options) (*Runner, error) {
templates.SeverityColorizer = colorizer.New(runner.colorizer)

if options.EnablePprof {
server := &http.Server{
Addr: pprofServerAddress,
Handler: http.DefaultServeMux,
}
gologger.Info().Msgf("Listening pprof debug server on: %s", pprofServerAddress)
runner.pprofServer = server
go func() {
_ = server.ListenAndServe()
}()
runner.pprofServer = pprofutil.NewPprofServer()
runner.pprofServer.Start()
}

if options.HttpApiEndpoint != "" {
Expand Down Expand Up @@ -256,6 +253,10 @@ func New(options *types.Options) (*Runner, error) {
}
// setup a proxy writer to automatically upload results to PDCP
runner.output = runner.setupPDCPUpload(outputWriter)
if options.HTTPStats {
runner.httpStats = outputstats.NewTracker()
runner.output = output.NewMultiWriter(runner.output, output.NewTrackerWriter(runner.httpStats))
}

if options.JSONL && options.EnableProgressBar {
options.StatsJSON = true
Expand Down Expand Up @@ -296,6 +297,37 @@ func New(options *types.Options) (*Runner, error) {
}
runner.resumeCfg = resumeCfg

if options.DASTReport || options.DASTServer {
var err error
runner.fuzzStats, err = fuzzStats.NewTracker()
if err != nil {
return nil, errors.Wrap(err, "could not create fuzz stats db")
}
if !options.DASTServer {
dastServer, err := server.NewStatsServer(runner.fuzzStats)
if err != nil {
return nil, errors.Wrap(err, "could not create dast server")
}
runner.dastServer = dastServer
}
}

if runner.fuzzStats != nil {
outputWriter.JSONLogRequestHook = func(request *output.JSONLogRequest) {
if request.Error == "none" || request.Error == "" {
return
}
runner.fuzzStats.RecordErrorEvent(fuzzStats.ErrorEvent{
TemplateID: request.Template,
URL: request.Input,
Error: request.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
Expand Down Expand Up @@ -362,6 +394,12 @@ func (r *Runner) runStandardEnumeration(executerOpts protocols.ExecutorOptions,

// Close releases all the resources and cleans up
func (r *Runner) Close() {
if r.dastServer != nil {
r.dastServer.Close()
}
if r.httpStats != nil {
r.httpStats.DisplayTopStats(r.options.NoColor)
}
// dump hosterrors cache
if r.hostErrors != nil {
r.hostErrors.Close()
Expand All @@ -380,7 +418,7 @@ func (r *Runner) Close() {
}
protocolinit.Close()
if r.pprofServer != nil {
_ = r.pprofServer.Shutdown(context.Background())
r.pprofServer.Stop()
}
if r.rateLimiter != nil {
r.rateLimiter.Stop()
Expand Down Expand Up @@ -439,6 +477,41 @@ func (r *Runner) setupPDCPUpload(writer output.Writer) output.Writer {
// RunEnumeration sets up the input layer for giving input nuclei.
// binary and runs the actual enumeration
func (r *Runner) RunEnumeration() error {
// If the user has asked for DAST server mode, run the live
// DAST fuzzing server.
if r.options.DASTServer {
execurOpts := &server.NucleiExecutorOptions{
Options: r.options,
Output: r.output,
Progress: r.progress,
Catalog: r.catalog,
IssuesClient: r.issuesClient,
RateLimiter: r.rateLimiter,
Interactsh: r.interactsh,
ProjectFile: r.projectFile,
Browser: r.browser,
Colorizer: r.colorizer,
Parser: r.parser,
TemporaryDirectory: r.tmpDir,
FuzzStatsDB: r.fuzzStats,
}
dastServer, err := server.New(&server.Options{
Address: r.options.DASTServerAddress,
Templates: r.options.Templates,
OutputWriter: r.output,
Verbose: r.options.Verbose,
Token: r.options.DASTServerToken,
InScope: r.options.Scope,
OutScope: r.options.OutOfScope,
NucleiExecutorOptions: execurOpts,
})
if err != nil {
return err
}
r.dastServer = dastServer
return dastServer.Start()
}

// If user asked for new templates to be executed, collect the list from the templates' directory.
if r.options.NewTemplates {
if arr := config.DefaultConfig.GetNewAdditions(); len(arr) > 0 {
Expand Down Expand Up @@ -624,6 +697,14 @@ func (r *Runner) RunEnumeration() error {
Retries: r.options.Retries,
}, "")

if r.dastServer != nil {
go func() {
if err := r.dastServer.Start(); err != nil {
gologger.Error().Msgf("could not start dast server: %v", err)
}
}()
}

enumeration := false
var results *atomic.Bool
results, err = r.runStandardEnumeration(executorOpts, store, executorEngine)
Expand All @@ -633,6 +714,9 @@ func (r *Runner) RunEnumeration() error {
return err
}

if executorOpts.FuzzStatsDB != nil {
executorOpts.FuzzStatsDB.Close()
}
if r.interactsh != nil {
matched := r.interactsh.Close()
if matched {
Expand Down
Loading
Loading