fix(multiproto): missing previous InternalEvents output when ExecuteWithResults (#5967)

Signed-off-by: Dwi Siswanto <git@dw1.io>
This commit is contained in:
Dwi Siswanto 2025-01-14 17:00:17 +07:00 committed by GitHub
parent a7f7616db9
commit 2450ecb503
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -2,6 +2,7 @@ package multiproto
import (
"strconv"
"strings"
"sync/atomic"
"github.com/projectdiscovery/nuclei/v3/pkg/output"
@ -9,6 +10,7 @@ import (
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
"github.com/projectdiscovery/nuclei/v3/pkg/scan"
"github.com/projectdiscovery/nuclei/v3/pkg/templates/types"
mapsutil "github.com/projectdiscovery/utils/maps"
stringsutil "github.com/projectdiscovery/utils/strings"
)
@ -60,11 +62,46 @@ func (m *MultiProtocol) ExecuteWithResults(ctx *scan.ScanContext) error {
m.options.GetTemplateCtx(ctx.Input.MetaInput).Set(key, value)
})
// callback to process results from all protocols
multiProtoCallback := func(event *output.InternalWrappedEvent) {
previous := mapsutil.NewSyncLockMap[string, any]()
// template context: contains values extracted using `internal` extractor from previous protocols
// these values are extracted from each protocol in queue and are passed to next protocol in queue
// instead of adding seperator field to handle such cases these values are appended to `dynamicValues` (which are meant to be used in workflows)
// this makes it possible to use multi protocol templates in workflows
// Note: internal extractor values take precedence over dynamicValues from workflows (i.e other templates in workflow)
// execute all protocols in the queue
for _, req := range m.requests {
select {
case <-ctx.Context().Done():
return ctx.Context().Err()
default:
}
inputItem := ctx.Input.Clone()
if m.options.InputHelper != nil && ctx.Input.MetaInput.Input != "" {
if inputItem.MetaInput.Input = m.options.InputHelper.Transform(inputItem.MetaInput.Input, req.Type()); inputItem.MetaInput.Input == "" {
return nil
}
}
// FIXME: this hack of using hash to get templateCtx has known issues scan context based approach should be adopted ASAP
values := m.options.GetTemplateCtx(inputItem.MetaInput).GetAll()
err := req.ExecuteWithResults(inputItem, output.InternalEvent(values), output.InternalEvent(previous.GetAll()), func(event *output.InternalWrappedEvent) {
if event == nil {
return
}
ID := req.GetID()
if ID != "" {
builder := &strings.Builder{}
for k, v := range event.InternalEvent {
builder.WriteString(ID)
builder.WriteString("_")
builder.WriteString(k)
_ = previous.Set(builder.String(), v)
builder.Reset()
}
}
// log event and generate result for the event
ctx.LogEvent(event)
// export dynamic values from operators (i.e internal:true)
@ -94,30 +131,7 @@ func (m *MultiProtocol) ExecuteWithResults(ctx *scan.ScanContext) error {
// evaluate all variables after execution of each protocol
variableMap := m.options.Variables.Evaluate(m.options.GetTemplateCtx(ctx.Input.MetaInput).GetAll())
m.options.GetTemplateCtx(ctx.Input.MetaInput).Merge(variableMap) // merge all variables into template context
}
// template context: contains values extracted using `internal` extractor from previous protocols
// these values are extracted from each protocol in queue and are passed to next protocol in queue
// instead of adding seperator field to handle such cases these values are appended to `dynamicValues` (which are meant to be used in workflows)
// this makes it possible to use multi protocol templates in workflows
// Note: internal extractor values take precedence over dynamicValues from workflows (i.e other templates in workflow)
// execute all protocols in the queue
for _, req := range m.requests {
select {
case <-ctx.Context().Done():
return ctx.Context().Err()
default:
}
inputItem := ctx.Input.Clone()
if m.options.InputHelper != nil && ctx.Input.MetaInput.Input != "" {
if inputItem.MetaInput.Input = m.options.InputHelper.Transform(inputItem.MetaInput.Input, req.Type()); inputItem.MetaInput.Input == "" {
return nil
}
}
// FIXME: this hack of using hash to get templateCtx has known issues scan context based approach should be adopted ASAP
values := m.options.GetTemplateCtx(inputItem.MetaInput).GetAll()
err := req.ExecuteWithResults(inputItem, output.InternalEvent(values), nil, multiProtoCallback)
})
// in case of fatal error skip execution of next protocols
if err != nil {
// always log errors