mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 19:35:27 +00:00
feat: fix global matchers JSON output and CLI formatting
- Add GlobalTemplateID, GlobalTemplatePath, and GlobalTemplateInfo fields to ResultEvent - Preserve original template information in JSON output when global matchers trigger - Store global template information in separate fields for visibility - Update CLI format for global matchers: [global-template-id:matcher] [global] [original-template-id] [protocol] [severity] - Use global template severity in CLI output instead of original template severity - Display original template ID in white (no color) for distinction - Update both HTTP and Network operators for consistency Fixes issue where global matcher results showed global template info instead of original template info in JSON output.
This commit is contained in:
parent
8ef3662634
commit
1abc65dea4
@ -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(w.aurora.Cyan(output.Timestamp.Format("2006-01-02 15:04:05")).String())
|
||||||
builder.WriteString("] ")
|
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 {
|
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("] [")
|
||||||
builder.WriteString(w.aurora.BrightMagenta("global").String())
|
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 != "" {
|
if output.Matched != "" {
|
||||||
builder.WriteString(output.Matched)
|
builder.WriteString(output.Matched)
|
||||||
|
|||||||
@ -199,6 +199,12 @@ type ResultEvent struct {
|
|||||||
// GlobalMatchers identifies whether the matches was detected in the response
|
// GlobalMatchers identifies whether the matches was detected in the response
|
||||||
// of another template's result event
|
// of another template's result event
|
||||||
GlobalMatchers bool `json:"global-matchers,omitempty"`
|
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 is the metadata for issue trackers
|
||||||
IssueTrackers map[string]IssueTrackerMetadata `json:"issue_trackers,omitempty"`
|
IssueTrackers map[string]IssueTrackerMetadata `json:"issue_trackers,omitempty"`
|
||||||
|
|||||||
@ -173,30 +173,60 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
|
|||||||
if value, ok := wrapped.InternalEvent["analyzer_details"]; ok {
|
if value, ok := wrapped.InternalEvent["analyzer_details"]; ok {
|
||||||
analyzerDetails = value.(string)
|
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{
|
data := &output.ResultEvent{
|
||||||
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
|
TemplateID: templateID,
|
||||||
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
|
TemplatePath: templatePath,
|
||||||
Info: wrapped.InternalEvent["template-info"].(model.Info),
|
Info: templateInfo,
|
||||||
TemplateVerifier: request.options.TemplateVerifier,
|
TemplateVerifier: request.options.TemplateVerifier,
|
||||||
Type: types.ToString(wrapped.InternalEvent["type"]),
|
Type: types.ToString(wrapped.InternalEvent["type"]),
|
||||||
Host: fields.Host,
|
Host: fields.Host,
|
||||||
Port: fields.Port,
|
Port: fields.Port,
|
||||||
Scheme: fields.Scheme,
|
Scheme: fields.Scheme,
|
||||||
URL: fields.URL,
|
URL: fields.URL,
|
||||||
Path: fields.Path,
|
Path: fields.Path,
|
||||||
Matched: types.ToString(wrapped.InternalEvent["matched"]),
|
Matched: types.ToString(wrapped.InternalEvent["matched"]),
|
||||||
Metadata: wrapped.OperatorsResult.PayloadValues,
|
Metadata: wrapped.OperatorsResult.PayloadValues,
|
||||||
ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
|
ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
|
||||||
Timestamp: time.Now(),
|
Timestamp: time.Now(),
|
||||||
MatcherStatus: true,
|
MatcherStatus: true,
|
||||||
IP: fields.Ip,
|
IP: fields.Ip,
|
||||||
GlobalMatchers: isGlobalMatchers,
|
GlobalMatchers: isGlobalMatchers,
|
||||||
Request: types.ToString(wrapped.InternalEvent["request"]),
|
GlobalTemplateID: globalTemplateID,
|
||||||
Response: request.truncateResponse(wrapped.InternalEvent["response"]),
|
GlobalTemplatePath: globalTemplatePath,
|
||||||
CURLCommand: types.ToString(wrapped.InternalEvent["curl-command"]),
|
GlobalTemplateInfo: globalTemplateInfo,
|
||||||
TemplateEncoded: request.options.EncodeTemplate(),
|
Request: types.ToString(wrapped.InternalEvent["request"]),
|
||||||
Error: types.ToString(wrapped.InternalEvent["error"]),
|
Response: request.truncateResponse(wrapped.InternalEvent["response"]),
|
||||||
AnalyzerDetails: analyzerDetails,
|
CURLCommand: types.ToString(wrapped.InternalEvent["curl-command"]),
|
||||||
|
TemplateEncoded: request.options.EncodeTemplate(),
|
||||||
|
Error: types.ToString(wrapped.InternalEvent["error"]),
|
||||||
|
AnalyzerDetails: analyzerDetails,
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,25 +99,61 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
|
|||||||
if types.ToString(wrapped.InternalEvent["ip"]) != "" {
|
if types.ToString(wrapped.InternalEvent["ip"]) != "" {
|
||||||
fields.Ip = 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{
|
data := &output.ResultEvent{
|
||||||
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
|
TemplateID: templateID,
|
||||||
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
|
TemplatePath: templatePath,
|
||||||
Info: wrapped.InternalEvent["template-info"].(model.Info),
|
Info: templateInfo,
|
||||||
TemplateVerifier: request.options.TemplateVerifier,
|
TemplateVerifier: request.options.TemplateVerifier,
|
||||||
Type: types.ToString(wrapped.InternalEvent["type"]),
|
Type: types.ToString(wrapped.InternalEvent["type"]),
|
||||||
Host: fields.Host,
|
Host: fields.Host,
|
||||||
Port: fields.Port,
|
Port: fields.Port,
|
||||||
URL: fields.URL,
|
URL: fields.URL,
|
||||||
Matched: types.ToString(wrapped.InternalEvent["matched"]),
|
Matched: types.ToString(wrapped.InternalEvent["matched"]),
|
||||||
ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
|
ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
|
||||||
Metadata: wrapped.OperatorsResult.PayloadValues,
|
Metadata: wrapped.OperatorsResult.PayloadValues,
|
||||||
Timestamp: time.Now(),
|
Timestamp: time.Now(),
|
||||||
MatcherStatus: true,
|
MatcherStatus: true,
|
||||||
IP: fields.Ip,
|
IP: fields.Ip,
|
||||||
Request: types.ToString(wrapped.InternalEvent["request"]),
|
GlobalMatchers: isGlobalMatchers,
|
||||||
Response: types.ToString(wrapped.InternalEvent["data"]),
|
GlobalTemplateID: globalTemplateID,
|
||||||
TemplateEncoded: request.options.EncodeTemplate(),
|
GlobalTemplatePath: globalTemplatePath,
|
||||||
Error: types.ToString(wrapped.InternalEvent["error"]),
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user