From b4b769d501bff10005c4d2d74889799f41ed2061 Mon Sep 17 00:00:00 2001 From: Tarun Koyalwar Date: Fri, 18 Aug 2023 02:37:35 +0530 Subject: [PATCH 1/2] fix logic bug in request[s] condition --- v2/pkg/protocols/http/request.go | 11 +++++++++-- v2/pkg/protocols/http/utils.go | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/v2/pkg/protocols/http/request.go b/v2/pkg/protocols/http/request.go index aed626ff54..f1a49e27fa 100644 --- a/v2/pkg/protocols/http/request.go +++ b/v2/pkg/protocols/http/request.go @@ -35,6 +35,7 @@ import ( templateTypes "github.com/projectdiscovery/nuclei/v2/pkg/templates/types" "github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/rawhttp" + sliceutil "github.com/projectdiscovery/utils/slice" stringsutil "github.com/projectdiscovery/utils/strings" urlutil "github.com/projectdiscovery/utils/url" ) @@ -342,6 +343,7 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa var gotDynamicValues map[string][]string var requestErr error + for { // returns two values, error and skip, which skips the execution for the request instance. executeFunc := func(data string, payloads, dynamicValue map[string]interface{}) (bool, error) { @@ -375,7 +377,10 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa } var gotMatches bool err = request.executeRequest(input, generatedHttpRequest, previous, hasInteractMatchers, func(event *output.InternalWrappedEvent) { - if hasInteractMarkers && hasInteractMatchers && request.options.Interactsh != nil { + // a special case where operators has interactsh matchers and multiple request are made + // ex: status_code_2 , interactsh_protocol (from 1st request) etc + needsRequestEvent := interactsh.HasMatchers(request.CompiledOperators) && request.NeedsRequestCondition() + if (hasInteractMarkers || needsRequestEvent) && request.options.Interactsh != nil { requestData := &interactsh.RequestData{ MakeResultFunc: request.MakeResultEvent, Event: event, @@ -383,7 +388,9 @@ func (request *Request) ExecuteWithResults(input *contextargs.Context, dynamicVa MatchFunc: request.Match, ExtractFunc: request.Extract, } - request.options.Interactsh.RequestEvent(generatedHttpRequest.interactshURLs, requestData) + allOASTUrls := getInteractshURLsFromEvent(event.InternalEvent) + allOASTUrls = append(allOASTUrls, generatedHttpRequest.interactshURLs...) + request.options.Interactsh.RequestEvent(sliceutil.Dedupe(allOASTUrls), requestData) gotMatches = request.options.Interactsh.AlreadyMatched(requestData) } // Add the extracts to the dynamic values if any. diff --git a/v2/pkg/protocols/http/utils.go b/v2/pkg/protocols/http/utils.go index 24d34d2214..a706b8b468 100644 --- a/v2/pkg/protocols/http/utils.go +++ b/v2/pkg/protocols/http/utils.go @@ -14,7 +14,9 @@ import ( "golang.org/x/text/transform" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators" + "github.com/projectdiscovery/nuclei/v2/pkg/types" "github.com/projectdiscovery/rawhttp" + mapsutil "github.com/projectdiscovery/utils/maps" stringsutil "github.com/projectdiscovery/utils/strings" ) @@ -163,3 +165,16 @@ func isContentTypeGbk(contentType string) bool { contentType = strings.ToLower(contentType) return stringsutil.ContainsAny(contentType, "gbk", "gb2312", "gb18030") } + +// if template contains more than 1 request and matchers require requestcondition from +// both requests , then we need to request for event from interactsh even if current request +// doesnot use interactsh url in it +func getInteractshURLsFromEvent(event map[string]interface{}) []string { + interactshUrls := map[string]struct{}{} + for k, v := range event { + if strings.HasPrefix(k, "interactsh-url") { + interactshUrls[types.ToString(v)] = struct{}{} + } + } + return mapsutil.GetKeys(interactshUrls) +} From 61fc7350d1aa9ae44e02ade55140c3a3ae07689a Mon Sep 17 00:00:00 2001 From: Tarun Koyalwar Date: Fri, 18 Aug 2023 02:49:05 +0530 Subject: [PATCH 2/2] add integration test --- .../http/interactsh-requests-mc-and.yaml | 27 +++++++++++++++++++ v2/cmd/integration-test/http.go | 10 +++++++ v2/cmd/integration-test/interactsh.go | 1 + 3 files changed, 38 insertions(+) create mode 100644 integration_tests/http/interactsh-requests-mc-and.yaml diff --git a/integration_tests/http/interactsh-requests-mc-and.yaml b/integration_tests/http/interactsh-requests-mc-and.yaml new file mode 100644 index 0000000000..e9eea1be61 --- /dev/null +++ b/integration_tests/http/interactsh-requests-mc-and.yaml @@ -0,0 +1,27 @@ +id: interactsh-requests-mc-and + +info: + name: interactsh multi request matcher condition + author: pdteam + severity: info + +requests: + - raw: + - | + GET /api/geoping/{{interactsh-url}} HTTP/1.1 + Host: {{Hostname}} + + - | + GET / HTTP/1.1 + Host: {{Hostname}} + + matchers-condition: and + matchers: + - type: word + part: interactsh_protocol # Confirms the DNS Interaction + words: + - "dns" + + - type: dsl + dsl: + - "status_code_2 == 200" \ No newline at end of file diff --git a/v2/cmd/integration-test/http.go b/v2/cmd/integration-test/http.go index d76125a281..0409c2b579 100644 --- a/v2/cmd/integration-test/http.go +++ b/v2/cmd/integration-test/http.go @@ -1465,3 +1465,13 @@ func (h *httpDisablePathAutomerge) Execute(filePath string) error { } return expectResultsCount(got, 2) } + +type httpInteractshRequestsWithMCAnd struct{} + +func (h *httpInteractshRequestsWithMCAnd) Execute(filePath string) error { + got, err := testutils.RunNucleiTemplateAndGetResults(filePath, "honey.scanme.sh", debug) + if err != nil { + return err + } + return expectResultsCount(got, 1) +} diff --git a/v2/cmd/integration-test/interactsh.go b/v2/cmd/integration-test/interactsh.go index d163fef806..5d0e82dfb9 100644 --- a/v2/cmd/integration-test/interactsh.go +++ b/v2/cmd/integration-test/interactsh.go @@ -7,4 +7,5 @@ var interactshTestCases = []TestCaseInfo{ {Path: "http/interactsh.yaml", TestCase: &httpInteractshRequest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "http/interactsh-stop-at-first-match.yaml", TestCase: &httpInteractshStopAtFirstMatchRequest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, {Path: "http/default-matcher-condition.yaml", TestCase: &httpDefaultMatcherCondition{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }}, + {Path: "http/interactsh-requests-mc-and.yaml", TestCase: &httpInteractshRequestsWithMCAnd{}}, }