Skip to content

Commit

Permalink
Clone Input when the workflow execution forks (projectdiscovery#5621)
Browse files Browse the repository at this point in the history
* clone Input when the workflow forks, add integration test

* fix line endings
  • Loading branch information
tovask authored Sep 19, 2024
1 parent 4cd065d commit 6347efa
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 1 deletion.
40 changes: 40 additions & 0 deletions cmd/integration-test/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/templates"
"github.com/projectdiscovery/nuclei/v3/pkg/templates/signer"
"github.com/projectdiscovery/nuclei/v3/pkg/testutils"
sliceutil "github.com/projectdiscovery/utils/slice"
)

var workflowTestcases = []TestCaseInfo{
Expand All @@ -25,6 +26,7 @@ var workflowTestcases = []TestCaseInfo{
{Path: "workflow/dns-value-share-workflow.yaml", TestCase: &workflowDnsKeyValueShare{}},
{Path: "workflow/code-value-share-workflow.yaml", TestCase: &workflowCodeKeyValueShare{}, DisableOn: isCodeDisabled}, // isCodeDisabled declared in code.go
{Path: "workflow/multiprotocol-value-share-workflow.yaml", TestCase: &workflowMultiProtocolKeyValueShare{}},
{Path: "workflow/multimatch-value-share-workflow.yaml", TestCase: &workflowMultiMatchKeyValueShare{}},
{Path: "workflow/shared-cookie.yaml", TestCase: &workflowSharedCookies{}},
}

Expand Down Expand Up @@ -229,6 +231,44 @@ func (h *workflowMultiProtocolKeyValueShare) Execute(filePath string) error {
return expectResultsCount(results, 2)
}

type workflowMultiMatchKeyValueShare struct{}

// Execute executes a test case and returns an error if occurred
func (h *workflowMultiMatchKeyValueShare) Execute(filePath string) error {
var receivedData []string
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprintf(w, "This is test matcher text")
})
router.GET("/path1", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprintf(w, "href=\"test-value-%s\"", r.URL.Query().Get("v"))
})
router.GET("/path2", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
body, _ := io.ReadAll(r.Body)
receivedData = append(receivedData, string(body))
fmt.Fprintf(w, "test-value")
})
ts := httptest.NewServer(router)
defer ts.Close()

results, err := testutils.RunNucleiWorkflowAndGetResults(filePath, ts.URL, debug)
if err != nil {
return err
}

// Check if we received the data from both request to /path1 and it is not overwritten by the later one.
// They will appear in brackets because of another bug: https://github.com/orgs/projectdiscovery/discussions/3766
if !sliceutil.Contains(receivedData, "[test-value-1]") || !sliceutil.Contains(receivedData, "[test-value-2]") {
return fmt.Errorf(
"incorrect data: did not receive both extracted data from the first request!\nReceived Data:\n\t%s\nResults:\n\t%s",
strings.Join(receivedData, "\n\t"),
strings.Join(results, "\n\t"),
)
}
// The number of expected results is 3: the workflow's Matcher Name based condition check forwards both match, and the other branch with simple subtemplates goes with one
return expectResultsCount(results, 3)
}

type workflowSharedCookies struct{}

// Execute executes a test case and returns an error if occurred
Expand Down
23 changes: 23 additions & 0 deletions integration_tests/workflow/multimatch-value-share-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
id: multimatch-value-share-template

info:
name: MultiMatch Value Share Template
author: tovask
severity: info

http:
- path:
- "{{BaseURL}}/path1?v=1"
- "{{BaseURL}}/path1?v=2"
matchers:
- type: word
name: test-matcher
words:
- "href"
extractors:
- type: regex
part: body
name: extracted
regex:
- 'href="(.*)"'
group: 1
21 changes: 21 additions & 0 deletions integration_tests/workflow/multimatch-value-share-workflow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
id: multimatch-value-share-workflow

info:
name: MultiMatch Value Share Workflow
author: tovask
severity: info
description: Workflow to test value sharing when multiple matches occur in the extractor template

workflows:
- template: workflow/multimatch-value-share-template.yaml
subtemplates:
- template: workflow/match-1.yaml
subtemplates:
- template: workflow/http-value-share-template-2.yaml
- template: workflow/multimatch-value-share-template.yaml
matchers:
- name: test-matcher
subtemplates:
- template: workflow/match-1.yaml
subtemplates:
- template: workflow/http-value-share-template-2.yaml
3 changes: 2 additions & 1 deletion pkg/core/workflow_execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, ctx *scan
defer swg.Done()

// create a new context with the same input but with unset callbacks
subCtx := scan.NewScanContext(ctx.Context(), ctx.Input)
// clone the Input so that other parallel executions won't overwrite the shared variables when subsequent templates are running
subCtx := scan.NewScanContext(ctx.Context(), ctx.Input.Clone())
if err := e.runWorkflowStep(subtemplate, subCtx, results, swg, w); err != nil {
gologger.Warning().Msgf(workflowStepExecutionError, subtemplate.Template, err)
}
Expand Down

0 comments on commit 6347efa

Please sign in to comment.