2021-01-02 02:39:27 +05:30
|
|
|
package executer
|
2020-12-29 01:30:07 +05:30
|
|
|
|
|
|
|
|
import (
|
2021-12-07 17:34:36 +02:00
|
|
|
"fmt"
|
2021-01-16 14:10:24 +05:30
|
|
|
"strings"
|
2023-02-06 16:18:30 +05:30
|
|
|
"sync/atomic"
|
2021-01-16 14:10:24 +05:30
|
|
|
|
2021-12-07 17:34:36 +02:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
|
2021-02-01 16:21:49 +05:30
|
|
|
"github.com/projectdiscovery/gologger"
|
2021-12-07 17:34:36 +02:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/operators/common/dsl"
|
2020-12-29 01:30:07 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
2022-10-03 12:12:20 +02:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs"
|
2021-11-22 17:53:25 +05:30
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/helpers/writer"
|
2020-12-29 01:30:07 +05:30
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Executer executes a group of requests for a protocol
|
|
|
|
|
type Executer struct {
|
2021-01-02 02:39:27 +05:30
|
|
|
requests []protocols.Request
|
2023-05-31 16:58:10 -04:00
|
|
|
options *protocols.ExecutorOptions
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var _ protocols.Executer = &Executer{}
|
|
|
|
|
|
|
|
|
|
// NewExecuter creates a new request executer for list of requests
|
2023-05-31 16:58:10 -04:00
|
|
|
func NewExecuter(requests []protocols.Request, options *protocols.ExecutorOptions) *Executer {
|
2020-12-29 01:30:07 +05:30
|
|
|
return &Executer{requests: requests, options: options}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compile compiles the execution generators preparing any requests possible.
|
|
|
|
|
func (e *Executer) Compile() error {
|
2021-12-07 17:34:36 +02:00
|
|
|
cliOptions := e.options.Options
|
|
|
|
|
|
2020-12-29 01:30:07 +05:30
|
|
|
for _, request := range e.requests {
|
2021-08-31 12:55:52 +03:00
|
|
|
if err := request.Compile(e.options); err != nil {
|
2022-08-29 10:11:32 +02:00
|
|
|
var dslCompilationError *dsl.CompilationError
|
2021-12-07 17:34:36 +02:00
|
|
|
if errors.As(err, &dslCompilationError) {
|
|
|
|
|
if cliOptions.Verbose {
|
|
|
|
|
rawErrorMessage := dslCompilationError.Error()
|
|
|
|
|
formattedErrorMessage := strings.ToUpper(rawErrorMessage[:1]) + rawErrorMessage[1:] + "."
|
|
|
|
|
gologger.Warning().Msgf(formattedErrorMessage)
|
|
|
|
|
gologger.Info().Msgf("The available custom DSL functions are:")
|
|
|
|
|
fmt.Println(dsl.GetPrintableDslFunctionSignatures(cliOptions.NoColor))
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-29 01:30:07 +05:30
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Requests returns the total number of requests the rule will perform
|
2020-12-29 15:38:14 +05:30
|
|
|
func (e *Executer) Requests() int {
|
|
|
|
|
var count int
|
2020-12-29 01:30:07 +05:30
|
|
|
for _, request := range e.requests {
|
2021-01-12 02:00:11 +05:30
|
|
|
count += request.Requests()
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
|
|
|
|
return count
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Execute executes the protocol group and returns true or false if results were found.
|
2022-10-03 12:12:20 +02:00
|
|
|
func (e *Executer) Execute(input *contextargs.Context) (bool, error) {
|
2023-02-06 16:18:30 +05:30
|
|
|
results := &atomic.Bool{}
|
2020-12-29 01:30:07 +05:30
|
|
|
|
2021-01-01 19:36:21 +05:30
|
|
|
dynamicValues := make(map[string]interface{})
|
2022-10-03 12:12:20 +02:00
|
|
|
if input.HasArgs() {
|
|
|
|
|
input.ForEach(func(key string, value interface{}) {
|
|
|
|
|
dynamicValues[key] = value
|
|
|
|
|
})
|
|
|
|
|
}
|
2021-01-16 14:10:24 +05:30
|
|
|
previous := make(map[string]interface{})
|
2020-12-29 01:30:07 +05:30
|
|
|
for _, req := range e.requests {
|
2022-11-09 14:18:56 +01:00
|
|
|
inputItem := input.Clone()
|
|
|
|
|
if e.options.InputHelper != nil && input.MetaInput.Input != "" {
|
2022-12-20 21:59:28 +01:00
|
|
|
if inputItem.MetaInput.Input = e.options.InputHelper.Transform(inputItem.MetaInput.Input, req.Type()); inputItem.MetaInput.Input == "" {
|
2022-10-20 17:23:00 +05:30
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 14:18:56 +01:00
|
|
|
err := req.ExecuteWithResults(inputItem, dynamicValues, previous, func(event *output.InternalWrappedEvent) {
|
2021-01-16 14:10:24 +05:30
|
|
|
ID := req.GetID()
|
|
|
|
|
if ID != "" {
|
|
|
|
|
builder := &strings.Builder{}
|
|
|
|
|
for k, v := range event.InternalEvent {
|
|
|
|
|
builder.WriteString(ID)
|
|
|
|
|
builder.WriteString("_")
|
|
|
|
|
builder.WriteString(k)
|
|
|
|
|
previous[builder.String()] = v
|
|
|
|
|
builder.Reset()
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-22 17:53:25 +05:30
|
|
|
// If no results were found, and also interactsh is not being used
|
|
|
|
|
// in that case we can skip it, otherwise we've to show failure in
|
|
|
|
|
// case of matcher-status flag.
|
2023-03-17 14:41:16 +01:00
|
|
|
if !event.HasOperatorResult() && !event.UsesInteractsh {
|
2021-11-22 17:53:25 +05:30
|
|
|
if err := e.options.Output.WriteFailure(event.InternalEvent); err != nil {
|
|
|
|
|
gologger.Warning().Msgf("Could not write failure event to output: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if writer.WriteResult(event, e.options.Output, e.options.Progress, e.options.IssuesClient) {
|
2023-02-06 16:18:30 +05:30
|
|
|
results.CompareAndSwap(false, true)
|
2022-07-13 06:19:06 -05:00
|
|
|
} else {
|
|
|
|
|
if err := e.options.Output.WriteFailure(event.InternalEvent); err != nil {
|
|
|
|
|
gologger.Warning().Msgf("Could not write failure event to output: %s\n", err)
|
|
|
|
|
}
|
2021-02-02 12:10:47 +05:30
|
|
|
}
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
2021-01-01 19:36:21 +05:30
|
|
|
})
|
|
|
|
|
if err != nil {
|
2021-08-16 21:24:37 +05:30
|
|
|
if e.options.HostErrorsCache != nil {
|
2022-11-09 14:18:56 +01:00
|
|
|
e.options.HostErrorsCache.MarkFailed(input.MetaInput.ID(), err)
|
2021-08-16 21:24:37 +05:30
|
|
|
}
|
2022-11-09 14:18:56 +01:00
|
|
|
gologger.Warning().Msgf("[%s] Could not execute request for %s: %s\n", e.options.TemplateID, input.MetaInput.PrettyPrint(), err)
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
2021-11-29 18:06:25 +05:30
|
|
|
// If a match was found and stop at first match is set, break out of the loop and return
|
2023-02-06 16:18:30 +05:30
|
|
|
if results.Load() && (e.options.StopAtFirstMatch || e.options.Options.StopAtFirstMatch) {
|
2021-11-29 16:01:06 +05:30
|
|
|
break
|
|
|
|
|
}
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
2023-02-06 16:18:30 +05:30
|
|
|
return results.Load(), nil
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
|
2022-10-03 12:12:20 +02:00
|
|
|
func (e *Executer) ExecuteWithResults(input *contextargs.Context, callback protocols.OutputEventCallback) error {
|
2021-01-01 19:36:21 +05:30
|
|
|
dynamicValues := make(map[string]interface{})
|
2022-10-03 12:12:20 +02:00
|
|
|
if input.HasArgs() {
|
|
|
|
|
input.ForEach(func(key string, value interface{}) {
|
|
|
|
|
dynamicValues[key] = value
|
|
|
|
|
})
|
|
|
|
|
}
|
2021-01-16 14:10:24 +05:30
|
|
|
previous := make(map[string]interface{})
|
2023-02-06 16:18:30 +05:30
|
|
|
results := &atomic.Bool{}
|
2021-01-16 14:10:24 +05:30
|
|
|
|
2020-12-29 01:30:07 +05:30
|
|
|
for _, req := range e.requests {
|
2021-02-26 13:13:11 +05:30
|
|
|
req := req
|
|
|
|
|
|
2022-11-09 14:18:56 +01:00
|
|
|
inputItem := input.Clone()
|
|
|
|
|
if e.options.InputHelper != nil && input.MetaInput.Input != "" {
|
|
|
|
|
if inputItem.MetaInput.Input = e.options.InputHelper.Transform(input.MetaInput.Input, req.Type()); input.MetaInput.Input == "" {
|
2022-10-20 17:23:00 +05:30
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 14:18:56 +01:00
|
|
|
err := req.ExecuteWithResults(inputItem, dynamicValues, previous, func(event *output.InternalWrappedEvent) {
|
2021-01-16 14:10:24 +05:30
|
|
|
ID := req.GetID()
|
|
|
|
|
if ID != "" {
|
|
|
|
|
builder := &strings.Builder{}
|
|
|
|
|
for k, v := range event.InternalEvent {
|
|
|
|
|
builder.WriteString(ID)
|
|
|
|
|
builder.WriteString("_")
|
|
|
|
|
builder.WriteString(k)
|
|
|
|
|
previous[builder.String()] = v
|
|
|
|
|
builder.Reset()
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-29 01:30:07 +05:30
|
|
|
if event.OperatorsResult == nil {
|
2021-01-01 19:36:21 +05:30
|
|
|
return
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
2023-02-06 16:18:30 +05:30
|
|
|
results.CompareAndSwap(false, true)
|
2021-01-01 19:36:21 +05:30
|
|
|
callback(event)
|
|
|
|
|
})
|
2021-02-01 16:21:49 +05:30
|
|
|
if err != nil {
|
2021-08-16 21:24:37 +05:30
|
|
|
if e.options.HostErrorsCache != nil {
|
2022-11-09 14:18:56 +01:00
|
|
|
e.options.HostErrorsCache.MarkFailed(input.MetaInput.ID(), err)
|
2021-08-16 21:24:37 +05:30
|
|
|
}
|
2022-11-09 14:18:56 +01:00
|
|
|
gologger.Warning().Msgf("[%s] Could not execute request for %s: %s\n", e.options.TemplateID, input.MetaInput.PrettyPrint(), err)
|
2021-02-01 16:21:49 +05:30
|
|
|
}
|
2021-11-29 18:06:25 +05:30
|
|
|
// If a match was found and stop at first match is set, break out of the loop and return
|
2023-02-06 16:18:30 +05:30
|
|
|
if results.Load() && (e.options.StopAtFirstMatch || e.options.Options.StopAtFirstMatch) {
|
2021-11-29 18:06:25 +05:30
|
|
|
break
|
|
|
|
|
}
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|
2021-01-01 19:36:21 +05:30
|
|
|
return nil
|
2020-12-29 01:30:07 +05:30
|
|
|
}
|