From 42b3a5d3e2e98c7cb91b0861f7de2750dd721ea0 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Thu, 24 Feb 2022 14:32:41 +0530 Subject: [PATCH 1/2] Allow random resume file generation on conflict + made resume string flag --- v2/cmd/nuclei/main.go | 4 ++-- v2/internal/runner/runner.go | 7 +++---- v2/pkg/types/resume.go | 11 ++++++++++- v2/pkg/types/types.go | 4 ++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/v2/cmd/nuclei/main.go b/v2/cmd/nuclei/main.go index 5685245dd..9cd8a948d 100644 --- a/v2/cmd/nuclei/main.go +++ b/v2/cmd/nuclei/main.go @@ -50,7 +50,7 @@ func main() { nucleiRunner.Close() if options.ShouldSaveResume() { gologger.Info().Msgf("Creating resume file: %s\n", resumeFileName) - err := nucleiRunner.SaveResumeConfig() + err := nucleiRunner.SaveResumeConfig(resumeFileName) if err != nil { gologger.Error().Msgf("Couldn't create resume file: %s\n", err) } @@ -84,7 +84,7 @@ on extensive configurability, massive extensibility and ease of use.`) createGroup(flagSet, "input", "Target", flagSet.StringSliceVarP(&options.Targets, "target", "u", []string{}, "target URLs/hosts to scan"), flagSet.StringVarP(&options.TargetsFilePath, "list", "l", "", "path to file containing a list of target URLs/hosts to scan (one per line)"), - flagSet.BoolVar(&options.Resume, "resume", false, "Resume scan using resume.cfg (clustering will be disabled)"), + flagSet.StringVar(&options.Resume, "resume", "", "Resume scan using resume.cfg (clustering will be disabled)"), ) createGroup(flagSet, "templates", "Templates", diff --git a/v2/internal/runner/runner.go b/v2/internal/runner/runner.go index 333805119..6eb284e18 100644 --- a/v2/internal/runner/runner.go +++ b/v2/internal/runner/runner.go @@ -158,7 +158,7 @@ func New(options *types.Options) (*Runner, error) { resumeCfg := types.NewResumeCfg() if runner.options.ShouldLoadResume() { gologger.Info().Msg("Resuming from save checkpoint") - file, err := ioutil.ReadFile(types.DefaultResumeFilePath()) + file, err := ioutil.ReadFile(runner.options.Resume) if err != nil { return nil, err } @@ -168,7 +168,6 @@ func New(options *types.Options) (*Runner, error) { } resumeCfg.Compile() } - runner.resumeCfg = resumeCfg opts := interactsh.NewDefaultOptions(runner.output, runner.issuesClient, runner.progress) @@ -496,10 +495,10 @@ func isTemplate(filename string) bool { } // SaveResumeConfig to file -func (r *Runner) SaveResumeConfig() error { +func (r *Runner) SaveResumeConfig(path string) error { resumeCfg := types.NewResumeCfg() resumeCfg.ResumeFrom = r.resumeCfg.Current data, _ := json.MarshalIndent(resumeCfg, "", "\t") - return os.WriteFile(types.DefaultResumeFilePath(), data, os.ModePerm) + return os.WriteFile(path, data, os.ModePerm) } diff --git a/v2/pkg/types/resume.go b/v2/pkg/types/resume.go index 930b6fd12..60daabc18 100644 --- a/v2/pkg/types/resume.go +++ b/v2/pkg/types/resume.go @@ -1,10 +1,13 @@ package types import ( + "fmt" "math" "os" "path/filepath" "sync" + + "github.com/rs/xid" ) // Default resume file @@ -15,7 +18,13 @@ func DefaultResumeFilePath() string { if err != nil { return DefaultResumeFileName } - return filepath.Join(home, ".config", "nuclei", DefaultResumeFileName) + resumeFile := filepath.Join(home, ".config", "nuclei", DefaultResumeFileName) + + // Generate random name if already exists + if _, err := os.Stat(resumeFile); !os.IsNotExist(err) { + resumeFile = filepath.Join(home, ".config", "nuclei", fmt.Sprintf("resume-%s.cfg", xid.New().String())) + } + return resumeFile } // ResumeCfg contains the scan progression diff --git a/v2/pkg/types/types.go b/v2/pkg/types/types.go index c0bce5cb7..5e222681e 100644 --- a/v2/pkg/types/types.go +++ b/v2/pkg/types/types.go @@ -64,7 +64,7 @@ type Options struct { // TargetsFilePath specifies the targets from a file to scan using templates. TargetsFilePath string // Resume the scan from the state stored in the resume config file - Resume bool + Resume string // Output is the file to write found results to. Output string // List of HTTP(s)/SOCKS5 proxy to use (comma separated or file input) @@ -214,7 +214,7 @@ func (options *Options) VarsPayload() map[string]interface{} { // ShouldLoadResume resume file func (options *Options) ShouldLoadResume() bool { - return options.Resume && fileutil.FileExists(DefaultResumeFilePath()) + return options.Resume != "" && fileutil.FileExists(options.Resume) } // ShouldSaveResume file From 9e1e86d89fd8681f8821380517930dbeb95a1c67 Mon Sep 17 00:00:00 2001 From: Ice3man Date: Thu, 24 Feb 2022 14:34:37 +0530 Subject: [PATCH 2/2] Use random names by default to avoid collision --- v2/pkg/types/resume.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/v2/pkg/types/resume.go b/v2/pkg/types/resume.go index 60daabc18..5308888ef 100644 --- a/v2/pkg/types/resume.go +++ b/v2/pkg/types/resume.go @@ -11,19 +11,14 @@ import ( ) // Default resume file -const DefaultResumeFileName = "resume.cfg" +const DefaultResumeFileName = "resume-%s.cfg" func DefaultResumeFilePath() string { home, err := os.UserHomeDir() if err != nil { - return DefaultResumeFileName - } - resumeFile := filepath.Join(home, ".config", "nuclei", DefaultResumeFileName) - - // Generate random name if already exists - if _, err := os.Stat(resumeFile); !os.IsNotExist(err) { - resumeFile = filepath.Join(home, ".config", "nuclei", fmt.Sprintf("resume-%s.cfg", xid.New().String())) + return fmt.Sprintf("resume-%s.cfg", xid.New().String()) } + resumeFile := filepath.Join(home, ".config", "nuclei", fmt.Sprintf("resume-%s.cfg", xid.New().String())) return resumeFile }