mirror of https://github.com/daffainfo/nuclei.git
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 testdev
parent
3eecdeff95
commit
cddae989f3
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue