github.com/projectdiscovery/nuclei/v2@v2.9.15/pkg/protocols/network/network.go (about) 1 package network 2 3 import ( 4 "strings" 5 6 "github.com/pkg/errors" 7 8 "github.com/projectdiscovery/fastdialer/fastdialer" 9 "github.com/projectdiscovery/nuclei/v2/pkg/operators" 10 "github.com/projectdiscovery/nuclei/v2/pkg/protocols" 11 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/expressions" 12 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/generators" 13 "github.com/projectdiscovery/nuclei/v2/pkg/protocols/network/networkclientpool" 14 fileutil "github.com/projectdiscovery/utils/file" 15 ) 16 17 // Request contains a Network protocol request to be made from a template 18 type Request struct { 19 // ID is the optional id of the request 20 ID string `yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=ID of the network request"` 21 22 // description: | 23 // Host to send network requests to. 24 // 25 // Usually it's set to `{{Hostname}}`. If you want to enable TLS for 26 // TCP Connection, you can use `tls://{{Hostname}}`. 27 // examples: 28 // - value: | 29 // []string{"{{Hostname}}"} 30 Address []string `yaml:"host,omitempty" json:"host,omitempty" jsonschema:"title=host to send requests to,description=Host to send network requests to"` 31 addresses []addressKV 32 33 // description: | 34 // Attack is the type of payload combinations to perform. 35 // 36 // Batteringram is inserts the same payload into all defined payload positions at once, pitchfork combines multiple payload sets and clusterbomb generates 37 // permutations and combinations for all payloads. 38 AttackType generators.AttackTypeHolder `yaml:"attack,omitempty" json:"attack,omitempty" jsonschema:"title=attack is the payload combination,description=Attack is the type of payload combinations to perform,enum=batteringram,enum=pitchfork,enum=clusterbomb"` 39 // description: | 40 // Payloads contains any payloads for the current request. 41 // 42 // Payloads support both key-values combinations where a list 43 // of payloads is provided, or optionally a single file can also 44 // be provided as payload which will be read on run-time. 45 Payloads map[string]interface{} `yaml:"payloads,omitempty" json:"payloads,omitempty" jsonschema:"title=payloads for the network request,description=Payloads contains any payloads for the current request"` 46 47 // description: | 48 // Inputs contains inputs for the network socket 49 Inputs []*Input `yaml:"inputs,omitempty" json:"inputs,omitempty" jsonschema:"title=inputs for the network request,description=Inputs contains any input/output for the current request"` 50 // description: | 51 // Port is the port to send network requests to. this acts as default port but is overriden if target/input contains 52 // non-http(s) ports like 80,8080,8081 etc 53 Port string `yaml:"port,omitempty" json:"port,omitempty" jsonschema:"title=port to send requests to,description=Port to send network requests to"` 54 55 // description: | 56 // ExcludePorts is the list of ports to exclude from being scanned . It is intended to be used with `Port` field and contains a list of ports which are ignored/skipped 57 ExcludePorts string `yaml:"exclude-ports,omitempty" json:"exclude-ports,omitempty" jsonschema:"title=exclude ports from being scanned,description=Exclude ports from being scanned"` 58 // description: | 59 // ReadSize is the size of response to read at the end 60 // 61 // Default value for read-size is 1024. 62 // examples: 63 // - value: "2048" 64 ReadSize int `yaml:"read-size,omitempty" json:"read-size,omitempty" jsonschema:"title=size of network response to read,description=Size of response to read at the end. Default is 1024 bytes"` 65 // description: | 66 // ReadAll determines if the data stream should be read till the end regardless of the size 67 // 68 // Default value for read-all is false. 69 // examples: 70 // - value: false 71 ReadAll bool `yaml:"read-all,omitempty" json:"read-all,omitempty" jsonschema:"title=read all response stream,description=Read all response stream till the server stops sending"` 72 73 // description: | 74 // SelfContained specifies if the request is self-contained. 75 SelfContained bool `yaml:"-" json:"-"` 76 77 // Operators for the current request go here. 78 operators.Operators `yaml:",inline,omitempty"` 79 CompiledOperators *operators.Operators `yaml:"-"` 80 81 generator *generators.PayloadGenerator 82 // cache any variables that may be needed for operation. 83 dialer *fastdialer.Dialer 84 options *protocols.ExecutorOptions 85 } 86 87 // RequestPartDefinitions contains a mapping of request part definitions and their 88 // description. Multiple definitions are separated by commas. 89 // Definitions not having a name (generated on runtime) are prefixed & suffixed by <>. 90 var RequestPartDefinitions = map[string]string{ 91 "template-id": "ID of the template executed", 92 "template-info": "Info Block of the template executed", 93 "template-path": "Path of the template executed", 94 "host": "Host is the input to the template", 95 "matched": "Matched is the input which was matched upon", 96 "type": "Type is the type of request made", 97 "request": "Network request made from the client", 98 "body,all,data": "Network response received from server (default)", 99 "raw": "Full Network protocol data", 100 } 101 102 type addressKV struct { 103 address string 104 tls bool 105 } 106 107 // Input is the input to send on the network 108 type Input struct { 109 // description: | 110 // Data is the data to send as the input. 111 // 112 // It supports DSL Helper Functions as well as normal expressions. 113 // examples: 114 // - value: "\"TEST\"" 115 // - value: "\"hex_decode('50494e47')\"" 116 Data string `yaml:"data,omitempty" json:"data,omitempty" jsonschema:"title=data to send as input,description=Data is the data to send as the input"` 117 // description: | 118 // Type is the type of input specified in `data` field. 119 // 120 // Default value is text, but hex can be used for hex formatted data. 121 // values: 122 // - "hex" 123 // - "text" 124 Type NetworkInputTypeHolder `yaml:"type,omitempty" json:"type,omitempty" jsonschema:"title=type is the type of input data,description=Type of input specified in data field,enum=hex,enum=text"` 125 // description: | 126 // Read is the number of bytes to read from socket. 127 // 128 // This can be used for protocols which expect an immediate response. You can 129 // read and write responses one after another and eventually perform matching 130 // on every data captured with `name` attribute. 131 // 132 // The [network docs](https://nuclei.projectdiscovery.io/templating-guide/protocols/network/) highlight more on how to do this. 133 // examples: 134 // - value: "1024" 135 Read int `yaml:"read,omitempty" json:"read,omitempty" jsonschema:"title=bytes to read from socket,description=Number of bytes to read from socket"` 136 // description: | 137 // Name is the optional name of the data read to provide matching on. 138 // examples: 139 // - value: "\"prefix\"" 140 Name string `yaml:"name,omitempty" json:"name,omitempty" jsonschema:"title=optional name for data read,description=Optional name of the data read to provide matching on"` 141 } 142 143 // GetID returns the unique ID of the request if any. 144 func (request *Request) GetID() string { 145 return request.ID 146 } 147 148 // Compile compiles the protocol request for further execution. 149 func (request *Request) Compile(options *protocols.ExecutorOptions) error { 150 var shouldUseTLS bool 151 var err error 152 153 request.options = options 154 for _, address := range request.Address { 155 // check if the connection should be encrypted 156 if strings.HasPrefix(address, "tls://") { 157 shouldUseTLS = true 158 address = strings.TrimPrefix(address, "tls://") 159 } 160 request.addresses = append(request.addresses, addressKV{address: address, tls: shouldUseTLS}) 161 } 162 // Pre-compile any input dsl functions before executing the request. 163 for _, input := range request.Inputs { 164 if input.Type.String() != "" { 165 continue 166 } 167 if compiled, evalErr := expressions.Evaluate(input.Data, map[string]interface{}{}); evalErr == nil { 168 input.Data = compiled 169 } 170 } 171 172 // Resolve payload paths from vars if they exists 173 for name, payload := range request.options.Options.Vars.AsMap() { 174 payloadStr, ok := payload.(string) 175 // check if inputs contains the payload 176 var hasPayloadName bool 177 for _, input := range request.Inputs { 178 if input.Type.String() != "" { 179 continue 180 } 181 if expressions.ContainsVariablesWithNames(map[string]interface{}{name: payload}, input.Data) == nil { 182 hasPayloadName = true 183 break 184 } 185 } 186 if ok && hasPayloadName && fileutil.FileExists(payloadStr) { 187 if request.Payloads == nil { 188 request.Payloads = make(map[string]interface{}) 189 } 190 request.Payloads[name] = payloadStr 191 } 192 } 193 194 if len(request.Payloads) > 0 { 195 request.generator, err = generators.New(request.Payloads, request.AttackType.Value, request.options.TemplatePath, request.options.Options.AllowLocalFileAccess, request.options.Catalog, request.options.Options.AttackType) 196 if err != nil { 197 return errors.Wrap(err, "could not parse payloads") 198 } 199 } 200 201 // Create a client for the class 202 client, err := networkclientpool.Get(options.Options, &networkclientpool.Configuration{}) 203 if err != nil { 204 return errors.Wrap(err, "could not get network client") 205 } 206 request.dialer = client 207 208 if len(request.Matchers) > 0 || len(request.Extractors) > 0 { 209 compiled := &request.Operators 210 compiled.ExcludeMatchers = options.ExcludeMatchers 211 compiled.TemplateID = options.TemplateID 212 if err := compiled.Compile(); err != nil { 213 return errors.Wrap(err, "could not compile operators") 214 } 215 request.CompiledOperators = compiled 216 } 217 return nil 218 } 219 220 // Requests returns the total number of requests the YAML rule will perform 221 func (request *Request) Requests() int { 222 return len(request.Address) 223 }