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

Fuzzing layer enhancements + input-types support #4477

Merged
merged 92 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
26d848b
feat: move fuzz package to root directory
Ice3man543 Dec 2, 2023
f916eb9
feat: added support for input providers like openapi,postman,etc
Ice3man543 Dec 6, 2023
88e3772
feat: integration of new fuzzing logic in engine
Ice3man543 Dec 9, 2023
a3be761
bugfix: use and instead of or
Ice3man543 Dec 9, 2023
e6d8d64
fixed lint errors
Ice3man543 Dec 9, 2023
c7a6774
Merge branch 'dev' into fuzzing-layer-enhancements
ehsandeep Jan 7, 2024
84470f1
go mod tidy
ehsandeep Jan 7, 2024
dfc5c47
Merge branch 'dev' of https://github.com/projectdiscovery/nuclei into…
Ice3man543 Feb 4, 2024
dec6857
Merge branch 'fuzzing-layer-enhancements' of https://github.com/proje…
Ice3man543 Feb 4, 2024
dd35d36
Merge branch 'dev' into fuzzing-layer-enhancements
tarunKoyalwar Feb 8, 2024
37fe0ac
add new reqresp type + bump utils
tarunKoyalwar Feb 13, 2024
daf1397
custom http request parser
tarunKoyalwar Feb 13, 2024
4c45c00
use new struct type RequestResponse
tarunKoyalwar Feb 14, 2024
94c4199
introduce unified input/target provider
tarunKoyalwar Feb 14, 2024
e9913b8
abstract input formats via new inputprovider
tarunKoyalwar Feb 15, 2024
f3d5d61
completed input provider refactor
tarunKoyalwar Feb 15, 2024
2ce7cfa
remove duplicated code
tarunKoyalwar Feb 15, 2024
2057f19
resolve merge conflicts
tarunKoyalwar Feb 19, 2024
a2bff34
add sdk method to load targets
tarunKoyalwar Feb 19, 2024
f154f50
rename component url->path
tarunKoyalwar Feb 19, 2024
9a65fe2
add new yaml format + remove duplicated code
tarunKoyalwar Feb 20, 2024
f853497
use gopkg.in/yaml.v3 for parsing
tarunKoyalwar Feb 20, 2024
034abdb
update .gitignore
tarunKoyalwar Feb 20, 2024
29e3080
refactor/move + docs fuzzing in http protocol
tarunKoyalwar Feb 20, 2024
36aceda
fuzz: header + query integration test using fuzzplayground
tarunKoyalwar Feb 20, 2024
f9bfde6
fix integration test runner in windows
tarunKoyalwar Feb 20, 2024
9e216d8
feat add support for filter in http fuzz
tarunKoyalwar Feb 23, 2024
d362dd3
rewrite header/query integration test with filter
tarunKoyalwar Feb 23, 2024
3b03326
add replace regex rule
tarunKoyalwar Feb 23, 2024
244fb6a
support kv fuzzing + misc updates
tarunKoyalwar Feb 23, 2024
699007b
add path fuzzing example + misc improvements
tarunKoyalwar Feb 27, 2024
23219e3
fix matchedURL + skip httpx on multi formats
tarunKoyalwar Feb 27, 2024
3bf9b05
resolve merge conflict
tarunKoyalwar Feb 27, 2024
fe09df7
cookie fuzz integration test
tarunKoyalwar Feb 28, 2024
613db43
add json body + params body tests
tarunKoyalwar Feb 28, 2024
d379748
feat add multipart/form-data fuzzing support
tarunKoyalwar Feb 28, 2024
45a5765
add all fuzz body integration test
tarunKoyalwar Feb 28, 2024
3b4ea2d
misc bug fixes + minor refactor
tarunKoyalwar Feb 28, 2024
d74af44
add multipart form + body form unit tests
tarunKoyalwar Feb 28, 2024
0d72db2
only run fuzzing templates if -fuzz flag is given
tarunKoyalwar Feb 28, 2024
a4f92d7
refactor/move fuzz playground server to pkg
tarunKoyalwar Mar 1, 2024
5f9b467
fix integration test + refactor
tarunKoyalwar Mar 1, 2024
8494ae7
resolve merge conflict
tarunKoyalwar Mar 1, 2024
5d67504
add auth types and strategies
tarunKoyalwar Mar 1, 2024
78e1e3f
add file auth provider
tarunKoyalwar Mar 1, 2024
90955e9
start implementing auth logic in http
tarunKoyalwar Mar 1, 2024
03ea1a1
add logic in http protocol
tarunKoyalwar Mar 1, 2024
10215bf
static auth implemented for http
tarunKoyalwar Mar 1, 2024
a8b50f6
default :80,:443 normalization
tarunKoyalwar Mar 1, 2024
95c57b1
feat: dynamic auth init
tarunKoyalwar Mar 1, 2024
c88b9b4
feat: dynamic auth using templates
tarunKoyalwar Mar 1, 2024
a3fb458
validate targets count in openapi+swagger
tarunKoyalwar Mar 4, 2024
4c55e9e
inputformats: add support to accept variables
tarunKoyalwar Mar 4, 2024
40fbe6d
Merge branch 'dev' into fuzzing-layer-enhancements
tarunKoyalwar Mar 5, 2024
a7e301d
fix workflow integration test
tarunKoyalwar Mar 5, 2024
fbfec13
update lazy cred fetch logic
tarunKoyalwar Mar 5, 2024
62c7bd1
fix unit test
tarunKoyalwar Mar 5, 2024
473edf0
drop postman support
tarunKoyalwar Mar 5, 2024
7912710
domain related normalization
tarunKoyalwar Mar 7, 2024
5ca09b1
update secrets.yaml file format + misc updates
tarunKoyalwar Mar 7, 2024
643c918
add auth prefetch option
tarunKoyalwar Mar 7, 2024
83fe481
remove old secret files
tarunKoyalwar Mar 7, 2024
30f5a5e
add fuzzing+auth related sdk options
tarunKoyalwar Mar 7, 2024
3823213
fix/support multiple mode in kv header fuzzing
tarunKoyalwar Mar 7, 2024
da7de2c
rename 'headers' -> 'header' in fuzzing rules
tarunKoyalwar Mar 7, 2024
fe6d16c
Merge branch 'dev' into fuzzing-layer-enhancements
tarunKoyalwar Mar 7, 2024
9234b9d
fix deadlock due to merge conflict resolution
tarunKoyalwar Mar 7, 2024
d230e2a
misc update
ehsandeep Mar 9, 2024
18fd5c7
add bool type in parsed value
tarunKoyalwar Mar 9, 2024
52bde4a
add openapi validation+override+ new flags
tarunKoyalwar Mar 9, 2024
1c03c7a
misc updates
tarunKoyalwar Mar 9, 2024
c71883f
remove optional path parameters when unavailable
tarunKoyalwar Mar 9, 2024
c6045ef
fix swagger.yaml file
tarunKoyalwar Mar 9, 2024
428939c
misc updates
tarunKoyalwar Mar 10, 2024
6c3ee92
update print msg
tarunKoyalwar Mar 10, 2024
b96e51b
multiple openapi validation enchancements + appMode
tarunKoyalwar Mar 10, 2024
b61765a
add optional params in required_openapi_vars.yaml file
tarunKoyalwar Mar 10, 2024
453edb4
improve warning/verbose msgs in format
tarunKoyalwar Mar 10, 2024
9d6f374
fix skip-format-validation not working
tarunKoyalwar Mar 10, 2024
65e101c
use 'params/parameter' instead of 'variable' in openapi
tarunKoyalwar Mar 10, 2024
a3a00d2
add retry support for falky tests
tarunKoyalwar Mar 10, 2024
1d56767
fix nuclei loading ignored templates (#4849)
tarunKoyalwar Mar 9, 2024
97e3907
feat: issue tracker URLs in JSON + misc fixes (#4855)
Ice3man543 Mar 10, 2024
54c52b5
introduce `disable-unsigned-templates` flag (#4820)
dogancanbakir Mar 10, 2024
57f747b
Purge cache on global callback set (#4840)
Mzack9999 Mar 10, 2024
3a7a5b4
Merge branch 'dev' into fuzzing-layer-enhancements
tarunKoyalwar Mar 10, 2024
958d690
Merge branch 'dev' into fuzzing-layer-enhancements
ehsandeep Mar 11, 2024
328a231
misc update
ehsandeep Mar 13, 2024
339f97f
Merge branch 'dev' into fuzzing-layer-enhancements
ehsandeep Mar 13, 2024
bc81d02
add application/octet-stream support
tarunKoyalwar Mar 13, 2024
95b5b4b
openapi: support path specific params
tarunKoyalwar Mar 13, 2024
719a370
misc option + readme update
ehsandeep Mar 13, 2024
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
7 changes: 5 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ pkg/protocols/headless/engine/.cache
/tsgen
/scrapefuncs
/integration_tests/.cache/
/integration_tests/.nuclei-config/
/*.yaml
/pkg/protocols/headless/engine/.nuclei-config/
**/*-config
**/*-cache
/fuzzplayground
integration_tests/fuzzplayground

2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ jsupdate:
ts:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "tsgen" pkg/js/devtools/tsgen/cmd/tsgen/main.go
./tsgen -dir pkg/js/libs -out pkg/js/generated/ts
fuzzplayground:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "fuzzplayground" cmd/tools/fuzzplayground/main.go
memogen:
$(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "memogen" cmd/memogen/memogen.go
./memogen -src pkg/js/libs -tpl cmd/memogen/function.tpl
Expand Down
39 changes: 33 additions & 6 deletions cmd/integration-test/fuzz.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,40 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
)

const (
targetFile = "fuzz/testData/ginandjuice.proxify.yaml"
)

var fuzzingTestCases = []TestCaseInfo{
{Path: "fuzz/fuzz-mode.yaml", TestCase: &fuzzModeOverride{}},
{Path: "fuzz/fuzz-type.yaml", TestCase: &fuzzTypeOverride{}},
{Path: "fuzz/fuzz-query.yaml", TestCase: &httpFuzzQuery{}},
{Path: "fuzz/fuzz-headless.yaml", TestCase: &HeadlessFuzzingQuery{}},
{Path: "fuzz/fuzz-header-basic.yaml", TestCase: &FuzzHeaderBasic{}},
{Path: "fuzz/fuzz-header-multiple.yaml", TestCase: &FuzzHeaderMultiple{}},
// for fuzzing we should prioritize adding test case related backend
// logic in fuzz playground server instead of adding them here
{Path: "fuzz/fuzz-query-num-replace.yaml", TestCase: &genericFuzzTestCase{expectedResults: 2}},
{Path: "fuzz/fuzz-host-header-injection.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
{Path: "fuzz/fuzz-path-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
{Path: "fuzz/fuzz-cookie-error-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
{Path: "fuzz/fuzz-body-json-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
{Path: "fuzz/fuzz-body-multipart-form-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
{Path: "fuzz/fuzz-body-params-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
{Path: "fuzz/fuzz-body-xml-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 1}},
{Path: "fuzz/fuzz-body-generic-sqli.yaml", TestCase: &genericFuzzTestCase{expectedResults: 4}},
}

type genericFuzzTestCase struct {
expectedResults int
}

func (g *genericFuzzTestCase) Execute(filePath string) error {
results, err := testutils.RunNucleiWithArgsAndGetResults(debug, "-t", filePath, "-l", targetFile, "-im", "yaml")
if err != nil {
return err
}
return expectResultsCount(results, g.expectedResults)
}

type httpFuzzQuery struct{}
Expand All @@ -34,7 +61,7 @@ func (h *httpFuzzQuery) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()

results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example", debug)
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example", debug, "-fuzz")
if err != nil {
return err
}
Expand All @@ -53,7 +80,7 @@ func (h *fuzzModeOverride) Execute(filePath string) error {
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example&name=nuclei", debug, "-fuzzing-mode", "single", "-jsonl")
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/?id=example&name=nuclei", debug, "-fuzzing-mode", "single", "-jsonl", "-fuzz")
if err != nil {
return err
}
Expand Down Expand Up @@ -98,7 +125,7 @@ func (h *fuzzTypeOverride) Execute(filePath string) error {
})
ts := httptest.NewTLSServer(router)
defer ts.Close()
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?id=example", debug, "-fuzzing-type", "replace", "-jsonl")
results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?id=example", debug, "-fuzzing-type", "replace", "-jsonl", "-fuzz")
if err != nil {
return err
}
Expand Down Expand Up @@ -143,7 +170,7 @@ func (h *HeadlessFuzzingQuery) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()

got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?url=https://scanme.sh", debug, "-headless")
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"?url=https://scanme.sh", debug, "-headless", "-fuzz")
if err != nil {
return err
}
Expand All @@ -164,7 +191,7 @@ func (h *FuzzHeaderBasic) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()

got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-fuzz")
if err != nil {
return err
}
Expand Down Expand Up @@ -192,7 +219,7 @@ func (h *FuzzHeaderMultiple) Execute(filePath string) error {
ts := httptest.NewTLSServer(router)
defer ts.Close()

got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug)
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-fuzz")
if err != nil {
return err
}
Expand Down
20 changes: 20 additions & 0 deletions cmd/integration-test/integration-test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import (

"github.com/logrusorgru/aurora"

"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
"github.com/projectdiscovery/nuclei/v3/pkg/testutils/fuzzplayground"
sliceutil "github.com/projectdiscovery/utils/slice"
)

Expand Down Expand Up @@ -53,6 +55,10 @@ var (
"flow": flowTestcases,
"javascript": jsTestcases,
}
// flakyTests are run with a retry count of 3
flakyTests = map[string]bool{
"protocols/http/self-contained-file-input.yaml": true,
}

// For debug purposes
runProtocol = ""
Expand All @@ -78,6 +84,18 @@ func main() {
os.Exit(1)
}

// start fuzz playground server
defer fuzzplayground.Cleanup()
server := fuzzplayground.GetPlaygroundServer()
defer server.Close()
go func() {
if err := server.Start("localhost:8082"); err != nil {
if !strings.Contains(err.Error(), "Server closed") {
gologger.Fatal().Msgf("Could not start server: %s\n", err)
}
}
}()

customTestsList := normalizeSplit(customTests)

failedTestTemplatePaths := runTests(customTestsList)
Expand Down Expand Up @@ -150,6 +168,8 @@ func runTests(customTemplatePaths []string) []string {
var err error
if proto == "interactsh" || strings.Contains(testCaseInfo.Path, "interactsh") {
failedTemplatePath, err = executeWithRetry(testCaseInfo.TestCase, testCaseInfo.Path, interactshRetryCount)
} else if flakyTests[testCaseInfo.Path] {
failedTemplatePath, err = executeWithRetry(testCaseInfo.TestCase, testCaseInfo.Path, interactshRetryCount)
} else {
failedTemplatePath, err = execute(testCaseInfo.TestCase, testCaseInfo.Path)
}
Expand Down
6 changes: 2 additions & 4 deletions cmd/integration-test/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/disk"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/loader"
"github.com/projectdiscovery/nuclei/v3/pkg/core"
"github.com/projectdiscovery/nuclei/v3/pkg/core/inputs"
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
"github.com/projectdiscovery/nuclei/v3/pkg/parsers"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/contextargs"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/hosterrorscache"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolinit"
Expand Down Expand Up @@ -126,8 +125,7 @@ func executeNucleiAsLibrary(templatePath, templateURL string) ([]string, error)
}
store.Load()

input := &inputs.SimpleInputProvider{Inputs: []*contextargs.MetaInput{{Input: templateURL}}}
_ = engine.Execute(store.Templates(), input)
_ = engine.Execute(store.Templates(), provider.NewSimpleInputProviderWithUrls(templateURL))
engine.WorkPool().Wait() // Wait for the scan to finish

return results, nil
Expand Down
2 changes: 1 addition & 1 deletion cmd/integration-test/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ type workflowSharedCookies struct{}

// Execute executes a test case and returns an error if occurred
func (h *workflowSharedCookies) Execute(filePath string) error {
handleFunc := func(name string, w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
handleFunc := func(name string, w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
cookie := &http.Cookie{Name: name, Value: name}
http.SetCookie(w, cookie)
}
Expand Down
26 changes: 25 additions & 1 deletion cmd/nuclei/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/projectdiscovery/interactsh/pkg/client"
"github.com/projectdiscovery/nuclei/v3/internal/runner"
"github.com/projectdiscovery/nuclei/v3/pkg/catalog/config"
"github.com/projectdiscovery/nuclei/v3/pkg/input/provider"
"github.com/projectdiscovery/nuclei/v3/pkg/installer"
"github.com/projectdiscovery/nuclei/v3/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v3/pkg/operators/common/dsl"
Expand All @@ -46,6 +47,9 @@ var (
)

func main() {
// enables CLI specific configs mostly interactive behavior
config.CurrentAppMode = config.AppModeCLI

if err := runner.ConfigureOptions(); err != nil {
gologger.Fatal().Msgf("Could not initialize options: %s\n", err)
}
Expand Down Expand Up @@ -201,6 +205,12 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringSliceVarP(&options.IPVersion, "ip-version", "iv", nil, "IP version to scan of hostname (4,6) - (default 4)", goflags.CommaSeparatedStringSliceOptions),
)

flagSet.CreateGroup("target-format", "Target-Format",
flagSet.StringVarP(&options.InputFileMode, "input-mode", "im", "list", fmt.Sprintf("mode of input file (%v)", provider.SupportedInputFormats())),
flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"),
flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"),
)

flagSet.CreateGroup("templates", "Templates",
flagSet.BoolVarP(&options.NewTemplates, "new-templates", "nt", false, "run only new templates added in latest nuclei-templates release"),
flagSet.StringSliceVarP(&options.NewTemplatesWithVersion, "new-templates-version", "ntv", nil, "run new templates added in specific version", goflags.CommaSeparatedStringSliceOptions),
Expand Down Expand Up @@ -302,6 +312,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.CreateGroup("fuzzing", "Fuzzing",
flagSet.StringVarP(&options.FuzzingType, "fuzzing-type", "ft", "", "overrides fuzzing type set in template (replace, prefix, postfix, infix)"),
flagSet.StringVarP(&options.FuzzingMode, "fuzzing-mode", "fm", "", "overrides fuzzing mode set in template (multiple, single)"),
flagSet.BoolVar(&options.FuzzTemplates, "fuzz", false, "enable and run fuzzing templates"),
)

flagSet.CreateGroup("uncover", "Uncover",
Expand Down Expand Up @@ -392,6 +403,11 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.StringVarP(&options.ScanID, "scan-id", "sid", "", "upload scan results to given scan id"),
)

flagSet.CreateGroup("Authentication", "Authentication",
flagSet.StringSliceVar(&options.SecretsFile, "secrets", nil, "path to file containing secrets for nuclei authenticated scan", goflags.CommaSeparatedStringSliceOptions),
flagSet.BoolVarP(&options.PreFetchSecrets, "prefetch-secrets", "ps", false, "prefetch secrets from the secrets file"),
)

flagSet.SetCustomHelpText(`EXAMPLES:
Run nuclei on single host:
$ nuclei -target example.com
Expand All @@ -418,7 +434,7 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
goflags.DisableAutoConfigMigration = true
_ = flagSet.Parse()

// api key hierarchy: cli flag > env var > .pdcp/credential file
// api key hierarchy: cli flag > env var > .pdcp/credential file
if pdcpauth == "true" {
runner.AuthWithPDCP()
} else if len(pdcpauth) == 36 {
Expand Down Expand Up @@ -466,6 +482,14 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory)
}

if len(options.SecretsFile) > 0 {
for _, secretFile := range options.SecretsFile {
if !fileutil.FileExists(secretFile) {
gologger.Fatal().Msgf("given secrets file '%s' does not exist", options.SecretsFile)
}
}
}

cleanupOldResumeFiles()
return flagSet
}
Expand Down
99 changes: 16 additions & 83 deletions cmd/tools/fuzzplayground/main.go
Original file line number Diff line number Diff line change
@@ -1,94 +1,27 @@
package main

import (
"fmt"
"io"
"os/exec"
"strconv"
"strings"
"flag"

"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/projectdiscovery/retryablehttp-go"
_ "github.com/mattn/go-sqlite3"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v3/pkg/testutils/fuzzplayground"
)

func main() {
e := echo.New()
e.Use(middleware.Recover())
e.Use(middleware.Logger())

e.GET("/", indexHandler)
e.GET("/info", infoHandler)
e.GET("/redirect", redirectHandler)
e.GET("/request", requestHandler)
e.GET("/email", emailHandler)
e.GET("/permissions", permissionsHandler)
if err := e.Start("localhost:8082"); err != nil {
panic(err)
}
}

var bodyTemplate = `<html>
<head>
<title>Fuzz Playground</title>
</head>
<body>
%s
</body>
</html>`

func indexHandler(ctx echo.Context) error {
return ctx.HTML(200, fmt.Sprintf(bodyTemplate, `<h1>Fuzzing Playground</h1><hr>
<ul>
<li><a href="/info?name=test&another=value&random=data">Info Page XSS</a></li>
<li><a href="/redirect?redirect_url=/info?name=redirected_from_url">Redirect Page OpenRedirect</a></li>
<li><a href="/request?url=https://example.com">Request Page SSRF</a></li>
<li><a href="/email?text=important_user">Email Page SSTI</a></li>
<li><a href="/permissions?cmd=whoami">Permissions Page CMDI</a></li>
</ul>
`))
}

func infoHandler(ctx echo.Context) error {
return ctx.HTML(200, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Name of user: %s%s%s", ctx.QueryParam("name"), ctx.QueryParam("another"), ctx.QueryParam("random"))))
}
var (
addr string
)

func redirectHandler(ctx echo.Context) error {
url := ctx.QueryParam("redirect_url")
return ctx.Redirect(302, url)
}
func main() {
flag.StringVar(&addr, "addr", "localhost:8082", "playground server address")
flag.Parse()

func requestHandler(ctx echo.Context) error {
url := ctx.QueryParam("url")
data, err := retryablehttp.DefaultClient().Get(url)
if err != nil {
return ctx.HTML(500, err.Error())
}
defer data.Body.Close()
defer fuzzplayground.Cleanup()
server := fuzzplayground.GetPlaygroundServer()
defer server.Close()

body, _ := io.ReadAll(data.Body)
return ctx.HTML(200, fmt.Sprintf(bodyTemplate, string(body)))
}

func emailHandler(ctx echo.Context) error {
text := ctx.QueryParam("text")
if strings.Contains(text, "{{") {
trimmed := strings.SplitN(strings.Trim(text[strings.Index(text, "{"):], "{}"), "*", 2)
if len(trimmed) < 2 {
return ctx.HTML(500, "invalid template")
}
first, _ := strconv.Atoi(trimmed[0])
second, _ := strconv.Atoi(trimmed[1])
text = strconv.Itoa(first * second)
// Start the server
if err := server.Start(addr); err != nil {
gologger.Fatal().Msgf("Could not start server: %s\n", err)
}
return ctx.HTML(200, fmt.Sprintf(bodyTemplate, fmt.Sprintf("Text: %s", text)))
}

func permissionsHandler(ctx echo.Context) error {
command := ctx.QueryParam("cmd")
fields := strings.Fields(command)
cmd := exec.Command(fields[0], fields[1:]...)
data, _ := cmd.CombinedOutput()

return ctx.HTML(200, fmt.Sprintf(bodyTemplate, string(data)))
}
Loading
Loading