2021-10-27 16:50:36 +05:30
|
|
|
package core
|
2020-11-12 23:28:24 +05:30
|
|
|
|
2021-10-28 17:20:07 +05:30
|
|
|
import (
|
2022-10-03 12:12:20 +02:00
|
|
|
"fmt"
|
|
|
|
|
"net/http/cookiejar"
|
2023-01-20 23:49:04 +05:30
|
|
|
"sync/atomic"
|
2022-10-03 12:12:20 +02:00
|
|
|
|
2021-11-25 17:09:20 +02:00
|
|
|
"github.com/remeh/sizedwaitgroup"
|
|
|
|
|
|
2021-10-28 17:20:07 +05:30
|
|
|
"github.com/projectdiscovery/gologger"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
2022-10-03 12:12:20 +02:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
|
2021-10-28 17:20:07 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/workflows"
|
|
|
|
|
)
|
|
|
|
|
|
2022-10-03 12:12:20 +02:00
|
|
|
const workflowStepExecutionError = "[%s] Could not execute workflow step: %s\n"
|
2022-05-12 05:10:14 -05:00
|
|
|
|
2021-10-28 17:20:07 +05:30
|
|
|
// executeWorkflow runs a workflow on an input and returns true or false
|
2022-11-09 14:18:56 +01:00
|
|
|
func (e *Engine) executeWorkflow(input *contextargs.MetaInput, w *workflows.Workflow) bool {
|
2020-12-26 02:08:48 +05:30
|
|
|
results := &atomic.Bool{}
|
2020-11-12 23:28:24 +05:30
|
|
|
|
2022-10-03 12:12:20 +02:00
|
|
|
// at this point we should be at the start root execution of a workflow tree, hence we create global shared instances
|
|
|
|
|
workflowCookieJar, _ := cookiejar.New(nil)
|
|
|
|
|
ctxArgs := contextargs.New()
|
2022-11-09 14:18:56 +01:00
|
|
|
ctxArgs.MetaInput = input
|
2022-10-03 12:12:20 +02:00
|
|
|
ctxArgs.CookieJar = workflowCookieJar
|
|
|
|
|
|
2021-02-23 22:55:29 +05:30
|
|
|
swg := sizedwaitgroup.New(w.Options.Options.TemplateThreads)
|
2020-11-12 23:28:24 +05:30
|
|
|
for _, template := range w.Workflows {
|
2021-02-22 17:49:02 +05:30
|
|
|
swg.Add()
|
2021-10-28 17:20:07 +05:30
|
|
|
func(template *workflows.WorkflowTemplate) {
|
2022-10-03 12:12:20 +02:00
|
|
|
if err := e.runWorkflowStep(template, ctxArgs, results, &swg, w); err != nil {
|
|
|
|
|
gologger.Warning().Msgf(workflowStepExecutionError, template.Template, err)
|
2021-02-22 17:49:02 +05:30
|
|
|
}
|
|
|
|
|
swg.Done()
|
|
|
|
|
}(template)
|
2020-11-12 23:28:24 +05:30
|
|
|
}
|
2021-02-22 17:49:02 +05:30
|
|
|
swg.Wait()
|
|
|
|
|
return results.Load()
|
2020-11-12 23:28:24 +05:30
|
|
|
}
|
|
|
|
|
|
2020-12-26 02:08:48 +05:30
|
|
|
// runWorkflowStep runs a workflow step for the workflow. It executes the workflow
|
|
|
|
|
// in a recursive manner running all subtemplates and matchers.
|
2022-10-03 12:12:20 +02:00
|
|
|
func (e *Engine) runWorkflowStep(template *workflows.WorkflowTemplate, input *contextargs.Context, results *atomic.Bool, swg *sizedwaitgroup.SizedWaitGroup, w *workflows.Workflow) error {
|
2020-12-26 13:20:56 +05:30
|
|
|
var firstMatched bool
|
2021-02-27 20:54:22 +05:30
|
|
|
var err error
|
2021-01-17 12:56:29 +05:30
|
|
|
var mainErr error
|
2021-02-27 20:54:22 +05:30
|
|
|
|
2020-12-26 13:20:56 +05:30
|
|
|
if len(template.Matchers) == 0 {
|
2021-01-17 12:56:29 +05:30
|
|
|
for _, executer := range template.Executers {
|
|
|
|
|
executer.Options.Progress.AddToTotal(int64(executer.Executer.Requests()))
|
2020-12-29 18:02:45 +05:30
|
|
|
|
2021-02-27 20:54:22 +05:30
|
|
|
// Don't print results with subtemplates, only print results on template.
|
|
|
|
|
if len(template.Subtemplates) > 0 {
|
|
|
|
|
err = executer.Executer.ExecuteWithResults(input, func(result *output.InternalWrappedEvent) {
|
|
|
|
|
if result.OperatorsResult == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if len(result.Results) > 0 {
|
|
|
|
|
firstMatched = true
|
|
|
|
|
}
|
2022-10-03 12:12:20 +02:00
|
|
|
|
|
|
|
|
if result.OperatorsResult != nil && result.OperatorsResult.Extracts != nil {
|
|
|
|
|
for k, v := range result.OperatorsResult.Extracts {
|
|
|
|
|
// normalize items:
|
|
|
|
|
switch len(v) {
|
|
|
|
|
case 0, 1:
|
|
|
|
|
// - key:[item] => key: item
|
|
|
|
|
input.Set(k, v[0])
|
|
|
|
|
default:
|
|
|
|
|
// - key:[item_0, ..., item_n] => key0:item_0, keyn:item_n
|
|
|
|
|
for vIdx, vVal := range v {
|
|
|
|
|
normalizedKIdx := fmt.Sprintf("%s%d", k, vIdx)
|
|
|
|
|
input.Set(normalizedKIdx, vVal)
|
|
|
|
|
}
|
|
|
|
|
// also add the original name with full slice
|
|
|
|
|
input.Set(k, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-27 20:54:22 +05:30
|
|
|
})
|
|
|
|
|
} else {
|
2021-07-05 21:01:51 +05:30
|
|
|
var matched bool
|
|
|
|
|
matched, err = executer.Executer.Execute(input)
|
|
|
|
|
if matched {
|
|
|
|
|
firstMatched = true
|
|
|
|
|
}
|
2021-02-27 20:54:22 +05:30
|
|
|
}
|
2021-01-17 12:56:29 +05:30
|
|
|
if err != nil {
|
2021-08-16 21:24:37 +05:30
|
|
|
if w.Options.HostErrorsCache != nil {
|
2022-11-09 14:18:56 +01:00
|
|
|
w.Options.HostErrorsCache.MarkFailed(input.MetaInput.ID(), err)
|
2021-08-16 21:24:37 +05:30
|
|
|
}
|
2021-01-17 12:56:29 +05:30
|
|
|
if len(template.Executers) == 1 {
|
|
|
|
|
mainErr = err
|
|
|
|
|
} else {
|
2022-10-03 12:12:20 +02:00
|
|
|
gologger.Warning().Msgf(workflowStepExecutionError, template.Template, err)
|
2021-01-17 12:56:29 +05:30
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2020-12-29 20:32:04 +05:30
|
|
|
}
|
2020-12-26 13:20:56 +05:30
|
|
|
}
|
2021-02-27 20:54:22 +05:30
|
|
|
if len(template.Subtemplates) == 0 {
|
2022-09-19 08:38:52 +02:00
|
|
|
results.CompareAndSwap(false, firstMatched)
|
2021-02-27 20:54:22 +05:30
|
|
|
}
|
2020-11-12 23:28:24 +05:30
|
|
|
if len(template.Matchers) > 0 {
|
2021-01-17 12:56:29 +05:30
|
|
|
for _, executer := range template.Executers {
|
|
|
|
|
executer.Options.Progress.AddToTotal(int64(executer.Executer.Requests()))
|
|
|
|
|
|
|
|
|
|
err := executer.Executer.ExecuteWithResults(input, func(event *output.InternalWrappedEvent) {
|
|
|
|
|
if event.OperatorsResult == nil {
|
|
|
|
|
return
|
2020-12-26 02:08:48 +05:30
|
|
|
}
|
2020-11-12 23:28:24 +05:30
|
|
|
|
2022-10-03 12:12:20 +02:00
|
|
|
if event.OperatorsResult.Extracts != nil {
|
|
|
|
|
for k, v := range event.OperatorsResult.Extracts {
|
|
|
|
|
input.Set(k, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-17 12:56:29 +05:30
|
|
|
for _, matcher := range template.Matchers {
|
2022-09-19 16:49:30 +05:30
|
|
|
if !matcher.Match(event.OperatorsResult) {
|
2021-01-17 12:56:29 +05:30
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, subtemplate := range matcher.Subtemplates {
|
2021-02-22 17:49:02 +05:30
|
|
|
swg.Add()
|
|
|
|
|
|
2021-10-28 17:20:07 +05:30
|
|
|
go func(subtemplate *workflows.WorkflowTemplate) {
|
|
|
|
|
if err := e.runWorkflowStep(subtemplate, input, results, swg, w); err != nil {
|
2022-10-03 12:12:20 +02:00
|
|
|
gologger.Warning().Msgf(workflowStepExecutionError, subtemplate.Template, err)
|
2021-02-22 17:49:02 +05:30
|
|
|
}
|
|
|
|
|
swg.Done()
|
|
|
|
|
}(subtemplate)
|
2020-12-26 02:08:48 +05:30
|
|
|
}
|
2020-11-12 23:28:24 +05:30
|
|
|
}
|
2021-01-17 12:56:29 +05:30
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
if len(template.Executers) == 1 {
|
|
|
|
|
mainErr = err
|
|
|
|
|
} else {
|
2022-10-03 12:12:20 +02:00
|
|
|
gologger.Warning().Msgf(workflowStepExecutionError, template.Template, err)
|
2021-01-17 12:56:29 +05:30
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2020-11-12 23:28:24 +05:30
|
|
|
}
|
2021-01-17 12:56:29 +05:30
|
|
|
return mainErr
|
2020-11-12 23:28:24 +05:30
|
|
|
}
|
2020-12-26 13:20:56 +05:30
|
|
|
if len(template.Subtemplates) > 0 && firstMatched {
|
2020-11-12 23:28:24 +05:30
|
|
|
for _, subtemplate := range template.Subtemplates {
|
2021-02-22 17:49:02 +05:30
|
|
|
swg.Add()
|
|
|
|
|
|
2021-10-28 17:20:07 +05:30
|
|
|
go func(template *workflows.WorkflowTemplate) {
|
|
|
|
|
if err := e.runWorkflowStep(template, input, results, swg, w); err != nil {
|
2022-10-03 12:12:20 +02:00
|
|
|
gologger.Warning().Msgf(workflowStepExecutionError, template.Template, err)
|
2021-02-22 17:49:02 +05:30
|
|
|
}
|
|
|
|
|
swg.Done()
|
|
|
|
|
}(subtemplate)
|
2020-11-12 23:28:24 +05:30
|
|
|
}
|
|
|
|
|
}
|
2021-01-17 12:56:29 +05:30
|
|
|
return mainErr
|
2021-10-28 17:20:07 +05:30
|
|
|
}
|