diff --git a/cmd/integration-test/http.go b/cmd/integration-test/http.go index 41e1910a86..b4f957e692 100644 --- a/cmd/integration-test/http.go +++ b/cmd/integration-test/http.go @@ -82,6 +82,8 @@ var httpTestcases = []TestCaseInfo{ {Path: "protocols/http/multi-request.yaml", TestCase: &httpMultiRequest{}}, {Path: "protocols/http/http-matcher-extractor-dy-extractor.yaml", TestCase: &httpMatcherExtractorDynamicExtractor{}}, {Path: "protocols/http/multi-http-var-sharing.yaml", TestCase: &httpMultiVarSharing{}}, + {Path: "protocols/http/raw-path-single-slash.yaml", TestCase: &httpRawPathSingleSlash{}}, + {Path: "protocols/http/raw-unsafe-path-single-slash.yaml", TestCase: &httpRawUnsafePathSingleSlash{}}, } type httpMultiVarSharing struct{} @@ -1560,3 +1562,53 @@ func (h *httpMultiRequest) Execute(filePath string) error { return expectResultsCount(results, 1) } + +type httpRawPathSingleSlash struct{} + +func (h *httpRawPathSingleSlash) Execute(filepath string) error { + expectedPath := "/index.php" + results, err := testutils.RunNucleiBinaryAndGetCombinedOutput(debug, []string{"-t", filepath, "-u", "scanme.sh/index.php", "-debug-req"}) + if err != nil { + return err + } + + var actual string + for _, v := range strings.Split(results, "\n") { + if strings.Contains(v, "GET") { + parts := strings.Fields(v) + if len(parts) == 3 { + actual = parts[1] + } + } + } + + if actual != expectedPath { + return fmt.Errorf("expected: %v\n\nactual: %v", expectedPath, actual) + } + return nil +} + +type httpRawUnsafePathSingleSlash struct{} + +func (h *httpRawUnsafePathSingleSlash) Execute(filepath string) error { + expectedPath := "/index.php" + results, err := testutils.RunNucleiBinaryAndGetCombinedOutput(debug, []string{"-t", filepath, "-u", "scanme.sh/index.php", "-debug-req"}) + if err != nil { + return err + } + + var actual string + for _, v := range strings.Split(results, "\n") { + if strings.Contains(v, "GET") { + parts := strings.Fields(v) + if len(parts) == 3 { + actual = parts[1] + } + } + } + + if actual != expectedPath { + return fmt.Errorf("expected: %v\n\nactual: %v", expectedPath, actual) + } + return nil +} diff --git a/integration_tests/protocols/http/raw-path-single-slash.yaml b/integration_tests/protocols/http/raw-path-single-slash.yaml new file mode 100644 index 0000000000..4ea491f4be --- /dev/null +++ b/integration_tests/protocols/http/raw-path-single-slash.yaml @@ -0,0 +1,13 @@ +id: raw-path-single-slash + +info: + name: Test RAW HTTP Template with single slash + author: pdteam + severity: info + +requests: + - raw: + - | + GET / HTTP/1.1 + Host: {{Hostname}} + Origin: {{BaseURL}} \ No newline at end of file diff --git a/integration_tests/protocols/http/raw-unsafe-path-single-slash.yaml b/integration_tests/protocols/http/raw-unsafe-path-single-slash.yaml new file mode 100644 index 0000000000..a356d18e80 --- /dev/null +++ b/integration_tests/protocols/http/raw-unsafe-path-single-slash.yaml @@ -0,0 +1,15 @@ +id: raw-unsafe-path-single-slash + +info: + name: Test RAW Unsafe HTTP Template with single slash + author: pdteam + severity: info + +requests: + - raw: + - |+ + GET / HTTP/1.1 + Host: {{Hostname}} + Origin: {{BaseURL}} + + unsafe: true \ No newline at end of file diff --git a/pkg/protocols/http/raw/raw.go b/pkg/protocols/http/raw/raw.go index a1eb544a20..2ade9de88d 100644 --- a/pkg/protocols/http/raw/raw.go +++ b/pkg/protocols/http/raw/raw.go @@ -82,6 +82,13 @@ func Parse(request string, inputURL *urlutil.URL, unsafe, disablePathAutomerge b } } } else { + // Edgecase if raw request is + // GET / HTTP/1.1 + //use case: https://github.com/projectdiscovery/nuclei/issues/4921 + if rawrequest.Path == "/" && cloned.Path != "" { + rawrequest.Path = "" + } + if disablePathAutomerge { cloned.Path = "" } @@ -97,6 +104,13 @@ func Parse(request string, inputURL *urlutil.URL, unsafe, disablePathAutomerge b default: cloned := inputURL.Clone() cloned.Params.IncludeEquals = true + // Edgecase if raw request is + // GET / HTTP/1.1 + //use case: https://github.com/projectdiscovery/nuclei/issues/4921 + if rawrequest.Path == "/" { + rawrequest.Path = "" + } + if disablePathAutomerge { cloned.Path = "" }