uniformed template loading

dev
Mzack9999 2020-06-26 14:37:55 +02:00
parent 226cb23c97
commit d3ceb76585
5 changed files with 99 additions and 76 deletions

View File

@ -27,7 +27,6 @@ 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
WorkflowFile string // Workflow file - experimental support for one workflow file
Stdin bool // Stdin specifies whether stdin input was given to the process
}
@ -52,7 +51,6 @@ 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.StringVar(&options.WorkflowFile, "workflow-file", "", "workflow-file")
flag.Parse()

View File

@ -80,47 +80,39 @@ func (r *Runner) Close() {
// RunEnumeration sets up the input layer for giving input nuclei.
// binary and runs the actual enumeration
func (r *Runner) RunEnumeration() {
// handles a single workflow
if r.options.WorkflowFile != "" {
workflow, err := workflows.Parse(r.options.WorkflowFile)
if err != nil {
gologger.Errorf("Could not parse workflow file '%s': %s\n", r.options.WorkflowFile, err)
return
}
r.ProcessWorkflowWithList(workflow)
return
}
// If the template path is a single template and not a glob, use that.
// Single yaml provided
if !strings.Contains(r.options.Templates, "*") && strings.HasSuffix(r.options.Templates, ".yaml") {
template, err := templates.ParseTemplate(r.options.Templates)
if err != nil {
gologger.Errorf("Could not parse template file '%s': %s\n", r.options.Templates, err)
return
}
// process http requests
var results bool
for _, request := range template.RequestsHTTP {
results = r.processTemplateRequest(template, request)
}
// process dns requests
for _, request := range template.RequestsDNS {
dnsResults := r.processTemplateRequest(template, request)
t := r.parse(r.options.Templates)
switch t.(type) {
case *templates.Template:
results := false
template := t.(*templates.Template)
for _, request := range template.RequestsHTTP {
results = r.processTemplateRequest(template, request)
}
for _, request := range template.RequestsDNS {
dnsResults := r.processTemplateRequest(template, request)
if !results {
results = dnsResults
}
}
if !results {
results = dnsResults
if r.output != nil {
outputFile := r.output.Name()
r.output.Close()
os.Remove(outputFile)
}
gologger.Infof("No results found for the template. Happy hacking!")
}
}
if !results {
if r.output != nil {
outputFile := r.output.Name()
r.output.Close()
os.Remove(outputFile)
}
gologger.Infof("No results found for the template. Happy hacking!")
case *workflows.Workflow:
workflow := t.(*workflows.Workflow)
r.ProcessWorkflowWithList(workflow)
default:
gologger.Errorf("Could not parse file '%s'\n", r.options.Templates)
}
return
}
// If the template path is glob
if strings.Contains(r.options.Templates, "*") {
// Handle the glob, evaluate it and run all the template file checks
@ -131,22 +123,27 @@ func (r *Runner) RunEnumeration() {
var results bool
for _, match := range matches {
template, err := templates.ParseTemplate(match)
if err != nil {
gologger.Errorf("Could not parse template file '%s': %s\n", match, err)
return
}
for _, request := range template.RequestsDNS {
dnsResults := r.processTemplateRequest(template, request)
if dnsResults {
results = dnsResults
t := r.parse(match)
switch t.(type) {
case *templates.Template:
template := t.(*templates.Template)
for _, request := range template.RequestsDNS {
dnsResults := r.processTemplateRequest(template, request)
if dnsResults {
results = dnsResults
}
}
}
for _, request := range template.RequestsHTTP {
httpResults := r.processTemplateRequest(template, request)
if httpResults {
results = httpResults
for _, request := range template.RequestsHTTP {
httpResults := r.processTemplateRequest(template, request)
if httpResults {
results = httpResults
}
}
case *workflows.Workflow:
workflow := t.(*workflows.Workflow)
r.ProcessWorkflowWithList(workflow)
default:
gologger.Errorf("Could not parse file '%s'\n", r.options.Templates)
}
}
if !results {
@ -183,22 +180,28 @@ func (r *Runner) RunEnumeration() {
}
var results bool
for _, match := range matches {
template, err := templates.ParseTemplate(match)
if err != nil {
gologger.Errorf("Could not parse template file '%s': %s\n", match, err)
return
}
for _, request := range template.RequestsDNS {
dnsResults := r.processTemplateRequest(template, request)
if dnsResults {
results = dnsResults
t := r.parse(match)
switch t.(type) {
case *templates.Template:
template := t.(*templates.Template)
for _, request := range template.RequestsDNS {
dnsResults := r.processTemplateRequest(template, request)
if dnsResults {
results = dnsResults
}
}
}
for _, request := range template.RequestsHTTP {
httpResults := r.processTemplateRequest(template, request)
if httpResults {
results = httpResults
for _, request := range template.RequestsHTTP {
httpResults := r.processTemplateRequest(template, request)
if httpResults {
results = httpResults
}
}
case *workflows.Workflow:
workflow := t.(*workflows.Workflow)
r.ProcessWorkflowWithList(workflow)
default:
gologger.Errorf("Could not parse file '%s'\n", r.options.Templates)
}
}
if !results {
@ -385,3 +388,19 @@ func (r *Runner) ProcessWorkflow(workflow *workflows.Workflow, URL string) error
return nil
}
func (r *Runner) parse(file string) interface{} {
// check if it's a template
template, errTemplate := templates.ParseTemplate(r.options.Templates)
if errTemplate == nil {
return template
}
// check if it's a workflow
workflow, errWorkflow := workflows.Parse(r.options.Templates)
if errWorkflow == nil {
return workflow
}
return nil
}

View File

@ -14,16 +14,13 @@ func (options *Options) validateOptions() error {
return errors.New("both verbose and silent mode specified")
}
// Workflow needs to bypass the classical input checks
if options.WorkflowFile == "" {
// Check if a list of templates was provided and it exists
if options.Templates == "" && !options.UpdateTemplates {
return errors.New("no template/templates provided")
}
// Check if a list of templates was provided and it exists
if options.Templates == "" && !options.UpdateTemplates {
return errors.New("no template/templates provided")
}
if options.Targets == "" && !options.Stdin && !options.UpdateTemplates {
return errors.New("no target input provided")
}
if options.Targets == "" && !options.Stdin && !options.UpdateTemplates {
return errors.New("no target input provided")
}
// Validate proxy options if provided

View File

@ -1,6 +1,7 @@
package templates
import (
"errors"
"fmt"
"os"
@ -20,10 +21,13 @@ func ParseTemplate(file string) (*Template, error) {
err = yaml.NewDecoder(f).Decode(template)
if err != nil {
f.Close()
return nil, err
}
f.Close()
defer f.Close()
if len(template.RequestsHTTP)+len(template.RequestsDNS) <= 0 {
return nil, errors.New("No requests defined")
}
// Compile the matchers and the extractors for http requests
for _, request := range template.RequestsHTTP {

View File

@ -1,6 +1,7 @@
package workflows
import (
"errors"
"os"
"gopkg.in/yaml.v2"
@ -21,5 +22,9 @@ func Parse(file string) (*Workflow, error) {
return nil, err
}
if workflow.Logic == "" {
return nil, errors.New("No logic provided")
}
return workflow, nil
}