From 96049a32fa70aef0483d4180d386a57b3c2d973a Mon Sep 17 00:00:00 2001 From: Ice3man543 Date: Sun, 13 Dec 2020 13:31:12 +0530 Subject: [PATCH 1/3] Sandboxed workflows to only run safe commands --- v2/internal/runner/processor.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/v2/internal/runner/processor.go b/v2/internal/runner/processor.go index 8b3bd66c..2c425e36 100644 --- a/v2/internal/runner/processor.go +++ b/v2/internal/runner/processor.go @@ -143,10 +143,19 @@ func (r *Runner) processWorkflowWithList(p *progress.Progress, workflow *workflo defer wg.Done() script := tengo.NewScript(logicBytes) - script.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...)) + var moduleNames = []string{ + "math", + "text", + "rand", + "fmt", + "json", + "base64", + "hex", + "enum", + } + script.SetImports(stdlib.GetModuleMap(moduleNames...)) variables := make(map[string]*workflows.NucleiVar) - for _, workflowTemplate := range *workflowTemplatesList { name := workflowTemplate.Name variable := &workflows.NucleiVar{Templates: workflowTemplate.Templates, URL: targetURL} From cf2a98b03d76327c20fb0183b7f1c849eb692c91 Mon Sep 17 00:00:00 2001 From: Ice3man543 Date: Sun, 13 Dec 2020 14:04:58 +0530 Subject: [PATCH 2/3] Added flag to control workflow sandboxing --- v2/internal/runner/options.go | 2 ++ v2/internal/runner/processor.go | 18 +++++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/v2/internal/runner/options.go b/v2/internal/runner/options.go index 27cb69ec..85b6d35c 100644 --- a/v2/internal/runner/options.go +++ b/v2/internal/runner/options.go @@ -14,6 +14,7 @@ import ( // the template requesting process. // nolint // false positive, options are allocated once and are necessary as is type Options struct { + Sandbox bool // Sandbox mode allows users to run isolated workflows with system commands disabled Debug bool // Debug mode allows debugging request/responses for the engine Silent bool // Silent suppresses any extra text and only writes found URLs on screen. Version bool // Version specifies if we should just show version and exit @@ -66,6 +67,7 @@ func (m *multiStringFlag) Set(value string) error { func ParseOptions() *Options { options := &Options{} + flag.BoolVar(&options.Sandbox, "sandbox", false, "Run workflows in isolated sandbox mode") flag.StringVar(&options.Target, "target", "", "Target is a single target to scan using template") flag.Var(&options.Templates, "t", "Template input dir/file/files to run on host. Can be used multiple times. Supports globbing.") flag.Var(&options.ExcludedTemplates, "exclude", "Template input dir/file/files to exclude. Can be used multiple times. Supports globbing.") diff --git a/v2/internal/runner/processor.go b/v2/internal/runner/processor.go index 2c425e36..9bfd30ae 100644 --- a/v2/internal/runner/processor.go +++ b/v2/internal/runner/processor.go @@ -28,6 +28,8 @@ type workflowTemplates struct { Templates []*workflows.Template } +var sandboxedModules = []string{"math", "text", "rand", "fmt", "json", "base64", "hex", "enum"} + // processTemplateWithList processes a template and runs the enumeration on all the targets func (r *Runner) processTemplateWithList(p *progress.Progress, template *templates.Template, request interface{}) bool { var httpExecuter *executer.HTTPExecuter @@ -128,7 +130,7 @@ func (r *Runner) processWorkflowWithList(p *progress.Progress, workflow *workflo workflowTemplatesList, err := r.preloadWorkflowTemplates(p, workflow) if err != nil { gologger.Warningf("Could not preload templates for workflow %s: %s\n", workflow.ID, err) - return result + return false } logicBytes := []byte(workflow.Logic) @@ -143,17 +145,11 @@ func (r *Runner) processWorkflowWithList(p *progress.Progress, workflow *workflo defer wg.Done() script := tengo.NewScript(logicBytes) - var moduleNames = []string{ - "math", - "text", - "rand", - "fmt", - "json", - "base64", - "hex", - "enum", + if !r.options.Sandbox { + script.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...)) + } else { + script.SetImports(stdlib.GetModuleMap(sandboxedModules...)) } - script.SetImports(stdlib.GetModuleMap(moduleNames...)) variables := make(map[string]*workflows.NucleiVar) for _, workflowTemplate := range *workflowTemplatesList { From 2ae13d845ab29cc72e0e76533534e5bb6fb62a54 Mon Sep 17 00:00:00 2001 From: Ice3man543 Date: Sun, 13 Dec 2020 14:17:58 +0530 Subject: [PATCH 3/3] Max limit on execution of a workflow --- v2/internal/runner/options.go | 4 +++- v2/internal/runner/processor.go | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/v2/internal/runner/options.go b/v2/internal/runner/options.go index 85b6d35c..8dfa7f19 100644 --- a/v2/internal/runner/options.go +++ b/v2/internal/runner/options.go @@ -14,7 +14,8 @@ import ( // the template requesting process. // nolint // false positive, options are allocated once and are necessary as is type Options struct { - Sandbox bool // Sandbox mode allows users to run isolated workflows with system commands disabled + MaxWorkflowDuration int // MaxWorkflowDuration is the maximum time a workflow can run for a URL + Sandbox bool // Sandbox mode allows users to run isolated workflows with system commands disabled Debug bool // Debug mode allows debugging request/responses for the engine Silent bool // Silent suppresses any extra text and only writes found URLs on screen. Version bool // Version specifies if we should just show version and exit @@ -68,6 +69,7 @@ func ParseOptions() *Options { options := &Options{} flag.BoolVar(&options.Sandbox, "sandbox", false, "Run workflows in isolated sandbox mode") + flag.IntVar(&options.MaxWorkflowDuration, "workflow-duration", 10, "Max time for workflow run on single URL in minutes") flag.StringVar(&options.Target, "target", "", "Target is a single target to scan using template") flag.Var(&options.Templates, "t", "Template input dir/file/files to run on host. Can be used multiple times. Supports globbing.") flag.Var(&options.ExcludedTemplates, "exclude", "Template input dir/file/files to exclude. Can be used multiple times. Supports globbing.") diff --git a/v2/internal/runner/processor.go b/v2/internal/runner/processor.go index 9bfd30ae..2cd28861 100644 --- a/v2/internal/runner/processor.go +++ b/v2/internal/runner/processor.go @@ -8,6 +8,7 @@ import ( "path" "path/filepath" "strings" + "time" tengo "github.com/d5/tengo/v2" "github.com/d5/tengo/v2/stdlib" @@ -132,11 +133,9 @@ func (r *Runner) processWorkflowWithList(p *progress.Progress, workflow *workflo gologger.Warningf("Could not preload templates for workflow %s: %s\n", workflow.ID, err) return false } - logicBytes := []byte(workflow.Logic) wg := sizedwaitgroup.New(r.options.BulkSize) - r.hm.Scan(func(k, _ []byte) error { targetURL := string(k) wg.Add() @@ -163,7 +162,10 @@ func (r *Runner) processWorkflowWithList(p *progress.Progress, workflow *workflo variables[name] = variable } - _, err := script.RunContext(context.Background()) + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(r.options.MaxWorkflowDuration)*time.Minute) + defer cancel() + + _, err := script.RunContext(ctx) if err != nil { gologger.Errorf("Could not execute workflow '%s': %s\n", workflow.ID, err) }