2021-01-13 06:48:56 +00:00
|
|
|
package clusterer
|
|
|
|
|
|
|
|
import (
|
2021-02-02 06:40:47 +00:00
|
|
|
"github.com/projectdiscovery/gologger"
|
2021-01-13 06:48:56 +00:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/operators"
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
|
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/templates"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Executer executes a group of requests for a protocol for a clustered
|
|
|
|
// request. It is different from normal executers since the original
|
|
|
|
// operators are all combined and post processed after making the request.
|
|
|
|
//
|
|
|
|
// TODO: We only cluster http requests as of now.
|
|
|
|
type Executer struct {
|
|
|
|
requests *http.Request
|
|
|
|
operators []*clusteredOperator
|
|
|
|
options *protocols.ExecuterOptions
|
|
|
|
}
|
|
|
|
|
|
|
|
type clusteredOperator struct {
|
|
|
|
templateID string
|
2021-06-05 12:31:08 +00:00
|
|
|
templatePath string
|
2021-02-03 19:39:29 +00:00
|
|
|
templateInfo map[string]interface{}
|
2021-01-13 06:48:56 +00:00
|
|
|
operator *operators.Operators
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ protocols.Executer = &Executer{}
|
|
|
|
|
|
|
|
// NewExecuter creates a new request executer for list of requests
|
|
|
|
func NewExecuter(requests []*templates.Template, options *protocols.ExecuterOptions) *Executer {
|
|
|
|
executer := &Executer{
|
|
|
|
options: options,
|
|
|
|
requests: requests[0].RequestsHTTP[0],
|
|
|
|
}
|
|
|
|
for _, req := range requests {
|
|
|
|
executer.operators = append(executer.operators, &clusteredOperator{
|
|
|
|
templateID: req.ID,
|
|
|
|
templateInfo: req.Info,
|
2021-06-05 17:30:59 +00:00
|
|
|
templatePath: req.Path,
|
2021-01-13 06:48:56 +00:00
|
|
|
operator: req.RequestsHTTP[0].CompiledOperators,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return executer
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compile compiles the execution generators preparing any requests possible.
|
|
|
|
func (e *Executer) Compile() error {
|
|
|
|
return e.requests.Compile(e.options)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Requests returns the total number of requests the rule will perform
|
|
|
|
func (e *Executer) Requests() int {
|
|
|
|
var count int
|
|
|
|
count += e.requests.Requests()
|
|
|
|
return count
|
|
|
|
}
|
|
|
|
|
|
|
|
// Execute executes the protocol group and returns true or false if results were found.
|
|
|
|
func (e *Executer) Execute(input string) (bool, error) {
|
|
|
|
var results bool
|
|
|
|
|
2021-06-03 04:56:41 +00:00
|
|
|
previous := make(map[string]interface{})
|
2021-01-13 06:48:56 +00:00
|
|
|
dynamicValues := make(map[string]interface{})
|
2021-06-03 04:56:41 +00:00
|
|
|
err := e.requests.ExecuteWithResults(input, dynamicValues, previous, func(event *output.InternalWrappedEvent) {
|
2021-01-13 06:48:56 +00:00
|
|
|
for _, operator := range e.operators {
|
|
|
|
result, matched := operator.operator.Execute(event.InternalEvent, e.requests.Match, e.requests.Extract)
|
|
|
|
if matched && result != nil {
|
|
|
|
event.OperatorsResult = result
|
|
|
|
event.InternalEvent["template-id"] = operator.templateID
|
2021-06-05 12:31:08 +00:00
|
|
|
event.InternalEvent["template-path"] = operator.templatePath
|
2021-01-13 06:48:56 +00:00
|
|
|
event.InternalEvent["template-info"] = operator.templateInfo
|
|
|
|
event.Results = e.requests.MakeResultEvent(event)
|
|
|
|
results = true
|
|
|
|
for _, r := range event.Results {
|
2021-02-02 06:40:47 +00:00
|
|
|
if e.options.IssuesClient != nil {
|
|
|
|
if err := e.options.IssuesClient.CreateIssue(r); err != nil {
|
|
|
|
gologger.Warning().Msgf("Could not create issue on tracker: %s", err)
|
|
|
|
}
|
|
|
|
}
|
2021-02-26 07:43:11 +00:00
|
|
|
_ = e.options.Output.Write(r)
|
2021-01-16 06:56:38 +00:00
|
|
|
e.options.Progress.IncrementMatched()
|
2021-01-13 06:48:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2021-02-01 10:51:49 +00:00
|
|
|
return results, err
|
2021-01-13 06:48:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ExecuteWithResults executes the protocol requests and returns results instead of writing them.
|
|
|
|
func (e *Executer) ExecuteWithResults(input string, callback protocols.OutputEventCallback) error {
|
|
|
|
dynamicValues := make(map[string]interface{})
|
2021-02-01 10:51:49 +00:00
|
|
|
err := e.requests.ExecuteWithResults(input, dynamicValues, nil, func(event *output.InternalWrappedEvent) {
|
2021-01-13 06:48:56 +00:00
|
|
|
for _, operator := range e.operators {
|
|
|
|
result, matched := operator.operator.Execute(event.InternalEvent, e.requests.Match, e.requests.Extract)
|
|
|
|
if matched && result != nil {
|
|
|
|
event.OperatorsResult = result
|
|
|
|
event.InternalEvent["template-id"] = operator.templateID
|
2021-06-05 12:31:08 +00:00
|
|
|
event.InternalEvent["template-path"] = operator.templatePath
|
2021-01-13 06:48:56 +00:00
|
|
|
event.InternalEvent["template-info"] = operator.templateInfo
|
|
|
|
event.Results = e.requests.MakeResultEvent(event)
|
|
|
|
callback(event)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2021-02-01 10:51:49 +00:00
|
|
|
return err
|
2021-01-13 06:48:56 +00:00
|
|
|
}
|