diff --git a/pkg/output/format_screen.go b/pkg/output/format_screen.go index 3cdcec1e1..ff140d230 100644 --- a/pkg/output/format_screen.go +++ b/pkg/output/format_screen.go @@ -19,38 +19,63 @@ func (w *StandardWriter) formatScreen(output *ResultEvent) []byte { builder.WriteString(w.aurora.Cyan(output.Timestamp.Format("2006-01-02 15:04:05")).String()) builder.WriteString("] ") } - builder.WriteRune('[') - builder.WriteString(w.aurora.BrightGreen(output.TemplateID).String()) - - if output.MatcherName != "" { - builder.WriteString(":") - builder.WriteString(w.aurora.BrightGreen(output.MatcherName).Bold().String()) - } else if output.ExtractorName != "" { - builder.WriteString(":") - builder.WriteString(w.aurora.BrightGreen(output.ExtractorName).Bold().String()) - } - - if w.matcherStatus { - builder.WriteString("] [") - if !output.MatcherStatus { - builder.WriteString(w.aurora.Red("failed").String()) - } else { - builder.WriteString(w.aurora.Green("matched").String()) - } - } - if output.GlobalMatchers { + // For global matchers: [global-template-id:matcher-name] [global] [original-template-id] [http] [severity] + builder.WriteRune('[') + builder.WriteString(w.aurora.BrightGreen(output.GlobalTemplateID).String()) + + if output.MatcherName != "" { + builder.WriteString(":") + builder.WriteString(w.aurora.BrightGreen(output.MatcherName).Bold().String()) + } else if output.ExtractorName != "" { + builder.WriteString(":") + builder.WriteString(w.aurora.BrightGreen(output.ExtractorName).Bold().String()) + } + builder.WriteString("] [") builder.WriteString(w.aurora.BrightMagenta("global").String()) + + builder.WriteString("] [") + builder.WriteString(output.TemplateID) // Original template ID in white (no color) + + builder.WriteString("] [") + builder.WriteString(w.aurora.BrightBlue(output.Type).String()) + builder.WriteString("] ") + + builder.WriteString("[") + // Use global template severity instead of original template severity + builder.WriteString(w.severityColors(output.GlobalTemplateInfo.SeverityHolder.Severity)) + builder.WriteString("] ") + } else { + // For regular templates: [template-id:matcher-name] [http] [severity] + builder.WriteRune('[') + builder.WriteString(w.aurora.BrightGreen(output.TemplateID).String()) + + if output.MatcherName != "" { + builder.WriteString(":") + builder.WriteString(w.aurora.BrightGreen(output.MatcherName).Bold().String()) + } else if output.ExtractorName != "" { + builder.WriteString(":") + builder.WriteString(w.aurora.BrightGreen(output.ExtractorName).Bold().String()) + } + + if w.matcherStatus { + builder.WriteString("] [") + if !output.MatcherStatus { + builder.WriteString(w.aurora.Red("failed").String()) + } else { + builder.WriteString(w.aurora.Green("matched").String()) + } + } + + builder.WriteString("] [") + builder.WriteString(w.aurora.BrightBlue(output.Type).String()) + builder.WriteString("] ") + + builder.WriteString("[") + builder.WriteString(w.severityColors(output.Info.SeverityHolder.Severity)) + builder.WriteString("] ") } - - builder.WriteString("] [") - builder.WriteString(w.aurora.BrightBlue(output.Type).String()) - builder.WriteString("] ") - - builder.WriteString("[") - builder.WriteString(w.severityColors(output.Info.SeverityHolder.Severity)) - builder.WriteString("] ") } if output.Matched != "" { builder.WriteString(output.Matched) diff --git a/pkg/output/output.go b/pkg/output/output.go index 571bff782..475a6ea25 100644 --- a/pkg/output/output.go +++ b/pkg/output/output.go @@ -199,6 +199,12 @@ type ResultEvent struct { // GlobalMatchers identifies whether the matches was detected in the response // of another template's result event GlobalMatchers bool `json:"global-matchers,omitempty"` + // GlobalTemplateID is the ID of the global template that matched (only set when GlobalMatchers is true) + GlobalTemplateID string `json:"global-template-id,omitempty"` + // GlobalTemplatePath is the path of the global template that matched (only set when GlobalMatchers is true) + GlobalTemplatePath string `json:"global-template-path,omitempty"` + // GlobalTemplateInfo contains information block of the global template (only set when GlobalMatchers is true) + GlobalTemplateInfo model.Info `json:"global-template-info,omitempty"` // IssueTrackers is the metadata for issue trackers IssueTrackers map[string]IssueTrackerMetadata `json:"issue_trackers,omitempty"` diff --git a/pkg/protocols/http/operators.go b/pkg/protocols/http/operators.go index 298da25e1..8d235520b 100644 --- a/pkg/protocols/http/operators.go +++ b/pkg/protocols/http/operators.go @@ -173,30 +173,60 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent if value, ok := wrapped.InternalEvent["analyzer_details"]; ok { analyzerDetails = value.(string) } + + // For global matchers, use original template info and store global template info separately + var templateID, templatePath string + var templateInfo model.Info + var globalTemplateID, globalTemplatePath string + var globalTemplateInfo model.Info + + if isGlobalMatchers { + // Use original template information + templateID = types.ToString(wrapped.InternalEvent["origin-template-id"]) + templatePath = types.ToString(wrapped.InternalEvent["origin-template-path"]) + if originInfo := wrapped.InternalEvent["origin-template-info"]; originInfo != nil { + templateInfo = originInfo.(model.Info) + } + // Store global template information + globalTemplateID = types.ToString(wrapped.InternalEvent["template-id"]) + globalTemplatePath = types.ToString(wrapped.InternalEvent["template-path"]) + if globalInfo := wrapped.InternalEvent["template-info"]; globalInfo != nil { + globalTemplateInfo = globalInfo.(model.Info) + } + } else { + // Use current template information for non-global matchers + templateID = types.ToString(wrapped.InternalEvent["template-id"]) + templatePath = types.ToString(wrapped.InternalEvent["template-path"]) + templateInfo = wrapped.InternalEvent["template-info"].(model.Info) + } + data := &output.ResultEvent{ - TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), - TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), - Info: wrapped.InternalEvent["template-info"].(model.Info), - TemplateVerifier: request.options.TemplateVerifier, - Type: types.ToString(wrapped.InternalEvent["type"]), - Host: fields.Host, - Port: fields.Port, - Scheme: fields.Scheme, - URL: fields.URL, - Path: fields.Path, - Matched: types.ToString(wrapped.InternalEvent["matched"]), - Metadata: wrapped.OperatorsResult.PayloadValues, - ExtractedResults: wrapped.OperatorsResult.OutputExtracts, - Timestamp: time.Now(), - MatcherStatus: true, - IP: fields.Ip, - GlobalMatchers: isGlobalMatchers, - Request: types.ToString(wrapped.InternalEvent["request"]), - Response: request.truncateResponse(wrapped.InternalEvent["response"]), - CURLCommand: types.ToString(wrapped.InternalEvent["curl-command"]), - TemplateEncoded: request.options.EncodeTemplate(), - Error: types.ToString(wrapped.InternalEvent["error"]), - AnalyzerDetails: analyzerDetails, + TemplateID: templateID, + TemplatePath: templatePath, + Info: templateInfo, + TemplateVerifier: request.options.TemplateVerifier, + Type: types.ToString(wrapped.InternalEvent["type"]), + Host: fields.Host, + Port: fields.Port, + Scheme: fields.Scheme, + URL: fields.URL, + Path: fields.Path, + Matched: types.ToString(wrapped.InternalEvent["matched"]), + Metadata: wrapped.OperatorsResult.PayloadValues, + ExtractedResults: wrapped.OperatorsResult.OutputExtracts, + Timestamp: time.Now(), + MatcherStatus: true, + IP: fields.Ip, + GlobalMatchers: isGlobalMatchers, + GlobalTemplateID: globalTemplateID, + GlobalTemplatePath: globalTemplatePath, + GlobalTemplateInfo: globalTemplateInfo, + Request: types.ToString(wrapped.InternalEvent["request"]), + Response: request.truncateResponse(wrapped.InternalEvent["response"]), + CURLCommand: types.ToString(wrapped.InternalEvent["curl-command"]), + TemplateEncoded: request.options.EncodeTemplate(), + Error: types.ToString(wrapped.InternalEvent["error"]), + AnalyzerDetails: analyzerDetails, } return data } diff --git a/pkg/protocols/network/operators.go b/pkg/protocols/network/operators.go index 2aa19e5b3..b24c8aa61 100644 --- a/pkg/protocols/network/operators.go +++ b/pkg/protocols/network/operators.go @@ -99,25 +99,61 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent if types.ToString(wrapped.InternalEvent["ip"]) != "" { fields.Ip = types.ToString(wrapped.InternalEvent["ip"]) } + + var isGlobalMatchers bool + if value, ok := wrapped.InternalEvent["global-matchers"]; ok { + isGlobalMatchers = value.(bool) + } + + // For global matchers, use original template info and store global template info separately + var templateID, templatePath string + var templateInfo model.Info + var globalTemplateID, globalTemplatePath string + var globalTemplateInfo model.Info + + if isGlobalMatchers { + // Use original template information + templateID = types.ToString(wrapped.InternalEvent["origin-template-id"]) + templatePath = types.ToString(wrapped.InternalEvent["origin-template-path"]) + if originInfo := wrapped.InternalEvent["origin-template-info"]; originInfo != nil { + templateInfo = originInfo.(model.Info) + } + // Store global template information + globalTemplateID = types.ToString(wrapped.InternalEvent["template-id"]) + globalTemplatePath = types.ToString(wrapped.InternalEvent["template-path"]) + if globalInfo := wrapped.InternalEvent["template-info"]; globalInfo != nil { + globalTemplateInfo = globalInfo.(model.Info) + } + } else { + // Use current template information for non-global matchers + templateID = types.ToString(wrapped.InternalEvent["template-id"]) + templatePath = types.ToString(wrapped.InternalEvent["template-path"]) + templateInfo = wrapped.InternalEvent["template-info"].(model.Info) + } + data := &output.ResultEvent{ - TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), - TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), - Info: wrapped.InternalEvent["template-info"].(model.Info), - TemplateVerifier: request.options.TemplateVerifier, - Type: types.ToString(wrapped.InternalEvent["type"]), - Host: fields.Host, - Port: fields.Port, - URL: fields.URL, - Matched: types.ToString(wrapped.InternalEvent["matched"]), - ExtractedResults: wrapped.OperatorsResult.OutputExtracts, - Metadata: wrapped.OperatorsResult.PayloadValues, - Timestamp: time.Now(), - MatcherStatus: true, - IP: fields.Ip, - Request: types.ToString(wrapped.InternalEvent["request"]), - Response: types.ToString(wrapped.InternalEvent["data"]), - TemplateEncoded: request.options.EncodeTemplate(), - Error: types.ToString(wrapped.InternalEvent["error"]), + TemplateID: templateID, + TemplatePath: templatePath, + Info: templateInfo, + TemplateVerifier: request.options.TemplateVerifier, + Type: types.ToString(wrapped.InternalEvent["type"]), + Host: fields.Host, + Port: fields.Port, + URL: fields.URL, + Matched: types.ToString(wrapped.InternalEvent["matched"]), + ExtractedResults: wrapped.OperatorsResult.OutputExtracts, + Metadata: wrapped.OperatorsResult.PayloadValues, + Timestamp: time.Now(), + MatcherStatus: true, + IP: fields.Ip, + GlobalMatchers: isGlobalMatchers, + GlobalTemplateID: globalTemplateID, + GlobalTemplatePath: globalTemplatePath, + GlobalTemplateInfo: globalTemplateInfo, + Request: types.ToString(wrapped.InternalEvent["request"]), + Response: types.ToString(wrapped.InternalEvent["data"]), + TemplateEncoded: request.options.EncodeTemplate(), + Error: types.ToString(wrapped.InternalEvent["error"]), } return data }