diff --git a/integration_tests/http/disable-redirects.yaml b/integration_tests/http/disable-redirects.yaml new file mode 100644 index 00000000..ec6616bb --- /dev/null +++ b/integration_tests/http/disable-redirects.yaml @@ -0,0 +1,17 @@ +id: basic-disable-redirects + +info: + name: Basic GET Redirects Request + author: pdteam + severity: info + +requests: + - method: GET + path: + - "{{BaseURL}}" + redirects: true + max-redirects: 2 + matchers: + - type: word + words: + - "This is test disable redirects matcher text" diff --git a/v2/cmd/integration-test/http.go b/v2/cmd/integration-test/http.go index 11499a59..6e8cb575 100644 --- a/v2/cmd/integration-test/http.go +++ b/v2/cmd/integration-test/http.go @@ -20,7 +20,8 @@ import ( var httpTestcases = map[string]testutils.TestCase{ "http/get-headers.yaml": &httpGetHeaders{}, "http/get-query-string.yaml": &httpGetQueryString{}, - "http/get-redirects.yaml": &httpGetRedirects{}, + "http/get-redirects.yaml": &httpGetRedirects{}, + "http/disable-redirects.yaml": &httpDisableRedirects{}, "http/get.yaml": &httpGet{}, "http/post-body.yaml": &httpPostBody{}, "http/post-json-body.yaml": &httpPostJSONBody{}, @@ -160,6 +161,28 @@ func (h *httpGetRedirects) Execute(filePath string) error { return expectResultsCount(results, 1) } +type httpDisableRedirects struct{} + +// Execute executes a test case and returns an error if occurred +func (h *httpDisableRedirects) Execute(filePath string) error { + router := httprouter.New() + router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + http.Redirect(w, r, "/redirected", http.StatusMovedPermanently) + }) + router.GET("/redirected", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + fmt.Fprintf(w, "This is test redirects matcher text") + }) + ts := httptest.NewServer(router) + defer ts.Close() + + results, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL, debug, "-dr", "-sresp") + if err != nil { + return err + } + + return expectResultsCount(results, 0) +} + type httpGet struct{} // Execute executes a test case and returns an error if occurred diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go index 44139e99..ca5d7363 100644 --- a/v2/cmd/nuclei/main.go +++ b/v2/cmd/nuclei/main.go @@ -146,6 +146,7 @@ on extensive configurability, massive extensibility and ease of use.`) flagSet.StringVarP(&options.ClientKeyFile, "client-key", "ck", "", "client key file (PEM-encoded) used for authenticating against scanned hosts"), flagSet.StringVarP(&options.ClientCAFile, "client-ca", "ca", "", "client certificate authority file (PEM-encoded) used for authenticating against scanned hosts"), flagSet.BoolVar(&options.ZTLS, "ztls", false, "Use ztls library with autofallback to standard one for tls13"), + flagSet.BoolVarP(&options.DisableRedirects, "disable-redirects", "dr", false, "disable redirects for http templates"), ) createGroup(flagSet, "interactsh", "interactsh", @@ -240,10 +241,10 @@ func cleanupOldResumeFiles() { return } filter := fileutil.FileFilters{ - OlderThan: 24*time.Hour*10, // cleanup on the 10th day + OlderThan: 24 * time.Hour * 10, // cleanup on the 10th day Prefix: "resume-", } - _=fileutil.DeleteFilesOlderThan(root, filter) + _ = fileutil.DeleteFilesOlderThan(root, filter) } func createGroup(flagSet *goflags.FlagSet, groupName, description string, flags ...*goflags.FlagData) { flagSet.SetGroup(groupName, description) diff --git a/v2/internal/runner/options.go b/v2/internal/runner/options.go index f6c1a516..5d2de89f 100644 --- a/v2/internal/runner/options.go +++ b/v2/internal/runner/options.go @@ -112,6 +112,9 @@ func validateOptions(options *types.Options) error { if options.Verbose && options.Silent { return errors.New("both verbose and silent mode specified") } + if options.FollowRedirects && options.DisableRedirects { + return errors.New("both follow redirects and disable redirects specified") + } // loading the proxy server list from file or cli and test the connectivity if err := loadProxyServers(options); err != nil { return err diff --git a/v2/pkg/protocols/http/httpclientpool/clientpool.go b/v2/pkg/protocols/http/httpclientpool/clientpool.go index f8439dc6..81f25885 100644 --- a/v2/pkg/protocols/http/httpclientpool/clientpool.go +++ b/v2/pkg/protocols/http/httpclientpool/clientpool.go @@ -163,6 +163,11 @@ func wrappedGet(options *types.Options, configuration *Configuration) (*retryabl followRedirects = true maxRedirects = forceMaxRedirects } + if options.DisableRedirects { + options.FollowRedirects = false + followRedirects = false + maxRedirects = 0 + } // override connection's settings if required if configuration.Connection != nil { disableKeepAlives = configuration.Connection.DisableKeepAlive diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go index 1507d107..3b0280e5 100644 --- a/v2/pkg/types/types.go +++ b/v2/pkg/types/types.go @@ -207,11 +207,13 @@ type Options struct { // Use ZTLS library ZTLS bool // EnablePprof enables exposing pprof runtime information with a webserver. - EnablePprof bool + EnablePprof bool // StoreResponse stores received response to output directory - StoreResponse bool + StoreResponse bool // StoreResponseDir stores received response to custom directory StoreResponseDir string + // DisableRedirects disables following redirects for http request module + DisableRedirects bool } func (options *Options) AddVarPayload(key string, value interface{}) {