mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-18 02:55:27 +00:00
* introducing execution id * wip * . * adding separate execution context id * lint * vet * fixing pg dialers * test ignore * fixing loader FD limit * test * fd fix * wip: remove CloseProcesses() from dev merge * wip: fix merge issue * protocolstate: stop memguarding on last dialer delete * avoid data race in dialers.RawHTTPClient * use shared logger and avoid race conditions * use shared logger and avoid race conditions * go mod * patch executionId into compiled template cache * clean up comment in Parse * go mod update * bump echarts * address merge issues * fix use of gologger * switch cmd/nuclei to options.Logger * address merge issues with go.mod * go vet: address copy of lock with new Copy function * fixing tests * disable speed control * fix nil ExecuterOptions * removing deprecated code * fixing result print * default logger * cli default logger * filter warning from results * fix performance test * hardcoding path * disable upload * refactor(runner): uses `Warning` instead of `Print` for `pdcpUploadErrMsg` Signed-off-by: Dwi Siswanto <git@dw1.io> * Revert "disable upload" This reverts commit 114fbe6663361bf41cf8b2645fd2d57083d53682. * Revert "hardcoding path" This reverts commit cf12ca800e0a0e974bd9fd4826a24e51547f7c00. --------- Signed-off-by: Dwi Siswanto <git@dw1.io> Co-authored-by: Mzack9999 <mzack9999@protonmail.com> Co-authored-by: Dwi Siswanto <git@dw1.io> Co-authored-by: Dwi Siswanto <25837540+dwisiswant0@users.noreply.github.com>
141 lines
5.9 KiB
Go
141 lines
5.9 KiB
Go
package flow
|
|
|
|
import (
|
|
"fmt"
|
|
"sync/atomic"
|
|
|
|
"github.com/Mzack9999/goja"
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/output"
|
|
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
|
|
mapsutil "github.com/projectdiscovery/utils/maps"
|
|
)
|
|
|
|
// contains all internal/unexported methods of flow
|
|
|
|
// requestExecutor executes a protocol/request and returns true if any matcher was found
|
|
func (f *FlowExecutor) requestExecutor(runtime *goja.Runtime, reqMap mapsutil.Map[string, protocols.Request], opts *ProtoOptions) bool {
|
|
defer func() {
|
|
// evaluate all variables after execution of each protocol
|
|
variableMap := f.options.Variables.Evaluate(f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll())
|
|
f.options.GetTemplateCtx(f.ctx.Input.MetaInput).Merge(variableMap) // merge all variables into template context
|
|
|
|
// to avoid polling update template variables everytime we execute a protocol
|
|
m := f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll()
|
|
_ = runtime.Set("template", m)
|
|
}()
|
|
matcherStatus := &atomic.Bool{} // due to interactsh matcher polling logic this needs to be atomic bool
|
|
// if no id is passed execute all requests in sequence
|
|
if len(opts.reqIDS) == 0 {
|
|
// execution logic for http()/dns() etc
|
|
for index := range f.allProtocols[opts.protoName] {
|
|
req := f.allProtocols[opts.protoName][index]
|
|
// transform input if required
|
|
inputItem := f.ctx.Input.Clone()
|
|
if f.options.InputHelper != nil && f.ctx.Input.MetaInput.Input != "" {
|
|
if inputItem.MetaInput.Input = f.options.InputHelper.Transform(inputItem.MetaInput.Input, req.Type()); inputItem.MetaInput.Input == "" {
|
|
f.ctx.LogError(fmt.Errorf("failed to transform input for protocol %s", req.Type()))
|
|
return false
|
|
}
|
|
}
|
|
err := req.ExecuteWithResults(inputItem, output.InternalEvent(f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll()), output.InternalEvent{}, f.protocolResultCallback(req, matcherStatus, opts))
|
|
if err != nil {
|
|
// save all errors in a map with id as key
|
|
// its less likely that there will be race condition but just in case
|
|
id := req.GetID()
|
|
if id == "" {
|
|
id, _ = reqMap.GetKeyWithValue(req)
|
|
}
|
|
err = f.allErrs.Set(opts.protoName+":"+id, err)
|
|
if err != nil {
|
|
f.ctx.LogError(fmt.Errorf("failed to store flow runtime errors got %v", err))
|
|
}
|
|
return matcherStatus.Load()
|
|
}
|
|
}
|
|
return matcherStatus.Load()
|
|
}
|
|
|
|
// execution logic for http("0") or http("get-aws-vpcs")
|
|
for _, id := range opts.reqIDS {
|
|
req, ok := reqMap[id]
|
|
if !ok {
|
|
f.ctx.LogError(fmt.Errorf("[%v] invalid request id '%s' provided", f.options.TemplateID, id))
|
|
// compile error
|
|
if err := f.allErrs.Set(opts.protoName+":"+id, ErrInvalidRequestID.Msgf(f.options.TemplateID, id)); err != nil {
|
|
f.ctx.LogError(fmt.Errorf("failed to store flow runtime errors got %v", err))
|
|
}
|
|
return matcherStatus.Load()
|
|
}
|
|
// transform input if required
|
|
inputItem := f.ctx.Input.Clone()
|
|
if f.options.InputHelper != nil && f.ctx.Input.MetaInput.Input != "" {
|
|
if inputItem.MetaInput.Input = f.options.InputHelper.Transform(inputItem.MetaInput.Input, req.Type()); inputItem.MetaInput.Input == "" {
|
|
f.ctx.LogError(fmt.Errorf("failed to transform input for protocol %s", req.Type()))
|
|
return false
|
|
}
|
|
}
|
|
err := req.ExecuteWithResults(inputItem, output.InternalEvent(f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll()), output.InternalEvent{}, f.protocolResultCallback(req, matcherStatus, opts))
|
|
// Mark the request as seen
|
|
_ = f.executed.Set(requestKey(opts.protoName, req, id), struct{}{})
|
|
if err != nil {
|
|
index := id
|
|
err = f.allErrs.Set(opts.protoName+":"+index, err)
|
|
if err != nil {
|
|
f.ctx.LogError(fmt.Errorf("failed to store flow runtime errors got %v", err))
|
|
}
|
|
}
|
|
}
|
|
return matcherStatus.Load()
|
|
}
|
|
|
|
func requestKey(proto string, req protocols.Request, id string) string {
|
|
if id == "" {
|
|
id = req.GetID()
|
|
}
|
|
return proto + ":" + id
|
|
}
|
|
|
|
// protocolResultCallback returns a callback that is executed
|
|
// after execution of each protocol request
|
|
func (f *FlowExecutor) protocolResultCallback(req protocols.Request, matcherStatus *atomic.Bool, _ *ProtoOptions) func(result *output.InternalWrappedEvent) {
|
|
return func(result *output.InternalWrappedEvent) {
|
|
if result != nil {
|
|
// Note: flow specific implicit behaviours should be handled here
|
|
// before logging the event
|
|
f.ctx.LogEvent(result)
|
|
// export dynamic values from operators (i.e internal:true)
|
|
// add add it to template context
|
|
// this is a conflicting behaviour with iterate-all
|
|
if result.HasOperatorResult() {
|
|
f.results.CompareAndSwap(false, true)
|
|
// this is to handle case where there is any operator result (matcher or extractor)
|
|
matcherStatus.CompareAndSwap(false, result.OperatorsResult.Matched)
|
|
if !result.OperatorsResult.Matched && !hasMatchers(req.GetCompiledOperators()) {
|
|
// if matcher status is false . check if template/request contains any matcher at all
|
|
// if it does then we need to set matcher status to true
|
|
matcherStatus.CompareAndSwap(false, true)
|
|
}
|
|
if len(result.OperatorsResult.DynamicValues) > 0 {
|
|
for k, v := range result.OperatorsResult.DynamicValues {
|
|
// if length of v is 1 then remove slice and convert it to single value
|
|
if len(v) == 1 {
|
|
// add it to flatten keys list so it will be flattened to a string later
|
|
f.flattenKeys = append(f.flattenKeys, k)
|
|
// flatten and convert it to string
|
|
f.options.GetTemplateCtx(f.ctx.Input.MetaInput).Set(k, v[0])
|
|
} else {
|
|
// keep it as slice
|
|
f.options.GetTemplateCtx(f.ctx.Input.MetaInput).Set(k, v)
|
|
}
|
|
}
|
|
}
|
|
} else if !result.HasOperatorResult() && !hasOperators(req.GetCompiledOperators()) {
|
|
// this is to handle case where there are no operator result and there was no matcher in operators
|
|
// if matcher status is false . check if template/request contains any matcher at all
|
|
// if it does then we need to set matcher status to true
|
|
matcherStatus.CompareAndSwap(false, true)
|
|
}
|
|
}
|
|
}
|
|
}
|