Added matched-status flag + template-path and url to output (#1272)

* Added matched-status flag + template-path and url to output
This commit is contained in:
Ice3man 2021-11-22 17:53:25 +05:30 committed by GitHub
parent ca9676f52e
commit 1581c96e4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 205 additions and 66 deletions

View File

@ -85,6 +85,7 @@ on extensive configurability, massive extensibility and ease of use.`)
flagSet.BoolVarP(&options.NoMeta, "no-meta", "nm", false, "don't display match metadata"), flagSet.BoolVarP(&options.NoMeta, "no-meta", "nm", false, "don't display match metadata"),
flagSet.BoolVarP(&options.NoTimestamp, "no-timestamp", "nts", false, "don't display timestamp metadata in CLI output"), flagSet.BoolVarP(&options.NoTimestamp, "no-timestamp", "nts", false, "don't display timestamp metadata in CLI output"),
flagSet.StringVarP(&options.ReportingDB, "report-db", "rdb", "", "local nuclei reporting database (always use this to persist report data)"), flagSet.StringVarP(&options.ReportingDB, "report-db", "rdb", "", "local nuclei reporting database (always use this to persist report data)"),
flagSet.BoolVarP(&options.MatcherStatus, "matcher-status", "ms", false, "show optional match failure status"),
flagSet.StringVarP(&options.MarkdownExportDirectory, "markdown-export", "me", "", "directory to export results in markdown format"), flagSet.StringVarP(&options.MarkdownExportDirectory, "markdown-export", "me", "", "directory to export results in markdown format"),
flagSet.StringVarP(&options.SarifExport, "sarif-export", "se", "", "file to export results in SARIF format"), flagSet.StringVarP(&options.SarifExport, "sarif-export", "se", "", "file to export results in SARIF format"),
) )

View File

@ -117,7 +117,7 @@ func New(options *types.Options) (*Runner, error) {
runner.hmapInputProvider = hmapInput runner.hmapInputProvider = hmapInput
// Create the output file if asked // Create the output file if asked
outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.NoTimestamp, options.JSON, options.JSONRequests, options.Output, options.TraceLogFile, options.ErrorLogFile) outputWriter, err := output.NewStandardWriter(!options.NoColor, options.NoMeta, options.NoTimestamp, options.JSON, options.JSONRequests, options.MatcherStatus, options.Output, options.TraceLogFile, options.ErrorLogFile)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "could not create output file") return nil, errors.Wrap(err, "could not create output file")
} }

View File

@ -27,6 +27,15 @@ func (w *StandardWriter) formatScreen(output *ResultEvent) []byte {
builder.WriteString(w.aurora.BrightGreen(output.ExtractorName).Bold().String()) 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("] [")
builder.WriteString(w.aurora.BrightBlue(output.Type).String()) builder.WriteString(w.aurora.BrightBlue(output.Type).String())
builder.WriteString("] ") builder.WriteString("] ")
@ -35,7 +44,11 @@ func (w *StandardWriter) formatScreen(output *ResultEvent) []byte {
builder.WriteString(w.severityColors(output.Info.SeverityHolder.Severity)) builder.WriteString(w.severityColors(output.Info.SeverityHolder.Severity))
builder.WriteString("] ") builder.WriteString("] ")
} }
if output.Matched != "" {
builder.WriteString(output.Matched) builder.WriteString(output.Matched)
} else {
builder.WriteString(output.Host)
}
// If any extractors, write the results // If any extractors, write the results
if len(output.ExtractedResults) > 0 { if len(output.ExtractedResults) > 0 {

View File

@ -16,6 +16,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/model" "github.com/projectdiscovery/nuclei/v2/pkg/model"
"github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity" "github.com/projectdiscovery/nuclei/v2/pkg/model/types/severity"
"github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/types"
"github.com/projectdiscovery/nuclei/v2/pkg/utils" "github.com/projectdiscovery/nuclei/v2/pkg/utils"
) )
@ -27,6 +28,8 @@ type Writer interface {
Colorizer() aurora.Aurora Colorizer() aurora.Aurora
// Write writes the event to file and/or screen. // Write writes the event to file and/or screen.
Write(*ResultEvent) error Write(*ResultEvent) error
// WriteFailure writes the optional failure event for template to file and/or screen.
WriteFailure(event InternalEvent) error
// Request logs a request in the trace log // Request logs a request in the trace log
Request(templateID, url, requestType string, err error) Request(templateID, url, requestType string, err error)
} }
@ -37,6 +40,7 @@ type StandardWriter struct {
jsonReqResp bool jsonReqResp bool
noTimestamp bool noTimestamp bool
noMetadata bool noMetadata bool
matcherStatus bool
aurora aurora.Aurora aurora aurora.Aurora
outputFile io.WriteCloser outputFile io.WriteCloser
traceFile io.WriteCloser traceFile io.WriteCloser
@ -54,10 +58,16 @@ type InternalWrappedEvent struct {
InternalEvent InternalEvent InternalEvent InternalEvent
Results []*ResultEvent Results []*ResultEvent
OperatorsResult *operators.Result OperatorsResult *operators.Result
UsesInteractsh bool
} }
// ResultEvent is a wrapped result event for a single nuclei output. // ResultEvent is a wrapped result event for a single nuclei output.
type ResultEvent struct { type ResultEvent struct {
// Template is the relative filename for the template
Template string `json:"template,omitempty"`
// TemplateURL is the URL of the template for the result inside the nuclei
// templates repository if it belongs to the repository.
TemplateURL string `json:"template-url,omitempty"`
// TemplateID is the ID of the template for the result. // TemplateID is the ID of the template for the result.
TemplateID string `json:"template-id"` TemplateID string `json:"template-id"`
// TemplatePath is the path of template // TemplatePath is the path of template
@ -93,11 +103,13 @@ type ResultEvent struct {
// CURLCommand is an optional curl command to reproduce the request // CURLCommand is an optional curl command to reproduce the request
// Only applicable if the report is for HTTP. // Only applicable if the report is for HTTP.
CURLCommand string `json:"curl-command,omitempty"` CURLCommand string `json:"curl-command,omitempty"`
// MatcherStatus is the status of the match
MatcherStatus bool `json:"matcher-status"`
FileToIndexPosition map[string]int `json:"-"` FileToIndexPosition map[string]int `json:"-"`
} }
// NewStandardWriter creates a new output writer based on user configurations // NewStandardWriter creates a new output writer based on user configurations
func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp bool, file, traceFile string, errorFile string) (*StandardWriter, error) { func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp, MatcherStatus bool, file, traceFile string, errorFile string) (*StandardWriter, error) {
auroraColorizer := aurora.NewAurora(colors) auroraColorizer := aurora.NewAurora(colors)
var outputFile io.WriteCloser var outputFile io.WriteCloser
@ -128,6 +140,7 @@ func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp bool,
json: json, json: json,
jsonReqResp: jsonReqResp, jsonReqResp: jsonReqResp,
noMetadata: noMetadata, noMetadata: noMetadata,
matcherStatus: MatcherStatus,
noTimestamp: noTimestamp, noTimestamp: noTimestamp,
aurora: auroraColorizer, aurora: auroraColorizer,
outputFile: outputFile, outputFile: outputFile,
@ -140,6 +153,10 @@ func NewStandardWriter(colors, noMetadata, noTimestamp, json, jsonReqResp bool,
// Write writes the event to file and/or screen. // Write writes the event to file and/or screen.
func (w *StandardWriter) Write(event *ResultEvent) error { func (w *StandardWriter) Write(event *ResultEvent) error {
// Enrich the result event with extra metadata on the template-path and url.
if event.TemplatePath != "" {
event.Template, event.TemplateURL = utils.TemplatePathURL(types.ToString(event.TemplatePath))
}
event.Timestamp = time.Now() event.Timestamp = time.Now()
var data []byte var data []byte
@ -224,3 +241,23 @@ func (w *StandardWriter) Close() {
w.errorFile.Close() w.errorFile.Close()
} }
} }
// WriteFailure writes the failure event for template to file and/or screen.
func (w *StandardWriter) WriteFailure(event InternalEvent) error {
if !w.matcherStatus {
return nil
}
templatePath, templateURL := utils.TemplatePathURL(types.ToString(event["template-path"]))
data := &ResultEvent{
Template: templatePath,
TemplateURL: templateURL,
TemplateID: types.ToString(event["template-id"]),
TemplatePath: types.ToString(event["template-path"]),
Info: event["template-info"].(model.Info),
Type: types.ToString(event["type"]),
Host: types.ToString(event["host"]),
MatcherStatus: false,
Timestamp: time.Now(),
}
return w.Write(data)
}

View File

@ -11,7 +11,7 @@ import (
func TestStandardWriterRequest(t *testing.T) { func TestStandardWriterRequest(t *testing.T) {
t.Run("WithoutTraceAndError", func(t *testing.T) { t.Run("WithoutTraceAndError", func(t *testing.T) {
w, err := NewStandardWriter(false, false, false, false, false, "", "", "") w, err := NewStandardWriter(false, false, false, false, false, false, "", "", "")
require.NoError(t, err) require.NoError(t, err)
require.NotPanics(t, func() { require.NotPanics(t, func() {
w.Request("path", "input", "http", nil) w.Request("path", "input", "http", nil)
@ -23,7 +23,7 @@ func TestStandardWriterRequest(t *testing.T) {
traceWriter := &testWriteCloser{} traceWriter := &testWriteCloser{}
errorWriter := &testWriteCloser{} errorWriter := &testWriteCloser{}
w, err := NewStandardWriter(false, false, false, false, false, "", "", "") w, err := NewStandardWriter(false, false, false, false, false, false, "", "", "")
w.traceFile = traceWriter w.traceFile = traceWriter
w.errorFile = errorWriter w.errorFile = errorWriter
require.NoError(t, err) require.NoError(t, err)
@ -36,7 +36,7 @@ func TestStandardWriterRequest(t *testing.T) {
t.Run("ErrorWithWrappedError", func(t *testing.T) { t.Run("ErrorWithWrappedError", func(t *testing.T) {
errorWriter := &testWriteCloser{} errorWriter := &testWriteCloser{}
w, err := NewStandardWriter(false, false, false, false, false, "", "", "") w, err := NewStandardWriter(false, false, false, false, false, false, "", "", "")
w.errorFile = errorWriter w.errorFile = errorWriter
require.NoError(t, err) require.NoError(t, err)
w.Request( w.Request(

View File

@ -6,6 +6,7 @@ import (
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/writer"
) )
// Executer executes a group of requests for a protocol // Executer executes a group of requests for a protocol
@ -59,18 +60,17 @@ func (e *Executer) Execute(input string) (bool, error) {
builder.Reset() builder.Reset()
} }
} }
if event.OperatorsResult == nil { // If no results were found, and also interactsh is not being used
return // in that case we can skip it, otherwise we've to show failure in
} // case of matcher-status flag.
for _, result := range event.Results { if event.OperatorsResult == nil && !event.UsesInteractsh {
if e.options.IssuesClient != nil { if err := e.options.Output.WriteFailure(event.InternalEvent); err != nil {
if err := e.options.IssuesClient.CreateIssue(result); err != nil { gologger.Warning().Msgf("Could not write failure event to output: %s\n", err)
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
}
} }
} else {
if writer.WriteResult(event, e.options.Output, e.options.Progress, e.options.IssuesClient) {
results = true results = true
_ = e.options.Output.Write(result) }
e.options.Progress.IncrementMatched()
} }
}) })
if err != nil { if err != nil {

View File

@ -0,0 +1,35 @@
package writer
import (
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/progress"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting"
)
// WriteResult is a helper for writing results to the output
func WriteResult(data *output.InternalWrappedEvent, output output.Writer, progress progress.Progress, issuesClient *reporting.Client) bool {
// Handle the case where no result found for the template.
// In this case, we just show misc information about the failed
// match for the template.
if data.OperatorsResult == nil {
return false
}
var matched bool
for _, result := range data.Results {
if err := output.Write(result); err != nil {
gologger.Warning().Msgf("Could not write output event: %s\n", err)
}
if !matched {
matched = true
}
progress.IncrementMatched()
if issuesClient != nil {
if err := issuesClient.CreateIssue(result); err != nil {
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
}
}
}
return matched
}

View File

@ -19,6 +19,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/progress" "github.com/projectdiscovery/nuclei/v2/pkg/progress"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/writer"
"github.com/projectdiscovery/nuclei/v2/pkg/reporting" "github.com/projectdiscovery/nuclei/v2/pkg/reporting"
) )
@ -177,20 +178,9 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d
} }
data.Event.Results = data.MakeResultFunc(data.Event) data.Event.Results = data.MakeResultFunc(data.Event)
for _, result := range data.Event.Results { if writer.WriteResult(data.Event, c.options.Output, c.options.Progress, c.options.IssuesClient) {
result.Interaction = interaction
_ = c.options.Output.Write(result)
if !c.matched {
c.matched = true c.matched = true
} }
c.options.Progress.IncrementMatched()
if c.options.IssuesClient != nil {
if err := c.options.IssuesClient.CreateIssue(result); err != nil {
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
}
}
}
return true return true
} }

View File

@ -90,6 +90,7 @@ func (request *Request) responseToDSLMap(req, resp *dns.Msg, host, matched strin
"template-id": request.options.TemplateID, "template-id": request.options.TemplateID,
"template-info": request.options.TemplateInfo, "template-info": request.options.TemplateInfo,
"template-path": request.options.TemplatePath, "template-path": request.options.TemplatePath,
"type": request.Type().String(),
"trace": traceToString(tracedata, false), "trace": traceToString(tracedata, false),
} }
} }
@ -104,10 +105,11 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
Info: wrapped.InternalEvent["template-info"].(model.Info), Info: wrapped.InternalEvent["template-info"].(model.Info),
Type: "dns", Type: types.ToString(wrapped.InternalEvent["type"]),
Host: types.ToString(wrapped.InternalEvent["host"]), Host: types.ToString(wrapped.InternalEvent["host"]),
Matched: types.ToString(wrapped.InternalEvent["matched"]), Matched: types.ToString(wrapped.InternalEvent["matched"]),
ExtractedResults: wrapped.OperatorsResult.OutputExtracts, ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
MatcherStatus: true,
Timestamp: time.Now(), Timestamp: time.Now(),
Request: types.ToString(wrapped.InternalEvent["request"]), Request: types.ToString(wrapped.InternalEvent["request"]),
Response: types.ToString(wrapped.InternalEvent["raw"]), Response: types.ToString(wrapped.InternalEvent["raw"]),

View File

@ -45,7 +45,7 @@ func TestResponseToDSLMap(t *testing.T) {
resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}}) resp.Answer = append(resp.Answer, &dns.A{A: net.ParseIP("1.1.1.1"), Hdr: dns.RR_Header{Name: "one.one.one.one."}})
event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil) event := request.responseToDSLMap(req, resp, "one.one.one.one", "one.one.one.one", nil)
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, dns.RcodeSuccess, event["rcode"], "could not get correct rcode") require.Equal(t, dns.RcodeSuccess, event["rcode"], "could not get correct rcode")
} }

View File

@ -73,6 +73,7 @@ func (request *Request) responseToDSLMap(raw, inputFilePath, matchedFileName str
"path": inputFilePath, "path": inputFilePath,
"matched": matchedFileName, "matched": matchedFileName,
"raw": raw, "raw": raw,
"type": request.Type().String(),
"template-id": request.options.TemplateID, "template-id": request.options.TemplateID,
"template-info": request.options.TemplateInfo, "template-info": request.options.TemplateInfo,
"template-path": request.options.TemplatePath, "template-path": request.options.TemplatePath,
@ -120,10 +121,11 @@ func (request *Request) GetCompiledOperators() []*operators.Operators {
func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent) *output.ResultEvent { func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent) *output.ResultEvent {
data := &output.ResultEvent{ data := &output.ResultEvent{
MatcherStatus: true,
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
Info: wrapped.InternalEvent["template-info"].(model.Info), Info: wrapped.InternalEvent["template-info"].(model.Info),
Type: "file", Type: types.ToString(wrapped.InternalEvent["type"]),
Path: types.ToString(wrapped.InternalEvent["path"]), Path: types.ToString(wrapped.InternalEvent["path"]),
Matched: types.ToString(wrapped.InternalEvent["matched"]), Matched: types.ToString(wrapped.InternalEvent["matched"]),
Host: types.ToString(wrapped.InternalEvent["host"]), Host: types.ToString(wrapped.InternalEvent["host"]),

View File

@ -35,7 +35,7 @@ func TestResponseToDSLMap(t *testing.T) {
resp := "test-data\r\n" resp := "test-data\r\n"
event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")
require.Len(t, event, 6, "could not get correct number of items in dsl map") require.Len(t, event, 7, "could not get correct number of items in dsl map")
require.Equal(t, resp, event["raw"], "could not get correct resp") require.Equal(t, resp, event["raw"], "could not get correct resp")
} }
@ -60,7 +60,7 @@ func TestFileOperatorMatch(t *testing.T) {
resp := "test-data\r\n1.1.1.1\r\n" resp := "test-data\r\n1.1.1.1\r\n"
event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")
require.Len(t, event, 6, "could not get correct number of items in dsl map") require.Len(t, event, 7, "could not get correct number of items in dsl map")
require.Equal(t, resp, event["raw"], "could not get correct resp") require.Equal(t, resp, event["raw"], "could not get correct resp")
t.Run("valid", func(t *testing.T) { t.Run("valid", func(t *testing.T) {
@ -109,7 +109,7 @@ func TestFileOperatorMatch(t *testing.T) {
t.Run("caseInsensitive", func(t *testing.T) { t.Run("caseInsensitive", func(t *testing.T) {
resp := "TEST-DATA\r\n1.1.1.1\r\n" resp := "TEST-DATA\r\n1.1.1.1\r\n"
event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")
require.Len(t, event, 6, "could not get correct number of items in dsl map") require.Len(t, event, 7, "could not get correct number of items in dsl map")
require.Equal(t, resp, event["raw"], "could not get correct resp") require.Equal(t, resp, event["raw"], "could not get correct resp")
matcher := &matchers.Matcher{ matcher := &matchers.Matcher{
@ -148,7 +148,7 @@ func TestFileOperatorExtract(t *testing.T) {
resp := "test-data\r\n1.1.1.1\r\n" resp := "test-data\r\n1.1.1.1\r\n"
event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one") event := request.responseToDSLMap(resp, "one.one.one.one", "one.one.one.one")
require.Len(t, event, 6, "could not get correct number of items in dsl map") require.Len(t, event, 7, "could not get correct number of items in dsl map")
require.Equal(t, resp, event["raw"], "could not get correct resp") require.Equal(t, resp, event["raw"], "could not get correct resp")
t.Run("extract", func(t *testing.T) { t.Run("extract", func(t *testing.T) {
@ -266,7 +266,7 @@ func testFileMakeResult(t *testing.T, matchers []*matchers.Matcher, matcherCondi
fileContent := "test-data\r\n1.1.1.1\r\n" fileContent := "test-data\r\n1.1.1.1\r\n"
event := request.responseToDSLMap(fileContent, "/tmp", matchedFileName) event := request.responseToDSLMap(fileContent, "/tmp", matchedFileName)
require.Len(t, event, 6, "could not get correct number of items in dsl map") require.Len(t, event, 7, "could not get correct number of items in dsl map")
require.Equal(t, fileContent, event["raw"], "could not get correct resp") require.Equal(t, fileContent, event["raw"], "could not get correct resp")
finalEvent := &output.InternalWrappedEvent{InternalEvent: event} finalEvent := &output.InternalWrappedEvent{InternalEvent: event}

View File

@ -72,6 +72,7 @@ func (request *Request) responseToDSLMap(resp, req, host, matched string) output
"matched": matched, "matched": matched,
"req": req, "req": req,
"data": resp, "data": resp,
"type": request.Type().String(),
"template-id": request.options.TemplateID, "template-id": request.options.TemplateID,
"template-info": request.options.TemplateInfo, "template-info": request.options.TemplateInfo,
"template-path": request.options.TemplatePath, "template-path": request.options.TemplatePath,
@ -92,11 +93,12 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
Info: wrapped.InternalEvent["template-info"].(model.Info), Info: wrapped.InternalEvent["template-info"].(model.Info),
Type: "headless", Type: types.ToString(wrapped.InternalEvent["type"]),
Host: types.ToString(wrapped.InternalEvent["host"]), Host: types.ToString(wrapped.InternalEvent["host"]),
Matched: types.ToString(wrapped.InternalEvent["matched"]), Matched: types.ToString(wrapped.InternalEvent["matched"]),
ExtractedResults: wrapped.OperatorsResult.OutputExtracts, ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
Timestamp: time.Now(), Timestamp: time.Now(),
MatcherStatus: true,
IP: types.ToString(wrapped.InternalEvent["ip"]), IP: types.ToString(wrapped.InternalEvent["ip"]),
Request: types.ToString(wrapped.InternalEvent["request"]), Request: types.ToString(wrapped.InternalEvent["request"]),
Response: types.ToString(wrapped.InternalEvent["data"]), Response: types.ToString(wrapped.InternalEvent["data"]),

View File

@ -113,6 +113,7 @@ func (request *Request) responseToDSLMap(resp *http.Response, host, matched, raw
data[k] = strings.Join(v, " ") data[k] = strings.Join(v, " ")
} }
data["host"] = host data["host"] = host
data["type"] = request.Type().String()
data["matched"] = matched data["matched"] = matched
data["request"] = rawReq data["request"] = rawReq
data["response"] = rawResp data["response"] = rawResp
@ -141,12 +142,13 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
Info: wrapped.InternalEvent["template-info"].(model.Info), Info: wrapped.InternalEvent["template-info"].(model.Info),
Type: "http", Type: types.ToString(wrapped.InternalEvent["type"]),
Host: types.ToString(wrapped.InternalEvent["host"]), Host: types.ToString(wrapped.InternalEvent["host"]),
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,
IP: types.ToString(wrapped.InternalEvent["ip"]), IP: types.ToString(wrapped.InternalEvent["ip"]),
Request: types.ToString(wrapped.InternalEvent["request"]), Request: types.ToString(wrapped.InternalEvent["request"]),
Response: types.ToString(wrapped.InternalEvent["response"]), Response: types.ToString(wrapped.InternalEvent["response"]),

View File

@ -41,7 +41,7 @@ func TestResponseToDSLMap(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header")
} }
@ -71,7 +71,7 @@ func TestHTTPOperatorMatch(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header")
@ -159,7 +159,7 @@ func TestHTTPOperatorExtract(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test_header"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test_header"], "could not get correct resp for header")
@ -286,7 +286,7 @@ func TestHTTPMakeResult(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header")

View File

@ -473,6 +473,9 @@ func (request *Request) executeRequest(reqURL string, generatedRequest *generate
event := eventcreator.CreateEventWithAdditionalOptions(request, finalEvent, request.options.Options.Debug || request.options.Options.DebugResponse, func(internalWrappedEvent *output.InternalWrappedEvent) { event := eventcreator.CreateEventWithAdditionalOptions(request, finalEvent, request.options.Options.Debug || request.options.Options.DebugResponse, func(internalWrappedEvent *output.InternalWrappedEvent) {
internalWrappedEvent.OperatorsResult.PayloadValues = generatedRequest.meta internalWrappedEvent.OperatorsResult.PayloadValues = generatedRequest.meta
}) })
if hasInteractMarkers {
event.UsesInteractsh = true
}
responseContentType := resp.Header.Get("Content-Type") responseContentType := resp.Header.Get("Content-Type")
dumpResponse(event, request.options, response.fullResponse, formedURL, responseContentType) dumpResponse(event, request.options, response.fullResponse, formedURL, responseContentType)

View File

@ -73,6 +73,7 @@ func (request *Request) responseToDSLMap(req, resp, raw, host, matched string) o
"request": req, "request": req,
"data": resp, // Data is the last bytes read "data": resp, // Data is the last bytes read
"raw": raw, // Raw is the full transaction data for network "raw": raw, // Raw is the full transaction data for network
"type": request.Type().String(),
"template-id": request.options.TemplateID, "template-id": request.options.TemplateID,
"template-info": request.options.TemplateInfo, "template-info": request.options.TemplateInfo,
"template-path": request.options.TemplatePath, "template-path": request.options.TemplatePath,
@ -93,12 +94,13 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
Info: wrapped.InternalEvent["template-info"].(model.Info), Info: wrapped.InternalEvent["template-info"].(model.Info),
Type: "network", Type: types.ToString(wrapped.InternalEvent["type"]),
Host: types.ToString(wrapped.InternalEvent["host"]), Host: types.ToString(wrapped.InternalEvent["host"]),
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,
IP: types.ToString(wrapped.InternalEvent["ip"]), IP: types.ToString(wrapped.InternalEvent["ip"]),
Request: types.ToString(wrapped.InternalEvent["request"]), Request: types.ToString(wrapped.InternalEvent["request"]),
Response: types.ToString(wrapped.InternalEvent["data"]), Response: types.ToString(wrapped.InternalEvent["data"]),

View File

@ -35,7 +35,7 @@ func TestResponseToDSLMap(t *testing.T) {
req := "test-data\r\n" req := "test-data\r\n"
resp := "resp-data\r\n" resp := "resp-data\r\n"
event := request.responseToDSLMap(req, resp, "test", "one.one.one.one", "one.one.one.one") event := request.responseToDSLMap(req, resp, "test", "one.one.one.one", "one.one.one.one")
require.Len(t, event, 8, "could not get correct number of items in dsl map") require.Len(t, event, 9, "could not get correct number of items in dsl map")
require.Equal(t, resp, event["data"], "could not get correct resp") require.Equal(t, resp, event["data"], "could not get correct resp")
} }

View File

@ -281,6 +281,9 @@ func (request *Request) executeRequestWithPayloads(actualAddress, address, input
ExtractFunc: request.Extract, ExtractFunc: request.Extract,
}) })
} }
if len(interactshURLs) > 0 {
event.UsesInteractsh = true
}
dumpResponse(event, request.options, response, actualAddress) dumpResponse(event, request.options, response, actualAddress)

View File

@ -113,6 +113,7 @@ func (request *Request) responseToDSLMap(resp *http.Response, host, matched, raw
data["content_length"] = resp.ContentLength data["content_length"] = resp.ContentLength
data["status_code"] = resp.StatusCode data["status_code"] = resp.StatusCode
data["body"] = body data["body"] = body
data["type"] = request.Type().String()
data["all_headers"] = headers data["all_headers"] = headers
data["duration"] = duration.Seconds() data["duration"] = duration.Seconds()
data["template-id"] = request.options.TemplateID data["template-id"] = request.options.TemplateID
@ -135,11 +136,12 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
TemplateID: types.ToString(wrapped.InternalEvent["template-id"]), TemplateID: types.ToString(wrapped.InternalEvent["template-id"]),
TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]), TemplatePath: types.ToString(wrapped.InternalEvent["template-path"]),
Info: wrapped.InternalEvent["template-info"].(model.Info), Info: wrapped.InternalEvent["template-info"].(model.Info),
Type: "http", Type: types.ToString(wrapped.InternalEvent["type"]),
Path: types.ToString(wrapped.InternalEvent["path"]), Path: types.ToString(wrapped.InternalEvent["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,
MatcherStatus: true,
IP: types.ToString(wrapped.InternalEvent["ip"]), IP: types.ToString(wrapped.InternalEvent["ip"]),
Request: types.ToString(wrapped.InternalEvent["request"]), Request: types.ToString(wrapped.InternalEvent["request"]),
Response: types.ToString(wrapped.InternalEvent["raw"]), Response: types.ToString(wrapped.InternalEvent["raw"]),

View File

@ -37,7 +37,7 @@ func TestResponseToDSLMap(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header")
} }
@ -63,7 +63,7 @@ func TestHTTPOperatorMatch(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header")
@ -132,7 +132,7 @@ func TestHTTPOperatorExtract(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test-header"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test-header"], "could not get correct resp for header")
@ -198,7 +198,7 @@ func TestHTTPMakeResult(t *testing.T) {
matched := "http://example.com/test/?test=1" matched := "http://example.com/test/?test=1"
event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{}) event := request.responseToDSLMap(resp, host, matched, exampleRawRequest, exampleRawResponse, exampleResponseBody, exampleResponseHeader, 1*time.Second, map[string]interface{}{})
require.Len(t, event, 13, "could not get correct number of items in dsl map") require.Len(t, event, 14, "could not get correct number of items in dsl map")
require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp") require.Equal(t, exampleRawResponse, event["response"], "could not get correct resp")
require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header") require.Equal(t, "Test-Response", event["test"], "could not get correct resp for header")

View File

@ -129,6 +129,7 @@ func (request *Request) ExecuteWithResults(input string, dynamicValues, previous
data := make(map[string]interface{}) data := make(map[string]interface{})
cert := connTLS.ConnectionState().PeerCertificates[0] cert := connTLS.ConnectionState().PeerCertificates[0]
data["type"] = request.Type().String()
data["response"] = jsonDataString data["response"] = jsonDataString
data["host"] = input data["host"] = input
data["matched"] = addressToDial data["matched"] = addressToDial
@ -195,12 +196,13 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
TemplateID: types.ToString(request.options.TemplateID), TemplateID: types.ToString(request.options.TemplateID),
TemplatePath: types.ToString(request.options.TemplatePath), TemplatePath: types.ToString(request.options.TemplatePath),
Info: request.options.TemplateInfo, Info: request.options.TemplateInfo,
Type: request.Type().String(), Type: types.ToString(wrapped.InternalEvent["type"]),
Host: types.ToString(wrapped.InternalEvent["host"]), Host: types.ToString(wrapped.InternalEvent["host"]),
Matched: types.ToString(wrapped.InternalEvent["host"]), Matched: types.ToString(wrapped.InternalEvent["host"]),
Metadata: wrapped.OperatorsResult.PayloadValues, Metadata: wrapped.OperatorsResult.PayloadValues,
ExtractedResults: wrapped.OperatorsResult.OutputExtracts, ExtractedResults: wrapped.OperatorsResult.OutputExtracts,
Timestamp: time.Now(), Timestamp: time.Now(),
MatcherStatus: true,
IP: types.ToString(wrapped.InternalEvent["ip"]), IP: types.ToString(wrapped.InternalEvent["ip"]),
} }
return data return data

View File

@ -248,6 +248,8 @@ func (request *Request) executeRequestWithPayloads(input, hostname string, dynam
for k, v := range events { for k, v := range events {
data[k] = v data[k] = v
} }
data["type"] = request.Type().String()
data["success"] = "true" data["success"] = "true"
data["request"] = requestOutput data["request"] = requestOutput
data["response"] = responseBuilder.String() data["response"] = responseBuilder.String()
@ -364,12 +366,13 @@ func (request *Request) MakeResultEventItem(wrapped *output.InternalWrappedEvent
TemplateID: types.ToString(request.options.TemplateID), TemplateID: types.ToString(request.options.TemplateID),
TemplatePath: types.ToString(request.options.TemplatePath), TemplatePath: types.ToString(request.options.TemplatePath),
Info: request.options.TemplateInfo, Info: request.options.TemplateInfo,
Type: request.Type().String(), Type: types.ToString(wrapped.InternalEvent["type"]),
Host: types.ToString(wrapped.InternalEvent["host"]), Host: types.ToString(wrapped.InternalEvent["host"]),
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,
IP: types.ToString(wrapped.InternalEvent["ip"]), IP: types.ToString(wrapped.InternalEvent["ip"]),
Request: types.ToString(wrapped.InternalEvent["request"]), Request: types.ToString(wrapped.InternalEvent["request"]),
Response: types.ToString(wrapped.InternalEvent["response"]), Response: types.ToString(wrapped.InternalEvent["response"]),

View File

@ -8,6 +8,7 @@ import (
"github.com/projectdiscovery/nuclei/v2/pkg/operators" "github.com/projectdiscovery/nuclei/v2/pkg/operators"
"github.com/projectdiscovery/nuclei/v2/pkg/output" "github.com/projectdiscovery/nuclei/v2/pkg/output"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols" "github.com/projectdiscovery/nuclei/v2/pkg/protocols"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/writer"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http" "github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
"github.com/rs/xid" "github.com/rs/xid"
) )
@ -147,22 +148,22 @@ func (e *Executer) Execute(input string) (bool, error) {
err := e.requests.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) { err := e.requests.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) {
for _, operator := range e.operators { for _, operator := range e.operators {
result, matched := operator.operator.Execute(event.InternalEvent, e.requests.Match, e.requests.Extract, e.options.Options.Debug || e.options.Options.DebugResponse) result, matched := operator.operator.Execute(event.InternalEvent, e.requests.Match, e.requests.Extract, e.options.Options.Debug || e.options.Options.DebugResponse)
if matched && result != nil {
event.OperatorsResult = result
event.InternalEvent["template-id"] = operator.templateID event.InternalEvent["template-id"] = operator.templateID
event.InternalEvent["template-path"] = operator.templatePath event.InternalEvent["template-path"] = operator.templatePath
event.InternalEvent["template-info"] = operator.templateInfo event.InternalEvent["template-info"] = operator.templateInfo
if result == nil && !matched {
if err := e.options.Output.WriteFailure(event.InternalEvent); err != nil {
gologger.Warning().Msgf("Could not write failure event to output: %s\n", err)
}
continue
}
if matched && result != nil {
event.OperatorsResult = result
event.Results = e.requests.MakeResultEvent(event) event.Results = e.requests.MakeResultEvent(event)
results = true results = true
for _, r := range event.Results {
if e.options.IssuesClient != nil { _ = writer.WriteResult(event, e.options.Output, e.options.Progress, e.options.IssuesClient)
if err := e.options.IssuesClient.CreateIssue(r); err != nil {
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
}
}
_ = e.options.Output.Write(r)
e.options.Progress.IncrementMatched()
}
} }
} }
}) })

View File

@ -131,6 +131,11 @@ func (m *MockOutputWriter) Request(templateID, url, requestType string, err erro
} }
} }
// Write writes the event to file and/or screen.
func (m *MockOutputWriter) WriteFailure(result output.InternalEvent) error {
return nil
}
type MockProgressClient struct{} type MockProgressClient struct{}
// Stop stops the progress recorder. // Stop stops the progress recorder.

View File

@ -177,6 +177,8 @@ type Options struct {
NoUpdateTemplates bool NoUpdateTemplates bool
// EnvironmentVariables enables support for environment variables // EnvironmentVariables enables support for environment variables
EnvironmentVariables bool EnvironmentVariables bool
// MatcherStatus displays optional status for the failed matches as well
MatcherStatus bool
// ClientCertFile client certificate file (PEM-encoded) used for authenticating against scanned hosts // ClientCertFile client certificate file (PEM-encoded) used for authenticating against scanned hosts
ClientCertFile string ClientCertFile string
// ClientKeyFile client key file (PEM-encoded) used for authenticating against scanned hosts // ClientKeyFile client key file (PEM-encoded) used for authenticating against scanned hosts

View File

@ -0,0 +1,32 @@
package utils
import (
"strings"
"github.com/projectdiscovery/nuclei/v2/pkg/catalog/config"
)
const (
// TemplatesRepoURL is the URL for files in nuclei-templates repository
TemplatesRepoURL = "https://github.com/projectdiscovery/nuclei-templates/blob/master/"
)
var configData *config.Config
func init() {
configData, _ = config.ReadConfiguration()
}
// TemplatePathURL returns the Path and URL for the provided template
func TemplatePathURL(fullPath string) (string, string) {
var templateDirectory string
if configData != nil && configData.TemplatesDirectory != "" && strings.HasPrefix(fullPath, configData.TemplatesDirectory) {
templateDirectory = configData.TemplatesDirectory
} else {
return "", ""
}
finalPath := strings.TrimPrefix(strings.TrimPrefix(fullPath, templateDirectory), "/")
templateURL := TemplatesRepoURL + finalPath
return finalPath, templateURL
}