Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/tmplexec/flow/flow_internal.go
2070 views
1
package flow
2
3
import (
4
"fmt"
5
"sync/atomic"
6
7
"github.com/Mzack9999/goja"
8
"github.com/projectdiscovery/nuclei/v3/pkg/output"
9
"github.com/projectdiscovery/nuclei/v3/pkg/protocols"
10
"github.com/projectdiscovery/utils/errkit"
11
mapsutil "github.com/projectdiscovery/utils/maps"
12
)
13
14
// contains all internal/unexported methods of flow
15
16
// requestExecutor executes a protocol/request and returns true if any matcher was found
17
func (f *FlowExecutor) requestExecutor(runtime *goja.Runtime, reqMap mapsutil.Map[string, protocols.Request], opts *ProtoOptions) bool {
18
defer func() {
19
// evaluate all variables after execution of each protocol
20
variableMap := f.options.Variables.Evaluate(f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll())
21
f.options.GetTemplateCtx(f.ctx.Input.MetaInput).Merge(variableMap) // merge all variables into template context
22
23
// to avoid polling update template variables everytime we execute a protocol
24
m := f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll()
25
_ = runtime.Set("template", m)
26
}()
27
matcherStatus := &atomic.Bool{} // due to interactsh matcher polling logic this needs to be atomic bool
28
// if no id is passed execute all requests in sequence
29
if len(opts.reqIDS) == 0 {
30
// execution logic for http()/dns() etc
31
for index := range f.allProtocols[opts.protoName] {
32
req := f.allProtocols[opts.protoName][index]
33
// transform input if required
34
inputItem := f.ctx.Input.Clone()
35
if f.options.InputHelper != nil && f.ctx.Input.MetaInput.Input != "" {
36
if inputItem.MetaInput.Input = f.options.InputHelper.Transform(inputItem.MetaInput.Input, req.Type()); inputItem.MetaInput.Input == "" {
37
f.ctx.LogError(fmt.Errorf("failed to transform input for protocol %s", req.Type()))
38
return false
39
}
40
}
41
err := req.ExecuteWithResults(inputItem, output.InternalEvent(f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll()), output.InternalEvent{}, f.protocolResultCallback(req, matcherStatus, opts))
42
if err != nil {
43
// save all errors in a map with id as key
44
// its less likely that there will be race condition but just in case
45
id := req.GetID()
46
if id == "" {
47
id, _ = reqMap.GetKeyWithValue(req)
48
}
49
err = f.allErrs.Set(opts.protoName+":"+id, err)
50
if err != nil {
51
f.ctx.LogError(fmt.Errorf("failed to store flow runtime errors got %v", err))
52
}
53
return matcherStatus.Load()
54
}
55
}
56
return matcherStatus.Load()
57
}
58
59
// execution logic for http("0") or http("get-aws-vpcs")
60
for _, id := range opts.reqIDS {
61
req, ok := reqMap[id]
62
if !ok {
63
f.ctx.LogError(fmt.Errorf("[%v] invalid request id '%s' provided", f.options.TemplateID, id))
64
// compile error
65
if err := f.allErrs.Set(opts.protoName+":"+id, errkit.Newf("[%s] invalid request id '%s' provided", f.options.TemplateID, id)); err != nil {
66
f.ctx.LogError(fmt.Errorf("failed to store flow runtime errors got %v", err))
67
}
68
return matcherStatus.Load()
69
}
70
// transform input if required
71
inputItem := f.ctx.Input.Clone()
72
if f.options.InputHelper != nil && f.ctx.Input.MetaInput.Input != "" {
73
if inputItem.MetaInput.Input = f.options.InputHelper.Transform(inputItem.MetaInput.Input, req.Type()); inputItem.MetaInput.Input == "" {
74
f.ctx.LogError(fmt.Errorf("failed to transform input for protocol %s", req.Type()))
75
return false
76
}
77
}
78
err := req.ExecuteWithResults(inputItem, output.InternalEvent(f.options.GetTemplateCtx(f.ctx.Input.MetaInput).GetAll()), output.InternalEvent{}, f.protocolResultCallback(req, matcherStatus, opts))
79
// Mark the request as seen
80
_ = f.executed.Set(requestKey(opts.protoName, req, id), struct{}{})
81
if err != nil {
82
index := id
83
err = f.allErrs.Set(opts.protoName+":"+index, err)
84
if err != nil {
85
f.ctx.LogError(fmt.Errorf("failed to store flow runtime errors got %v", err))
86
}
87
}
88
}
89
return matcherStatus.Load()
90
}
91
92
func requestKey(proto string, req protocols.Request, id string) string {
93
if id == "" {
94
id = req.GetID()
95
}
96
return proto + ":" + id
97
}
98
99
// protocolResultCallback returns a callback that is executed
100
// after execution of each protocol request
101
func (f *FlowExecutor) protocolResultCallback(req protocols.Request, matcherStatus *atomic.Bool, _ *ProtoOptions) func(result *output.InternalWrappedEvent) {
102
return func(result *output.InternalWrappedEvent) {
103
if result != nil {
104
// Note: flow specific implicit behaviours should be handled here
105
// before logging the event
106
f.ctx.LogEvent(result)
107
// export dynamic values from operators (i.e internal:true)
108
// add add it to template context
109
// this is a conflicting behaviour with iterate-all
110
if result.HasOperatorResult() {
111
f.results.CompareAndSwap(false, true)
112
// this is to handle case where there is any operator result (matcher or extractor)
113
matcherStatus.CompareAndSwap(false, result.OperatorsResult.Matched)
114
if !result.OperatorsResult.Matched && !hasMatchers(req.GetCompiledOperators()) {
115
// if matcher status is false . check if template/request contains any matcher at all
116
// if it does then we need to set matcher status to true
117
matcherStatus.CompareAndSwap(false, true)
118
}
119
if len(result.OperatorsResult.DynamicValues) > 0 {
120
for k, v := range result.OperatorsResult.DynamicValues {
121
// if length of v is 1 then remove slice and convert it to single value
122
if len(v) == 1 {
123
// add it to flatten keys list so it will be flattened to a string later
124
f.flattenKeys = append(f.flattenKeys, k)
125
// flatten and convert it to string
126
f.options.GetTemplateCtx(f.ctx.Input.MetaInput).Set(k, v[0])
127
} else {
128
// keep it as slice
129
f.options.GetTemplateCtx(f.ctx.Input.MetaInput).Set(k, v)
130
}
131
}
132
}
133
} else if !result.HasOperatorResult() && !hasOperators(req.GetCompiledOperators()) {
134
// this is to handle case where there are no operator result and there was no matcher in operators
135
// if matcher status is false . check if template/request contains any matcher at all
136
// if it does then we need to set matcher status to true
137
matcherStatus.CompareAndSwap(false, true)
138
}
139
}
140
}
141
}
142
143