mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-22 15:25:24 +00:00
merged master
This commit is contained in:
commit
c2433fdb34
@ -12,7 +12,7 @@ import (
|
||||
// the template requesting process.
|
||||
type Options struct {
|
||||
Debug bool // Debug mode allows debugging request/responses for the engine
|
||||
Templates string // Signature specifies the template/templates to use
|
||||
Templates multiStringFlag // Signature specifies the template/templates to use
|
||||
Target string // Target is a single URL/Domain to scan usng a template
|
||||
Targets string // Targets specifies the targets to scan using templates.
|
||||
Threads int // Thread controls the number of concurrent requests to make.
|
||||
@ -33,12 +33,23 @@ type Options struct {
|
||||
Stdin bool // Stdin specifies whether stdin input was given to the process
|
||||
}
|
||||
|
||||
type multiStringFlag []string
|
||||
|
||||
func (m *multiStringFlag) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *multiStringFlag) Set(value string) error {
|
||||
*m = append(*m, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseOptions parses the command line flags provided by a user
|
||||
func ParseOptions() *Options {
|
||||
options := &Options{}
|
||||
|
||||
flag.StringVar(&options.Target, "target", "", "Target is a single target to scan using template")
|
||||
flag.StringVar(&options.Templates, "t", "", "Template input file/files to run on host")
|
||||
flag.Var(&options.Templates, "t","Template input file/files to run on host. Can be used multiple times.")
|
||||
flag.StringVar(&options.Targets, "l", "", "List of URLs to run templates on")
|
||||
flag.StringVar(&options.Output, "o", "", "File to write output to (optional)")
|
||||
flag.StringVar(&options.ProxyURL, "proxy-url", "", "URL of the proxy server")
|
||||
|
||||
@ -44,7 +44,7 @@ func New(options *Options) (*Runner, error) {
|
||||
if err := runner.updateTemplates(); err != nil {
|
||||
gologger.Warningf("Could not update templates: %s\n", err)
|
||||
}
|
||||
if (options.Templates == "" || (options.Targets == "" && !options.Stdin && options.Target == "")) && options.UpdateTemplates {
|
||||
if (len(options.Templates) == 0 || (options.Targets == "" && !options.Stdin && options.Target == "")) && options.UpdateTemplates {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@ -88,84 +88,112 @@ func (r *Runner) Close() {
|
||||
os.Remove(r.tempFile)
|
||||
}
|
||||
|
||||
func isFilePath(path string) (bool, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return info.Mode().IsRegular(), nil
|
||||
}
|
||||
|
||||
func (r *Runner) resolvePathIfRelative(path string) (string, error) {
|
||||
if r.isRelative(path) {
|
||||
newPath, err := r.resolvePath(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return newPath, nil
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func isNewPath(path string, pathMap map[string]bool) bool {
|
||||
if _, already := pathMap[path]; already {
|
||||
gologger.Warningf("Skipping already specified path '%s'", path)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// RunEnumeration sets up the input layer for giving input nuclei.
|
||||
// binary and runs the actual enumeration
|
||||
func (r *Runner) RunEnumeration() {
|
||||
var err error
|
||||
// keeps track of processed dirs and files
|
||||
processed := make(map[string]bool)
|
||||
allTemplates := []string{}
|
||||
|
||||
// Check if the template is an absolute path or relative path.
|
||||
// If the path is absolute, use it. Otherwise,
|
||||
if r.isRelative(r.options.Templates) {
|
||||
newPath, err := r.resolvePath(r.options.Templates)
|
||||
// parses user input, handle file/directory cases and produce a list of unique templates
|
||||
for _, t := range r.options.Templates {
|
||||
// resolve and convert relative to absolute path
|
||||
absPath, err := r.resolvePathIfRelative(t)
|
||||
if err != nil {
|
||||
gologger.Errorf("Could not find template file '%s': %s\n", r.options.Templates, err)
|
||||
return
|
||||
gologger.Errorf("Could not find template file '%s': %s\n", t, err)
|
||||
continue
|
||||
}
|
||||
r.options.Templates = newPath
|
||||
}
|
||||
|
||||
// Single yaml provided
|
||||
if strings.HasSuffix(r.options.Templates, ".yaml") {
|
||||
t, err := r.parse(r.options.Templates)
|
||||
switch t.(type) {
|
||||
case *templates.Template:
|
||||
var results bool
|
||||
template := t.(*templates.Template)
|
||||
// process http requests
|
||||
for _, request := range template.BulkRequestsHTTP {
|
||||
results = r.processTemplateRequest(template, request)
|
||||
}
|
||||
// process dns requests
|
||||
for _, request := range template.RequestsDNS {
|
||||
dnsResults := r.processTemplateRequest(template, request)
|
||||
if !results {
|
||||
results = dnsResults
|
||||
}
|
||||
}
|
||||
|
||||
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': %s\n", r.options.Templates, err)
|
||||
// determine file/directory
|
||||
isFile, err := isFilePath(absPath)
|
||||
if err != nil {
|
||||
gologger.Errorf("Could not stat '%s': %s\n", absPath, err)
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If the template passed is a directory
|
||||
matches := []string{}
|
||||
// test for uniqueness
|
||||
if !isNewPath(absPath, processed) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Recursively walk down the Templates directory and run all the template file checks
|
||||
err = godirwalk.Walk(r.options.Templates, &godirwalk.Options{
|
||||
Callback: func(path string, d *godirwalk.Dirent) error {
|
||||
if !d.IsDir() && strings.HasSuffix(path, ".yaml") {
|
||||
matches = append(matches, path)
|
||||
// mark this absolute path as processed
|
||||
// - if it's a file, we'll never process it again
|
||||
// - if it's a dir, we'll never walk it again
|
||||
processed[absPath] = true
|
||||
|
||||
if isFile {
|
||||
allTemplates = append(allTemplates, absPath)
|
||||
} else {
|
||||
matches := []string{}
|
||||
|
||||
// Recursively walk down the Templates directory and run all the template file checks
|
||||
err = godirwalk.Walk(absPath, &godirwalk.Options{
|
||||
Callback: func(path string, d *godirwalk.Dirent) error {
|
||||
if !d.IsDir() && strings.HasSuffix(path, ".yaml") {
|
||||
if isNewPath(path, processed) {
|
||||
matches = append(matches, path)
|
||||
processed[path] = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ErrorCallback: func(path string, err error) godirwalk.ErrorAction {
|
||||
return godirwalk.SkipNode
|
||||
},
|
||||
Unsorted: true,
|
||||
})
|
||||
|
||||
// directory couldn't be walked
|
||||
if err != nil {
|
||||
gologger.Labelf("Could not find templates in directory '%s': %s\n", absPath, err)
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ErrorCallback: func(path string, err error) godirwalk.ErrorAction {
|
||||
return godirwalk.SkipNode
|
||||
},
|
||||
Unsorted: true,
|
||||
})
|
||||
if err != nil {
|
||||
gologger.Fatalf("Could not find templates in directory '%s': %s\n", r.options.Templates, err)
|
||||
|
||||
// couldn't find templates in directory
|
||||
if len(matches) == 0 {
|
||||
gologger.Labelf("Error, no templates were found in '%s'.\n", absPath)
|
||||
continue
|
||||
}
|
||||
|
||||
allTemplates = append(allTemplates, matches...)
|
||||
}
|
||||
}
|
||||
|
||||
// 0 matches means no templates were found in directory
|
||||
if len(matches) == 0 {
|
||||
gologger.Fatalf("Error, no templates found in directory: '%s'\n", r.options.Templates)
|
||||
if len(allTemplates) == 0 {
|
||||
gologger.Fatalf("Error, no templates were found.\n")
|
||||
}
|
||||
|
||||
// run with the specified templates
|
||||
var results bool
|
||||
for _, match := range matches {
|
||||
for _, match := range allTemplates {
|
||||
t, err := r.parse(match)
|
||||
switch t.(type) {
|
||||
case *templates.Template:
|
||||
@ -195,7 +223,7 @@ func (r *Runner) RunEnumeration() {
|
||||
r.output.Close()
|
||||
os.Remove(outputFile)
|
||||
}
|
||||
gologger.Infof("No results found for the template. Happy hacking!")
|
||||
gologger.Infof("No results found. Happy hacking!")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ func (options *Options) validateOptions() error {
|
||||
}
|
||||
|
||||
// Check if a list of templates was provided and it exists
|
||||
if options.Templates == "" && !options.UpdateTemplates {
|
||||
if len(options.Templates) == 0 && !options.UpdateTemplates {
|
||||
return errors.New("no template/templates provided")
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user