github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/common/fuzz/execute.go (about) 1 package fuzz 2 3 import ( 4 "regexp" 5 "strings" 6 7 "github.com/pkg/errors" 8 "github.com/projectdiscovery/nuclei/v2/pkg/protocols" 9 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/contextargs" 10 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators" 11 "github.com/projectdiscovery/retryablehttp-go" 12 urlutil "github.com/projectdiscovery/utils/url" 13 ) 14 15 // ExecuteRuleInput is the input for rule Execute function 16 type ExecuteRuleInput struct { 17 // Input is the context args input 18 Input *contextargs.Context 19 // Callback is the callback for generated rule requests 20 Callback func(GeneratedRequest) bool 21 // InteractURLs contains interact urls for execute call 22 InteractURLs []string 23 // Values contains dynamic values for the rule 24 Values map[string]interface{} 25 // BaseRequest is the base http request for fuzzing rule 26 BaseRequest *retryablehttp.Request 27 } 28 29 // GeneratedRequest is a single generated request for rule 30 type GeneratedRequest struct { 31 // Request is the http request for rule 32 Request *retryablehttp.Request 33 // InteractURLs is the list of interactsh urls 34 InteractURLs []string 35 // DynamicValues contains dynamic values map 36 DynamicValues map[string]interface{} 37 } 38 39 // Execute executes a fuzzing rule accepting a callback on which 40 // generated requests are returned. 41 // 42 // Input is not thread safe and should not be shared between concurrent 43 // goroutines. 44 func (rule *Rule) Execute(input *ExecuteRuleInput) error { 45 if !rule.isExecutable(input.Input) { 46 return nil 47 } 48 baseValues := input.Values 49 if rule.generator == nil { 50 evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(baseValues, rule.options.Interactsh) 51 input.Values = generators.MergeMaps(evaluatedValues, baseValues, rule.options.Constants) 52 input.InteractURLs = interactURLs 53 err := rule.executeRuleValues(input) 54 return err 55 } 56 iterator := rule.generator.NewIterator() 57 for { 58 values, next := iterator.Value() 59 if !next { 60 return nil 61 } 62 evaluatedValues, interactURLs := rule.options.Variables.EvaluateWithInteractsh(generators.MergeMaps(values, baseValues), rule.options.Interactsh) 63 input.InteractURLs = interactURLs 64 input.Values = generators.MergeMaps(values, evaluatedValues, baseValues, rule.options.Constants) 65 66 if err := rule.executeRuleValues(input); err != nil { 67 return err 68 } 69 } 70 } 71 72 // isExecutable returns true if the rule can be executed based on provided input 73 func (rule *Rule) isExecutable(input *contextargs.Context) bool { 74 parsed, err := urlutil.Parse(input.MetaInput.Input) 75 if err != nil { 76 return false 77 } 78 if !parsed.Query().IsEmpty() && rule.partType == queryPartType { 79 return true 80 } 81 return false 82 } 83 84 // executeRuleValues executes a rule with a set of values 85 func (rule *Rule) executeRuleValues(input *ExecuteRuleInput) error { 86 for _, payload := range rule.Fuzz { 87 if err := rule.executePartRule(input, payload); err != nil { 88 return err 89 } 90 } 91 return nil 92 } 93 94 // Compile compiles a fuzzing rule and initializes it for operation 95 func (rule *Rule) Compile(generator *generators.PayloadGenerator, options *protocols.ExecutorOptions) error { 96 // If a payload generator is specified from base request, use it 97 // for payload values. 98 if generator != nil { 99 rule.generator = generator 100 } 101 rule.options = options 102 103 // Resolve the default enums 104 if rule.Mode != "" { 105 if valueType, ok := stringToModeType[rule.Mode]; !ok { 106 return errors.Errorf("invalid mode value specified: %s", rule.Mode) 107 } else { 108 rule.modeType = valueType 109 } 110 } else { 111 rule.modeType = multipleModeType 112 } 113 if rule.Part != "" { 114 if valueType, ok := stringToPartType[rule.Part]; !ok { 115 return errors.Errorf("invalid part value specified: %s", rule.Part) 116 } else { 117 rule.partType = valueType 118 } 119 } else { 120 rule.partType = queryPartType 121 } 122 123 if rule.Type != "" { 124 if valueType, ok := stringToRuleType[rule.Type]; !ok { 125 return errors.Errorf("invalid type value specified: %s", rule.Type) 126 } else { 127 rule.ruleType = valueType 128 } 129 } else { 130 rule.ruleType = replaceRuleType 131 } 132 133 // Initialize other required regexes and maps 134 if len(rule.Keys) > 0 { 135 rule.keysMap = make(map[string]struct{}) 136 } 137 for _, key := range rule.Keys { 138 rule.keysMap[strings.ToLower(key)] = struct{}{} 139 } 140 for _, value := range rule.ValuesRegex { 141 compiled, err := regexp.Compile(value) 142 if err != nil { 143 return errors.Wrap(err, "could not compile value regex") 144 } 145 rule.valuesRegex = append(rule.valuesRegex, compiled) 146 } 147 for _, value := range rule.KeysRegex { 148 compiled, err := regexp.Compile(value) 149 if err != nil { 150 return errors.Wrap(err, "could not compile key regex") 151 } 152 rule.keysRegex = append(rule.keysRegex, compiled) 153 } 154 return nil 155 }