mirror of https://github.com/daffainfo/nuclei.git
json-request option for request/response output in JSON matches
parent
94ba9acbbf
commit
b3fb45d381
|
@ -29,6 +29,7 @@ type Options struct {
|
||||||
UpdateTemplates bool // UpdateTemplates updates the templates installed at startup
|
UpdateTemplates bool // UpdateTemplates updates the templates installed at startup
|
||||||
TemplatesDirectory string // TemplatesDirectory is the directory to use for storing templates
|
TemplatesDirectory string // TemplatesDirectory is the directory to use for storing templates
|
||||||
JSON bool // JSON writes json output to files
|
JSON bool // JSON writes json output to files
|
||||||
|
JSONRequests bool // write requests/responses for matches in JSON output
|
||||||
|
|
||||||
Stdin bool // Stdin specifies whether stdin input was given to the process
|
Stdin bool // Stdin specifies whether stdin input was given to the process
|
||||||
}
|
}
|
||||||
|
@ -66,6 +67,7 @@ func ParseOptions() *Options {
|
||||||
flag.BoolVar(&options.UpdateTemplates, "update-templates", false, "Update Templates updates the installed templates (optional)")
|
flag.BoolVar(&options.UpdateTemplates, "update-templates", false, "Update Templates updates the installed templates (optional)")
|
||||||
flag.StringVar(&options.TemplatesDirectory, "update-directory", "", "Directory to use for storing nuclei-templates")
|
flag.StringVar(&options.TemplatesDirectory, "update-directory", "", "Directory to use for storing nuclei-templates")
|
||||||
flag.BoolVar(&options.JSON, "json", false, "Write json output to files")
|
flag.BoolVar(&options.JSON, "json", false, "Write json output to files")
|
||||||
|
flag.BoolVar(&options.JSONRequests, "json-requests", false, "Write requests/responses for matches in JSON output")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,7 @@ func (r *Runner) processTemplateWithList(template *templates.Template, request i
|
||||||
ProxySocksURL: r.options.ProxySocksURL,
|
ProxySocksURL: r.options.ProxySocksURL,
|
||||||
CustomHeaders: r.options.CustomHeaders,
|
CustomHeaders: r.options.CustomHeaders,
|
||||||
JSON: r.options.JSON,
|
JSON: r.options.JSON,
|
||||||
|
JSONRequests: r.options.JSONRequests,
|
||||||
CookieReuse: value.CookieReuse,
|
CookieReuse: value.CookieReuse,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ type HTTPExecuter struct {
|
||||||
debug bool
|
debug bool
|
||||||
Results bool
|
Results bool
|
||||||
jsonOutput bool
|
jsonOutput bool
|
||||||
|
jsonRequest bool
|
||||||
httpClient *retryablehttp.Client
|
httpClient *retryablehttp.Client
|
||||||
template *templates.Template
|
template *templates.Template
|
||||||
bulkHttpRequest *requests.BulkHTTPRequest
|
bulkHttpRequest *requests.BulkHTTPRequest
|
||||||
|
@ -50,6 +51,7 @@ type HTTPOptions struct {
|
||||||
ProxySocksURL string
|
ProxySocksURL string
|
||||||
Debug bool
|
Debug bool
|
||||||
JSON bool
|
JSON bool
|
||||||
|
JSONRequests bool
|
||||||
CustomHeaders requests.CustomHeaders
|
CustomHeaders requests.CustomHeaders
|
||||||
CookieReuse bool
|
CookieReuse bool
|
||||||
CookieJar *cookiejar.Jar
|
CookieJar *cookiejar.Jar
|
||||||
|
@ -84,6 +86,7 @@ func NewHTTPExecuter(options *HTTPOptions) (*HTTPExecuter, error) {
|
||||||
executer := &HTTPExecuter{
|
executer := &HTTPExecuter{
|
||||||
debug: options.Debug,
|
debug: options.Debug,
|
||||||
jsonOutput: options.JSON,
|
jsonOutput: options.JSON,
|
||||||
|
jsonRequest: options.JSONRequests,
|
||||||
httpClient: client,
|
httpClient: client,
|
||||||
template: options.Template,
|
template: options.Template,
|
||||||
bulkHttpRequest: options.BulkHttpRequest,
|
bulkHttpRequest: options.BulkHttpRequest,
|
||||||
|
@ -187,7 +190,7 @@ func (e *HTTPExecuter) handleHTTP(URL string, request *requests.HttpRequest, dyn
|
||||||
result.Matches[matcher.Name] = nil
|
result.Matches[matcher.Name] = nil
|
||||||
// probably redundant but ensures we snapshot current payload values when matchers are valid
|
// probably redundant but ensures we snapshot current payload values when matchers are valid
|
||||||
result.Meta = request.Meta
|
result.Meta = request.Meta
|
||||||
e.writeOutputHTTP(request, matcher, nil)
|
e.writeOutputHTTP(request, resp, body, matcher, nil)
|
||||||
e.Results = true
|
e.Results = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +214,7 @@ func (e *HTTPExecuter) handleHTTP(URL string, request *requests.HttpRequest, dyn
|
||||||
// Write a final string of output if matcher type is
|
// Write a final string of output if matcher type is
|
||||||
// AND or if we have extractors for the mechanism too.
|
// AND or if we have extractors for the mechanism too.
|
||||||
if len(e.bulkHttpRequest.Extractors) > 0 || matcherCondition == matchers.ANDCondition {
|
if len(e.bulkHttpRequest.Extractors) > 0 || matcherCondition == matchers.ANDCondition {
|
||||||
e.writeOutputHTTP(request, nil, extractorResults)
|
e.writeOutputHTTP(request, resp, body, nil, extractorResults)
|
||||||
e.Results = true
|
e.Results = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ type jsonOutput struct {
|
||||||
Severity string `json:"severity"`
|
Severity string `json:"severity"`
|
||||||
Author string `json:"author"`
|
Author string `json:"author"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
Request string `json:"request,omitempty"`
|
||||||
|
Response string `json:"response,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsafeToString converts byte slice to string with zero allocations
|
// unsafeToString converts byte slice to string with zero allocations
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package executer
|
package executer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
|
@ -10,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// writeOutputHTTP writes http output to streams
|
// writeOutputHTTP writes http output to streams
|
||||||
func (e *HTTPExecuter) writeOutputHTTP(req *requests.HttpRequest, matcher *matchers.Matcher, extractorResults []string) {
|
func (e *HTTPExecuter) writeOutputHTTP(req *requests.HttpRequest, resp *http.Response, body string, matcher *matchers.Matcher, extractorResults []string) {
|
||||||
URL := req.Request.URL.String()
|
URL := req.Request.URL.String()
|
||||||
|
|
||||||
if e.jsonOutput {
|
if e.jsonOutput {
|
||||||
|
@ -28,6 +30,21 @@ func (e *HTTPExecuter) writeOutputHTTP(req *requests.HttpRequest, matcher *match
|
||||||
if len(extractorResults) > 0 {
|
if len(extractorResults) > 0 {
|
||||||
output.ExtractedResults = extractorResults
|
output.ExtractedResults = extractorResults
|
||||||
}
|
}
|
||||||
|
if e.jsonRequest {
|
||||||
|
dumpedRequest, err := httputil.DumpRequest(req.Request.Request, true)
|
||||||
|
if err != nil {
|
||||||
|
gologger.Warningf("could not dump request: %s\n", err)
|
||||||
|
} else {
|
||||||
|
output.Request = string(dumpedRequest)
|
||||||
|
}
|
||||||
|
dumpedResponse, err := httputil.DumpResponse(resp, false)
|
||||||
|
if err != nil {
|
||||||
|
gologger.Warningf("could not dump response: %s\n", err)
|
||||||
|
} else {
|
||||||
|
output.Response = string(dumpedResponse) + body
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
data, err := jsoniter.Marshal(output)
|
data, err := jsoniter.Marshal(output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gologger.Warningf("Could not marshal json output: %s\n", err)
|
gologger.Warningf("Could not marshal json output: %s\n", err)
|
||||||
|
|
Loading…
Reference in New Issue