Merge pull request #114 from projectdiscovery/iceman-json-output

Added json output support
dev
Ice3man 2020-06-27 07:50:25 -07:00 committed by GitHub
commit 952058c202
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 84 additions and 1 deletions

View File

@ -28,6 +28,7 @@ type Options struct {
CustomHeaders requests.CustomHeaders // Custom global headers
UpdateTemplates bool // UpdateTemplates updates the templates installed at startup
TemplatesDirectory string // TemplatesDirectory is the directory to use for storing templates
JSON bool // JSON writes json output to files
Stdin bool // Stdin specifies whether stdin input was given to the process
}
@ -53,6 +54,7 @@ func ParseOptions() *Options {
flag.BoolVar(&options.Debug, "debug", false, "Allow debugging of request/responses")
flag.BoolVar(&options.UpdateTemplates, "update-templates", false, "Update Templates updates the installed templates (optional)")
flag.StringVar(&options.TemplatesDirectory, "templates-directory", "", "Directory to use for storing nuclei-templates")
flag.BoolVar(&options.JSON, "json", false, "Write json output to files")
flag.Parse()

View File

@ -253,6 +253,7 @@ func (r *Runner) processTemplateWithList(template *templates.Template, request i
Template: template,
DNSRequest: value,
Writer: writer,
JSON: r.options.JSON,
})
case *requests.HTTPRequest:
httpExecutor, err = executor.NewHTTPExecutor(&executor.HTTPOptions{
@ -265,6 +266,7 @@ func (r *Runner) processTemplateWithList(template *templates.Template, request i
ProxyURL: r.options.ProxyURL,
ProxySocksURL: r.options.ProxySocksURL,
CustomHeaders: r.options.CustomHeaders,
JSON: r.options.JSON,
})
}
if err != nil {

View File

@ -30,6 +30,7 @@ import (
type HTTPExecutor struct {
debug bool
results uint32
jsonOutput bool
httpClient *retryablehttp.Client
template *templates.Template
httpRequest *requests.HTTPRequest
@ -48,6 +49,7 @@ type HTTPOptions struct {
ProxyURL string
ProxySocksURL string
Debug bool
JSON bool
CustomHeaders requests.CustomHeaders
}
@ -70,6 +72,7 @@ func NewHTTPExecutor(options *HTTPOptions) (*HTTPExecutor, error) {
executer := &HTTPExecutor{
debug: options.Debug,
jsonOutput: options.JSON,
results: 0,
httpClient: client,
template: options.Template,

View File

@ -19,6 +19,7 @@ import (
// for a template.
type DNSExecutor struct {
debug bool
jsonOutput bool
results uint32
dnsClient *retryabledns.Client
template *templates.Template
@ -38,6 +39,7 @@ var DefaultResolvers = []string{
// DNSOptions contains configuration options for the DNS executor.
type DNSOptions struct {
Debug bool
JSON bool
Template *templates.Template
DNSRequest *requests.DNSRequest
Writer *bufio.Writer
@ -50,6 +52,7 @@ func NewDNSExecutor(options *DNSOptions) *DNSExecutor {
executer := &DNSExecutor{
debug: options.Debug,
jsonOutput: options.JSON,
results: 0,
dnsClient: dnsClient,
template: options.Template,

View File

@ -6,6 +6,16 @@ import (
"unsafe"
)
type jsonOutput struct {
Template string `json:"template"`
Type string `json:"type"`
Matched string `json:"matched"`
MatcherName string `json:"matcher_name,omitempty"`
ExtractedResults []string `json:"extracted_results,omitempty"`
Severity string `json:"severity"`
Author string `json:"author"`
}
// unsafeToString converts byte slice to string with zero allocations
func unsafeToString(bs []byte) string {
return *(*string)(unsafe.Pointer(&bs))

View File

@ -3,12 +3,43 @@ package executor
import (
"strings"
jsoniter "github.com/json-iterator/go"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/pkg/matchers"
)
// writeOutputDNS writes dns output to streams
func (e *DNSExecutor) writeOutputDNS(domain string, matcher *matchers.Matcher, extractorResults []string) {
if e.jsonOutput {
output := jsonOutput{
Template: e.template.ID,
Type: "dns",
Matched: domain,
Severity: e.template.Info.Severity,
Author: e.template.Info.Author,
}
if matcher != nil && len(matcher.Name) > 0 {
output.MatcherName = matcher.Name
}
if len(extractorResults) > 0 {
output.ExtractedResults = extractorResults
}
data, err := jsoniter.Marshal(output)
if err != nil {
gologger.Warningf("Could not marshal json output: %s\n", err)
}
gologger.Silentf("%s", string(data))
if e.writer != nil {
e.outputMutex.Lock()
e.writer.Write(data)
e.writer.WriteRune('\n')
e.outputMutex.Unlock()
}
return
}
builder := &strings.Builder{}
builder.WriteRune('[')
builder.WriteString(e.template.ID)

View File

@ -3,6 +3,7 @@ package executor
import (
"strings"
jsoniter "github.com/json-iterator/go"
"github.com/projectdiscovery/gologger"
"github.com/projectdiscovery/nuclei/pkg/matchers"
"github.com/projectdiscovery/nuclei/pkg/requests"
@ -10,6 +11,38 @@ import (
// writeOutputHTTP writes http output to streams
func (e *HTTPExecutor) writeOutputHTTP(req *requests.CompiledHTTP, matcher *matchers.Matcher, extractorResults []string) {
URL := req.Request.URL.String()
if e.jsonOutput {
output := jsonOutput{
Template: e.template.ID,
Type: "http",
Matched: URL,
Severity: e.template.Info.Severity,
Author: e.template.Info.Author,
}
if matcher != nil && len(matcher.Name) > 0 {
output.MatcherName = matcher.Name
}
if len(extractorResults) > 0 {
output.ExtractedResults = extractorResults
}
data, err := jsoniter.Marshal(output)
if err != nil {
gologger.Warningf("Could not marshal json output: %s\n", err)
}
gologger.Silentf("%s", string(data))
if e.writer != nil {
e.outputMutex.Lock()
e.writer.Write(data)
e.writer.WriteRune('\n')
e.outputMutex.Unlock()
}
return
}
builder := &strings.Builder{}
builder.WriteRune('[')
@ -21,7 +54,6 @@ func (e *HTTPExecutor) writeOutputHTTP(req *requests.CompiledHTTP, matcher *matc
builder.WriteString("] [http] ")
// Escape the URL by replacing all % with %%
URL := req.Request.URL.String()
escapedURL := strings.Replace(URL, "%", "%%", -1)
builder.WriteString(escapedURL)