Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions cmd/integration-test/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,30 @@ func (h *httpInteractshRequest) Execute(filePath string) error {
return expectResultsCount(results, 1, 2)
}

type httpInteractshWithPayloadsRequest struct{}

// Execute executes a test case and returns an error if occurred
func (h *httpInteractshWithPayloadsRequest) Execute(filePath string) error {
router := httprouter.New()
router.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
value := r.Header.Get("url")
if value != "" {
if resp, _ := retryablehttp.DefaultClient().Get(value); resp != nil {
_ = resp.Body.Close()
}
}
})
ts := httptest.NewServer(router)
defer ts.Close()

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

return expectResultsCount(results, 1, 3)
}

type httpDefaultMatcherCondition struct{}

// Execute executes a test case and returns an error if occurred
Expand Down
1 change: 1 addition & 0 deletions cmd/integration-test/interactsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import osutils "github.com/projectdiscovery/utils/os"
// All Interactsh related testcases
var interactshTestCases = []TestCaseInfo{
{Path: "protocols/http/interactsh.yaml", TestCase: &httpInteractshRequest{}, DisableOn: func() bool { return osutils.IsWindows() || osutils.IsOSX() }},
{Path: "protocols/http/interactsh-with-payloads.yaml", TestCase: &httpInteractshWithPayloadsRequest{}, DisableOn: func() bool { return true }},
{Path: "protocols/http/interactsh-stop-at-first-match.yaml", TestCase: &httpInteractshStopAtFirstMatchRequest{}, DisableOn: func() bool { return true }}, // disable this test for now
{Path: "protocols/http/default-matcher-condition.yaml", TestCase: &httpDefaultMatcherCondition{}, DisableOn: func() bool { return true }},
{Path: "protocols/http/interactsh-requests-mc-and.yaml", TestCase: &httpInteractshRequestsWithMCAnd{}},
Expand Down
24 changes: 24 additions & 0 deletions integration_tests/protocols/http/interactsh-with-payloads.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
id: interactsh-with-payloads

info:
name: Interactsh With Payloads Integration Test
author: dwisiswant0
severity: info
tags: test

http:
- method: GET
path:
- "{{BaseURL}}/?p={{p}}"
headers:
url: 'http://{{interactsh-url}}'
payloads:
p:
- a
- b
- c
matchers:
- type: word
part: interactsh_protocol
words:
- "dns"
8 changes: 8 additions & 0 deletions pkg/protocols/common/interactsh/interactsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d
} else {
data.Event.SetOperatorResult(result)
}
// ensure payload values are preserved for interactsh-only matches
data.Event.Lock()
if data.Event.OperatorsResult != nil && len(data.Event.OperatorsResult.PayloadValues) == 0 {
if payloads, ok := data.Event.InternalEvent["payloads"].(map[string]interface{}); ok {
data.Event.OperatorsResult.PayloadValues = payloads
}
}
data.Event.Unlock()

data.Event.Lock()
data.Event.Results = data.MakeResultFunc(data.Event)
Expand Down
27 changes: 23 additions & 4 deletions pkg/protocols/http/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,9 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV

// bounded worker-pool to avoid spawning one goroutine per payload
type task struct {
req *generatedRequest
updatedInput *contextargs.Context
req *generatedRequest
updatedInput *contextargs.Context
hasInteractMarkers bool
}

var workersWg sync.WaitGroup
Expand All @@ -268,11 +269,27 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV
continue
}
request.options.RateLimitTake()
hasInteractMatchers := interactsh.HasMatchers(request.CompiledOperators)
needsRequestEvent := hasInteractMatchers && request.NeedsRequestCondition()
select {
case <-spmHandler.Done():
spmHandler.Release()
continue
case spmHandler.ResultChan <- request.executeRequest(t.updatedInput, t.req, make(map[string]interface{}), false, wrappedCallback, 0):
case spmHandler.ResultChan <- request.executeRequest(t.updatedInput, t.req, make(map[string]interface{}), hasInteractMatchers, func(event *output.InternalWrappedEvent) {
if (t.hasInteractMarkers || needsRequestEvent) && request.options.Interactsh != nil {
requestData := &interactsh.RequestData{
MakeResultFunc: request.MakeResultEvent,
Event: event,
Operators: request.CompiledOperators,
MatchFunc: request.Match,
ExtractFunc: request.Extract,
}
allOASTUrls := httputils.GetInteractshURLSFromEvent(event.InternalEvent)
allOASTUrls = append(allOASTUrls, t.req.interactshURLs...)
request.options.Interactsh.RequestEvent(sliceutil.Dedupe(allOASTUrls), requestData)
}
wrappedCallback(event)
}, 0):
spmHandler.Release()
}
}
Expand Down Expand Up @@ -330,6 +347,7 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV
workersWg.Wait()
return err
}
hasInteractMarkers := interactsh.HasMarkers(inputData) || len(generatedHttpRequest.interactshURLs) > 0
if input.MetaInput.Input == "" {
input.MetaInput.Input = generatedHttpRequest.URL()
}
Expand All @@ -350,7 +368,7 @@ func (request *Request) executeParallelHTTP(input *contextargs.Context, dynamicV
return nil
}
return multierr.Combine(spmHandler.CombinedResults()...)
case tasks <- task{req: generatedHttpRequest, updatedInput: updatedInput}:
case tasks <- task{req: generatedHttpRequest, updatedInput: updatedInput, hasInteractMarkers: hasInteractMarkers}:
}
request.options.Progress.IncrementRequests()
}
Expand Down Expand Up @@ -1047,6 +1065,7 @@ func (request *Request) executeRequest(input *contextargs.Context, generatedRequ
request.pruneSignatureInternalValues(generatedRequest.meta)

interimEvent := generators.MergeMaps(generatedRequest.dynamicValues, finalEvent)
interimEvent["payloads"] = generatedRequest.meta
// add the request URL pattern to the event BEFORE operators execute
// so that interactsh events etc can also access it
if request.options.ExportReqURLPattern {
Expand Down
Loading