Add template option to disable merging target url path with raw request path (#3799)

* add template option to disable merging target url path with raw request path

* rename disable-merge-path -> disable-path-automerge
add integration test
dev
Ramana Reddy 2023-06-19 20:22:17 +05:30 committed by GitHub
parent 3eecdeff95
commit cddae989f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 12 deletions

View File

@ -0,0 +1,18 @@
id: test
info:
name: test
author: pdteam
severity: info
http:
- raw:
- |
GET /api/v1/test?id=123 HTTP/1.1
Host: {{Hostname}}
disable-path-automerge: true
matchers:
- type: status
status:
- 200

View File

@ -78,6 +78,7 @@ var httpTestcases = map[string]testutils.TestCase{
"http/cl-body-with-header.yaml": &httpCLBodyWithHeader{}, "http/cl-body-with-header.yaml": &httpCLBodyWithHeader{},
"http/save-extractor-values-to-file.yaml": &httpSaveExtractorValuesToFile{}, "http/save-extractor-values-to-file.yaml": &httpSaveExtractorValuesToFile{},
"http/cli-with-constants.yaml": &ConstantWithCliVar{}, "http/cli-with-constants.yaml": &ConstantWithCliVar{},
"http/disable-path-automerge.yaml": &httpDisablePathAutomerge{},
} }
type httpInteractshRequest struct{} type httpInteractshRequest struct{}
@ -1423,3 +1424,21 @@ func (h *ConstantWithCliVar) Execute(filePath string) error {
} }
return expectResultsCount(got, 1) return expectResultsCount(got, 1)
} }
// disable path automerge in raw request
type httpDisablePathAutomerge struct{}
// Execute executes a test case and returns an error if occurred
func (h *httpDisablePathAutomerge) Execute(filePath string) error {
router := httprouter.New()
router.GET("/api/v1/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, r.URL.Query().Get("id"))
})
ts := httptest.NewServer(router)
defer ts.Close()
got, err := testutils.RunNucleiTemplateAndGetResults(filePath, ts.URL+"/api/v1/user", debug)
if err != nil {
return err
}
return expectResultsCount(got, 1)
}

View File

@ -264,7 +264,7 @@ func (r *requestGenerator) generateRawRequest(ctx context.Context, rawRequest st
// in self contained requests baseURL is extracted from raw request itself // in self contained requests baseURL is extracted from raw request itself
rawRequestData, err = raw.ParseRawRequest(rawRequest, r.request.Unsafe) rawRequestData, err = raw.ParseRawRequest(rawRequest, r.request.Unsafe)
} else { } else {
rawRequestData, err = raw.Parse(rawRequest, baseURL, r.request.Unsafe) rawRequestData, err = raw.Parse(rawRequest, baseURL, r.request.Unsafe, r.request.DisablePathAutomerge)
} }
if err != nil { if err != nil {
return nil, errorutil.NewWithErr(err).Msgf("failed to parse raw request") return nil, errorutil.NewWithErr(err).Msgf("failed to parse raw request")

View File

@ -197,6 +197,9 @@ type Request struct {
// description: | // description: |
// DigestAuthPassword specifies the password for digest authentication // DigestAuthPassword specifies the password for digest authentication
DigestAuthPassword string `yaml:"digest-password,omitempty" json:"digest-password,omitempty" jsonschema:"title=specifies the password for digest authentication,description=Optional parameter which specifies the password for digest auth"` DigestAuthPassword string `yaml:"digest-password,omitempty" json:"digest-password,omitempty" jsonschema:"title=specifies the password for digest authentication,description=Optional parameter which specifies the password for digest auth"`
// description: |
// DisablePathAutomerge disables merging target url path with raw request path
DisablePathAutomerge bool `yaml:"disable-path-automerge,omitempty" json:"disable-path-automerge,omitempty" jsonschema:"title=disable auto merging of path,description=Disable merging target url path with raw request path"`
} }
// Options returns executer options for http request // Options returns executer options for http request

View File

@ -26,7 +26,7 @@ type Request struct {
} }
// Parse parses the raw request as supplied by the user // Parse parses the raw request as supplied by the user
func Parse(request string, inputURL *urlutil.URL, unsafe bool) (*Request, error) { func Parse(request string, inputURL *urlutil.URL, unsafe, disablePathAutomerge bool) (*Request, error) {
rawrequest, err := readRawRequest(request, unsafe) rawrequest, err := readRawRequest(request, unsafe)
if err != nil { if err != nil {
return nil, err return nil, err
@ -45,6 +45,9 @@ func Parse(request string, inputURL *urlutil.URL, unsafe bool) (*Request, error)
return nil, errorutil.NewWithErr(err).WithTag("raw").Msgf("failed to parse url %v from template", rawrequest.Path) return nil, errorutil.NewWithErr(err).WithTag("raw").Msgf("failed to parse url %v from template", rawrequest.Path)
} }
cloned := inputURL.Clone() cloned := inputURL.Clone()
if disablePathAutomerge {
cloned.Path = ""
}
parseErr := cloned.MergePath(urlx.GetRelativePath(), true) parseErr := cloned.MergePath(urlx.GetRelativePath(), true)
if parseErr != nil { if parseErr != nil {
return nil, errorutil.NewWithTag("raw", "could not automergepath for template path %v", urlx.GetRelativePath()).Wrap(parseErr) return nil, errorutil.NewWithTag("raw", "could not automergepath for template path %v", urlx.GetRelativePath()).Wrap(parseErr)
@ -71,6 +74,9 @@ func Parse(request string, inputURL *urlutil.URL, unsafe bool) (*Request, error)
} }
} }
} else { } else {
if disablePathAutomerge {
cloned.Path = ""
}
err = cloned.MergePath(rawrequest.Path, true) err = cloned.MergePath(rawrequest.Path, true)
if err != nil { if err != nil {
return nil, errorutil.NewWithErr(err).WithTag("raw").Msgf("failed to automerge %v from unsafe template", rawrequest.Path) return nil, errorutil.NewWithErr(err).WithTag("raw").Msgf("failed to automerge %v from unsafe template", rawrequest.Path)
@ -81,6 +87,9 @@ func Parse(request string, inputURL *urlutil.URL, unsafe bool) (*Request, error)
default: default:
cloned := inputURL.Clone() cloned := inputURL.Clone()
if disablePathAutomerge {
cloned.Path = ""
}
parseErr := cloned.MergePath(rawrequest.Path, true) parseErr := cloned.MergePath(rawrequest.Path, true)
if parseErr != nil { if parseErr != nil {
return nil, errorutil.NewWithTag("raw", "could not automergepath for template path %v", rawrequest.Path).Wrap(parseErr) return nil, errorutil.NewWithTag("raw", "could not automergepath for template path %v", rawrequest.Path).Wrap(parseErr)

View File

@ -14,32 +14,32 @@ Origin: {{BaseURL}}
Connection: close Connection: close
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: en-US,en;q=0.9`, parseURL(t, "https://example.com:8080"), false) Accept-Language: en-US,en;q=0.9`, parseURL(t, "https://example.com:8080"), false, false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:8080/gg/phpinfo.php", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/gg/phpinfo.php", request.FullURL, "Could not parse request url correctly")
require.Equal(t, "/gg/phpinfo.php", request.Path, "Could not parse request path correctly") require.Equal(t, "/gg/phpinfo.php", request.Path, "Could not parse request path correctly")
t.Run("path-suffix", func(t *testing.T) { t.Run("path-suffix", func(t *testing.T) {
request, err := Parse(`GET /hello HTTP/1.1 request, err := Parse(`GET /hello HTTP/1.1
Host: {{Hostname}}`, parseURL(t, "https://example.com:8080/test"), false) Host: {{Hostname}}`, parseURL(t, "https://example.com:8080/test"), false, false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:8080/test/hello", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/test/hello", request.FullURL, "Could not parse request url correctly")
}) })
t.Run("query-values", func(t *testing.T) { t.Run("query-values", func(t *testing.T) {
request, err := Parse(`GET ?username=test&password=test HTTP/1.1 request, err := Parse(`GET ?username=test&password=test HTTP/1.1
Host: {{Hostname}}:123`, parseURL(t, "https://example.com:8080/test"), false) Host: {{Hostname}}:123`, parseURL(t, "https://example.com:8080/test"), false, false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
// url.values are sorted to avoid randomness of using maps // url.values are sorted to avoid randomness of using maps
require.Equal(t, "https://example.com:8080/test?password=test&username=test", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/test?password=test&username=test", request.FullURL, "Could not parse request url correctly")
request, err = Parse(`GET ?username=test&password=test HTTP/1.1 request, err = Parse(`GET ?username=test&password=test HTTP/1.1
Host: {{Hostname}}:123`, parseURL(t, "https://example.com:8080/test/"), false) Host: {{Hostname}}:123`, parseURL(t, "https://example.com:8080/test/"), false, false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:8080/test/?password=test&username=test", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/test/?password=test&username=test", request.FullURL, "Could not parse request url correctly")
request, err = Parse(`GET /?username=test&password=test HTTP/1.1 request, err = Parse(`GET /?username=test&password=test HTTP/1.1
Host: {{Hostname}}:123`, parseURL(t, "https://example.com:8080/test/"), false) Host: {{Hostname}}:123`, parseURL(t, "https://example.com:8080/test/"), false, false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "https://example.com:8080/test/?password=test&username=test", request.FullURL, "Could not parse request url correctly") require.Equal(t, "https://example.com:8080/test/?password=test&username=test", request.FullURL, "Could not parse request url correctly")
}) })
@ -51,7 +51,7 @@ Host: {{Hostname}}
Authorization: Basic {{base64('username:password')}} Authorization: Basic {{base64('username:password')}}
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0
Accept-Language: en-US,en;q=0.9 Accept-Language: en-US,en;q=0.9
Connection: close`, parseURL(t, "https://test.com"), false) Connection: close`, parseURL(t, "https://test.com"), false, false)
require.Nil(t, err, "could not parse GET request") require.Nil(t, err, "could not parse GET request")
require.Equal(t, "GET", request.Method, "Could not parse GET method request correctly") require.Equal(t, "GET", request.Method, "Could not parse GET method request correctly")
require.Equal(t, "/manager/html", request.Path, "Could not parse request path correctly") require.Equal(t, "/manager/html", request.Path, "Could not parse request path correctly")
@ -61,7 +61,7 @@ Host: {{Hostname}}
Content-Type: application/x-www-form-urlencoded Content-Type: application/x-www-form-urlencoded
Connection: close Connection: close
username=admin&password=login`, parseURL(t, "https://test.com"), false) username=admin&password=login`, parseURL(t, "https://test.com"), false, false)
require.Nil(t, err, "could not parse POST request") require.Nil(t, err, "could not parse POST request")
require.Equal(t, "POST", request.Method, "Could not parse POST method request correctly") require.Equal(t, "POST", request.Method, "Could not parse POST method request correctly")
require.Equal(t, "username=admin&password=login", request.Data, "Could not parse request data correctly") require.Equal(t, "username=admin&password=login", request.Data, "Could not parse request data correctly")
@ -73,13 +73,13 @@ Host: {{Hostname}}
Authorization: Basic {{base64('username:password')}} Authorization: Basic {{base64('username:password')}}
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0
Accept-Language: en-US,en;q=0.9 Accept-Language: en-US,en;q=0.9
Connection: close`, parseURL(t, "https://test.com/test/"), true) Connection: close`, parseURL(t, "https://test.com/test/"), true, false)
require.Nil(t, err, "could not parse unsafe request") require.Nil(t, err, "could not parse unsafe request")
require.Contains(t, string(request.UnsafeRawBytes), "GET /test/manager/html", "Could not parse unsafe method request path correctly") require.Contains(t, string(request.UnsafeRawBytes), "GET /test/manager/html", "Could not parse unsafe method request path correctly")
request, err = Parse(`GET ?a=b HTTP/1.1 request, err = Parse(`GET ?a=b HTTP/1.1
Host: {{Hostname}} Host: {{Hostname}}
Origin: {{BaseURL}}`, parseURL(t, "https://test.com/test.js"), true) Origin: {{BaseURL}}`, parseURL(t, "https://test.com/test.js"), true, false)
require.Nil(t, err, "could not parse unsafe request") require.Nil(t, err, "could not parse unsafe request")
require.Contains(t, string(request.UnsafeRawBytes), "GET /test.js?a=b", "Could not parse unsafe method request path correctly") require.Contains(t, string(request.UnsafeRawBytes), "GET /test.js?a=b", "Could not parse unsafe method request path correctly")
} }
@ -87,13 +87,26 @@ Connection: close`, parseURL(t, "https://test.com/test/"), true)
func TestTryFillCustomHeaders(t *testing.T) { func TestTryFillCustomHeaders(t *testing.T) {
testValue := "GET /manager/html HTTP/1.1\r\nHost: Test\r\n" testValue := "GET /manager/html HTTP/1.1\r\nHost: Test\r\n"
expected := "GET /test/manager/html HTTP/1.1\r\nHost: Test\r\ntest: test\r\n" expected := "GET /test/manager/html HTTP/1.1\r\nHost: Test\r\ntest: test\r\n"
request, err := Parse(testValue, parseURL(t, "https://test.com/test/"), true) request, err := Parse(testValue, parseURL(t, "https://test.com/test/"), true, false)
require.Nil(t, err, "could not parse unsafe request") require.Nil(t, err, "could not parse unsafe request")
err = request.TryFillCustomHeaders([]string{"test: test"}) err = request.TryFillCustomHeaders([]string{"test: test"})
require.Nil(t, err, "could not add custom headers") require.Nil(t, err, "could not add custom headers")
require.Equal(t, expected, string(request.UnsafeRawBytes), "actual value and expected value are different") require.Equal(t, expected, string(request.UnsafeRawBytes), "actual value and expected value are different")
} }
func TestDisableMergePath(t *testing.T) {
request, err := Parse(` GET /api/v1/id=123 HTTP/1.1
Host: {{Hostname}}`, parseURL(t, "https://example.com/api/v1/user"), false, true)
require.Nil(t, err, "could not parse GET request with disable merge path")
require.Equal(t, "https://example.com/api/v1/id=123", request.FullURL, "Could not parse request url with disable merge path correctly")
request, err = Parse(` GET /api/v1/id=123 HTTP/1.1
Host: {{Hostname}}`, parseURL(t, "https://example.com/api/v1/user"), false, false)
require.Nil(t, err, "could not parse GET request with merge path")
require.Equal(t, "https://example.com/api/v1/user/api/v1/id=123", request.FullURL, "Could not parse request url with merge path correctly")
}
func parseURL(t *testing.T, inputurl string) *urlutil.URL { func parseURL(t *testing.T, inputurl string) *urlutil.URL {
urlx, err := urlutil.Parse(inputurl) urlx, err := urlutil.Parse(inputurl)
if err != nil { if err != nil {