Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/protocols/common/variables/variables.go
2073 views
1
package variables
2
3
import (
4
"strings"
5
6
"github.com/invopop/jsonschema"
7
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/expressions"
8
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"
9
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/interactsh"
10
protocolutils "github.com/projectdiscovery/nuclei/v3/pkg/protocols/utils"
11
"github.com/projectdiscovery/nuclei/v3/pkg/types"
12
"github.com/projectdiscovery/nuclei/v3/pkg/utils"
13
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
14
stringsutil "github.com/projectdiscovery/utils/strings"
15
)
16
17
// Variable is a key-value pair of strings that can be used
18
// throughout template.
19
type Variable struct {
20
LazyEval bool `yaml:"-" json:"-"` // LazyEval is used to evaluate variables lazily if it using any expression or global variables
21
utils.InsertionOrderedStringMap `yaml:"-" json:"-"`
22
}
23
24
func (variables Variable) JSONSchema() *jsonschema.Schema {
25
gotType := &jsonschema.Schema{
26
Type: "object",
27
Title: "variables for the request",
28
Description: "Additional variables for the request",
29
AdditionalProperties: &jsonschema.Schema{},
30
}
31
return gotType
32
}
33
34
func (variables *Variable) UnmarshalYAML(unmarshal func(interface{}) error) error {
35
variables.InsertionOrderedStringMap = utils.InsertionOrderedStringMap{}
36
if err := unmarshal(&variables.InsertionOrderedStringMap); err != nil {
37
return err
38
}
39
40
if variables.LazyEval || variables.checkForLazyEval() {
41
return nil
42
}
43
44
evaluated := variables.Evaluate(map[string]interface{}{})
45
46
for k, v := range evaluated {
47
variables.Set(k, v)
48
}
49
return nil
50
}
51
52
func (variables *Variable) UnmarshalJSON(data []byte) error {
53
variables.InsertionOrderedStringMap = utils.InsertionOrderedStringMap{}
54
if err := json.Unmarshal(data, &variables.InsertionOrderedStringMap); err != nil {
55
return err
56
}
57
evaluated := variables.Evaluate(map[string]interface{}{})
58
59
for k, v := range evaluated {
60
variables.Set(k, v)
61
}
62
return nil
63
}
64
65
// Evaluate returns a finished map of variables based on set values
66
func (variables *Variable) Evaluate(values map[string]interface{}) map[string]interface{} {
67
result := make(map[string]interface{}, variables.Len())
68
variables.ForEach(func(key string, value interface{}) {
69
if sliceValue, ok := value.([]interface{}); ok {
70
// slices cannot be evaluated
71
result[key] = sliceValue
72
return
73
}
74
valueString := types.ToString(value)
75
combined := generators.MergeMaps(values, result)
76
if value, ok := combined[key]; ok {
77
valueString = types.ToString(value)
78
}
79
result[key] = evaluateVariableValue(valueString, combined, result)
80
})
81
return result
82
}
83
84
// GetAll returns all variables as a map
85
func (variables *Variable) GetAll() map[string]interface{} {
86
result := make(map[string]interface{}, variables.Len())
87
variables.ForEach(func(key string, value interface{}) {
88
result[key] = value
89
})
90
return result
91
}
92
93
// EvaluateWithInteractsh returns evaluation results of variables with interactsh
94
func (variables *Variable) EvaluateWithInteractsh(values map[string]interface{}, interact *interactsh.Client) (map[string]interface{}, []string) {
95
result := make(map[string]interface{}, variables.Len())
96
97
var interactURLs []string
98
variables.ForEach(func(key string, value interface{}) {
99
if sliceValue, ok := value.([]interface{}); ok {
100
// slices cannot be evaluated
101
result[key] = sliceValue
102
return
103
}
104
valueString := types.ToString(value)
105
if strings.Contains(valueString, "interactsh-url") {
106
valueString, interactURLs = interact.Replace(valueString, interactURLs)
107
}
108
combined := generators.MergeMaps(values, result)
109
if value, ok := combined[key]; ok {
110
valueString = types.ToString(value)
111
}
112
result[key] = evaluateVariableValue(valueString, combined, result)
113
})
114
return result, interactURLs
115
}
116
117
// evaluateVariableValue expression and returns final value
118
func evaluateVariableValue(expression string, values, processing map[string]interface{}) string {
119
finalMap := generators.MergeMaps(values, processing)
120
result, err := expressions.Evaluate(expression, finalMap)
121
if err != nil {
122
return expression
123
}
124
125
return result
126
}
127
128
// checkForLazyEval checks if the variables have any lazy evaluation i.e any dsl function
129
// and sets the flag accordingly.
130
func (variables *Variable) checkForLazyEval() bool {
131
variables.ForEach(func(key string, value interface{}) {
132
for _, v := range protocolutils.KnownVariables {
133
if stringsutil.ContainsAny(types.ToString(value), v) {
134
variables.LazyEval = true
135
return
136
}
137
}
138
// this is a hotfix and not the best way to do it
139
// will be refactored once we move scan state to scanContext (see: https://github.com/projectdiscovery/nuclei/issues/4631)
140
if strings.Contains(types.ToString(value), "interactsh-url") {
141
variables.LazyEval = true
142
return
143
}
144
})
145
return variables.LazyEval
146
}
147
148