From d04511494d90a0afe7dfd2030d56e13d2887e335 Mon Sep 17 00:00:00 2001 From: Ice3man543 Date: Tue, 27 Jul 2021 16:03:56 +0530 Subject: [PATCH] Added new YAML based doc to structures --- v2/pkg/operators/extractors/extractors.go | 58 +++++++-- v2/pkg/operators/matchers/matchers.go | 97 +++++++++++--- v2/pkg/operators/operators.go | 21 ++- v2/pkg/protocols/dns/dns.go | 40 +++++- v2/pkg/protocols/file/file.go | 26 +++- v2/pkg/protocols/headless/engine/action.go | 44 ++++++- v2/pkg/protocols/headless/headless.go | 3 +- v2/pkg/protocols/http/http.go | 141 +++++++++++++++++---- v2/pkg/protocols/http/http_test.go | 1 - v2/pkg/protocols/network/network.go | 69 ++++++++-- v2/pkg/templates/templates.go | 50 ++++++-- v2/pkg/workflows/workflows.go | 26 +++- 12 files changed, 478 insertions(+), 98 deletions(-) diff --git a/v2/pkg/operators/extractors/extractors.go b/v2/pkg/operators/extractors/extractors.go index f593a174..ff07fa01 100644 --- a/v2/pkg/operators/extractors/extractors.go +++ b/v2/pkg/operators/extractors/extractors.go @@ -4,28 +4,70 @@ import "regexp" // Extractor is used to extract part of response using a regex. type Extractor struct { - // Name is the extractor's name + // description: | + // Name of the extractor. Name should be lowercase and must not contain + // spaces or dashes (-). + // examples: + // - value: "\"cookie-extractor\"" Name string `yaml:"name,omitempty"` - // Type is the type of the extractor + // description: | + // Type is the type of the extractor. + // values: + // - "regex" + // - "kval" Type string `yaml:"type"` // extractorType is the internal type of the extractor extractorType ExtractorType - // Regex are the regex pattern required to be present in the response + // description: | + // Regex contains the regular expression patterns to exract from a part. + // + // Go regex engine does not supports lookaheads or lookbehinds, so as a result + // they are also not supported in nuclei. + // examples: + // - name: Braintree Access Token Regex + // value: > + // []string{"access_token\\$production\\$[0-9a-z]{16}\\$[0-9a-f]{32}"} + // - name: Wordpress Author Extraction regex + // value: > + // []string{"Author:(?:[A-Za-z0-9 -\\_=\"]+)?([A-Za-z0-9]+)<\\/span>"} Regex []string `yaml:"regex"` - // RegexGroup specifies a group to extract from the regex + // description: | + // Group specifies a numbered group to extract from the regex. + // examples: + // - name: Example Regex Group + // - value: "1" RegexGroup int `yaml:"group"` // regexCompiled is the compiled variant regexCompiled []*regexp.Regexp - // KVal are the kval to be present in the response headers/cookies + // description: | + // kval contains the key-value pairs required in the response. + // + // Each protocol exposes a lot of different data in response. The kval + // extractor can be used to extract those key-value pairs. A list of + // supported parts is available in docs for request types. + // examples: + // - name: Extract Server Header From HTTP Response + // value: > + // []string{"Server"} + // - name: Extracting value of PHPSESSID Cookie + // value: > + // []string{"PHPSESSID"} KVal []string `yaml:"kval,omitempty"` - // Part is the part of the request to match + // description: | + // Part is the part of the request response to extract data from. // - // By default, matching is performed in request body. + // Each protocol exposes a lot of different parts which are well + // documented in docs for each request type. + // examples: + // - value: "\"body\"" + // - value: "\"raw\"" Part string `yaml:"part,omitempty"` - // Internal defines if this is used internally + // description: | + // Internal, when set to true will allow using the value extracted + // in the next request for some protocols (like HTTP). Internal bool `yaml:"internal,omitempty"` } diff --git a/v2/pkg/operators/matchers/matchers.go b/v2/pkg/operators/matchers/matchers.go index 2a13b6a1..c8484c0c 100644 --- a/v2/pkg/operators/matchers/matchers.go +++ b/v2/pkg/operators/matchers/matchers.go @@ -8,35 +8,102 @@ import ( // Matcher is used to match a part in the output from a protocol. type Matcher struct { - // Type is the type of the matcher + // description: | + // Type is the type of the matcher. + // values: + // - "status" + // - "size" + // - "word" + // - "regex" + // - "binary" + // - "dsl" Type string `yaml:"type"` - // Condition is the optional condition between two matcher variables - // - // By default, the condition is assumed to be OR. + // description: | + // Condition is the optional condition between two matcher variables. By default, + // the condition is assumed to be OR. + // values: + // - "and" + // - "or" Condition string `yaml:"condition,omitempty"` - // Part is the part of the data to match + // description: | + // Part is the part of the request response to match data from. + // + // Each protocol exposes a lot of different parts which are well + // documented in docs for each request type. + // examples: + // - value: "\"body\"" + // - value: "\"raw\"" Part string `yaml:"part,omitempty"` - // Negative specifies if the match should be reversed - // It will only match if the condition is not true. + // description: | + // Negative specifies if the match should be reversed + // It will only match if the condition is not true. Negative bool `yaml:"negative,omitempty"` - // Name is matcher Name + // description: | + // Name of the matcher. Name should be lowercase and must not contain + // spaces or dashes (-). + // examples: + // - value: "\"cookie-matcher\"" Name string `yaml:"name,omitempty"` - // Status are the acceptable status codes for the response + // description: | + // Status are the acceptable status codes for the response. + // examples: + // - value: > + // []int{200, 302} Status []int `yaml:"status,omitempty"` - // Size is the acceptable size for the response + // description: | + // Size is the acceptable size for the response + // examples: + // - value: > + // []int{3029, 2042} Size []int `yaml:"size,omitempty"` - // Words are the words required to be present in the response + // description: | + // Words contains word patterns required to be present in the response part. + // examples: + // - name: Match for outlook mail protection domain + // value: > + // []string{"mail.protection.outlook.com"} + // - name: Match for application/json in response headers + // value: > + // []string{"application/json"} Words []string `yaml:"words,omitempty"` - // Regex are the regex pattern required to be present in the response + // description: | + // Regex contains Regular Expression patterns required to be present in the response part. + // examples: + // - name: Match for Linkerd Service via Regex + // value: > + // []string{`(?mi)^Via\\s*?:.*?linkerd.*$`} + // - name: Match for Open Redirect via Location header + // value: > + // []string{`(?m)^(?:Location\\s*?:\\s*?)(?:https?://|//)?(?:[a-zA-Z0-9\\-_\\.@]*)example\\.com.*$`} Regex []string `yaml:"regex,omitempty"` - // Binary are the binary characters required to be present in the response + // description: | + // Binary are the binary patterns required to be present in the response part. + // examples: + // - name: Match for Springboot Heapdump Actuator "JAVA PROFILE", "HPROF", "Gunzip magic byte" + // value: > + // []string{"4a4156412050524f46494c45", "4850524f46", "1f8b080000000000"} + // - name: Match for 7zip files + // value: > + // []string{"377ABCAF271C"} Binary []string `yaml:"binary,omitempty"` - // DSL are the dsl queries + // description: | + // DSL are the dsl expressions that will be evaluated as part of nuclei matching rules. + // A list of these helper functions are available [here](https://nuclei.projectdiscovery.io/templating-guide/helper-functions/). + // examples: + // - name: DSL Matcher for package.json file + // value: > + // []string{"contains(body, 'packages') && contains(tolower(all_headers), 'application/octet-stream') && status_code == 200"} + // - name: DSL Matcher for missing strict transport security header + // value: > + // []string{"!contains(tolower(all_headers), ''strict-transport-security'')"} DSL []string `yaml:"dsl,omitempty"` - // Encoding specifies the encoding for the word content if any. + // description: | + // Encoding specifies the encoding for the words field if any. + // values: + // - "hex" Encoding string `yaml:"encoding,omitempty"` // cached data for the compiled matcher diff --git a/v2/pkg/operators/operators.go b/v2/pkg/operators/operators.go index 2497fa49..26149f95 100644 --- a/v2/pkg/operators/operators.go +++ b/v2/pkg/operators/operators.go @@ -8,14 +8,23 @@ import ( // Operators contains the operators that can be applied on protocols type Operators struct { - // Matchers contains the detection mechanism for the request to identify - // whether the request was successful + // description: | + // Matchers contains the detection mechanism for the request to identify + // whether the request was successful by doing pattern matching + // on request/responses. + // + // Multiple matchers can be combined together with `matcher-condition` flag + // which accepts either `and` or `or` as argument. Matchers []*matchers.Matcher `yaml:"matchers,omitempty"` - // Extractors contains the extraction mechanism for the request to identify - // and extract parts of the response. + // description: | + // Extractors contains the extraction mechanism for the request to identify + // and extract parts of the response. Extractors []*extractors.Extractor `yaml:"extractors,omitempty"` - // MatchersCondition is the condition of the matchers - // whether to use AND or OR. Default is OR. + // description: | + // MatchersCondition is the condition between the matchers. Default is OR. + // values: + // - "and" + // - "or" MatchersCondition string `yaml:"matchers-condition,omitempty"` // cached variables that may be used along with request. matchersCondition matchers.ConditionType diff --git a/v2/pkg/protocols/dns/dns.go b/v2/pkg/protocols/dns/dns.go index 0538186f..571a4c83 100644 --- a/v2/pkg/protocols/dns/dns.go +++ b/v2/pkg/protocols/dns/dns.go @@ -20,13 +20,42 @@ type Request struct { ID string `yaml:"id"` - // Path contains the path/s for the request + // description: | + // Name is the Hostname to make DNS request for. + // + // Generally, it is set to {{FQDN}} which is the domain we get from input. + // examples: + // - value: "\"{{FQDN}}\"" Name string `yaml:"name"` - // Type is the type of DNS request to make + // description: | + // Type is the type of DNS request to make. + // values: + // - "A" + // - "NS" + // - "CNAME" + // - "SOA" + // - "PTR" + // - "MX" + // - "TXT" + // - "AAAA" Type string `yaml:"type"` - // Class is the class of the DNS request + // description: | + // Class is the class of the DNS request. + // + // Usually it's enough to just leave it as INET. + // values: + // - "INET" + // - "CSNET" + // - "CHAOS" + // - "HESIOD" + // - "NONE" + // - "ANY" Class string `yaml:"class"` - // Retries is the number of retries for the DNS request + // description: | + // Retries is the number of retries for the DNS request + // examples: + // - name: Use a retry of 3 to 5 generally + // value: 5 Retries int `yaml:"retries"` CompiledOperators *operators.Operators @@ -37,7 +66,8 @@ type Request struct { class uint16 question uint16 - // Recursion specifies whether to recurse all the answers. + // description: | + // Recursion determines if resolver should recurse all records to get fresh results. Recursion bool `yaml:"recursion"` } diff --git a/v2/pkg/protocols/file/file.go b/v2/pkg/protocols/file/file.go index d5b81018..81643c10 100644 --- a/v2/pkg/protocols/file/file.go +++ b/v2/pkg/protocols/file/file.go @@ -12,16 +12,29 @@ import ( type Request struct { // Operators for the current request go here. operators.Operators `yaml:",inline"` - // Extensions is the list of extensions to perform matching on. + // description: | + // Extensions is the list of extensions to perform matching on. + // examples: + // - value: '[]string{".txt", ".go", ".json"}' Extensions []string `yaml:"extensions"` - // ExtensionDenylist is the list of file extensions to deny during matching. + // description: | + // ExtensionDenylist is the list of file extensions to deny during matching. + // + // By default, it contains some non-interesting extensions that are hardcoded + // in nuclei. + // examples: + // - value: '[]string{".avi", ".mov", ".mp3"}' ExtensionDenylist []string `yaml:"denylist"` ID string `yaml:"id"` - // MaxSize is the maximum size of the file to run request on. - // By default, nuclei will process 5MB files and not go more than that. - // It can be set to much lower or higher depending on use. + // description: | + // MaxSize is the maximum size of the file to run request on. + // + // By default, nuclei will process 5MB files and not go more than that. + // It can be set to much lower or higher depending on use. + // examples: + // - value: 2048 MaxSize int `yaml:"max-size"` CompiledOperators *operators.Operators @@ -30,7 +43,8 @@ type Request struct { extensions map[string]struct{} extensionDenylist map[string]struct{} - // NoRecursive specifies whether to not do recursive checks if folders are provided. + // description: | + // NoRecursive specifies whether to not do recursive checks if folders are provided. NoRecursive bool `yaml:"no-recursive"` allExtensions bool diff --git a/v2/pkg/protocols/headless/engine/action.go b/v2/pkg/protocols/headless/engine/action.go index 3c5296ad..6ad6973f 100644 --- a/v2/pkg/protocols/headless/engine/action.go +++ b/v2/pkg/protocols/headless/engine/action.go @@ -109,10 +109,46 @@ var ActionToActionString = map[ActionType]string{ // are discovered on the found page. We also keep track and only // scrape new navigation from pages we haven't crawled yet. type Action struct { - Data map[string]string `yaml:"args,omitempty"` - Name string `yaml:"name,omitempty"` - Description string `yaml:"description,omitempty"` - ActionType string `yaml:"action"` + // description: + // Args contain arguments for the headless action. + // + // Per action arguments are described in detail [here](https://nuclei.projectdiscovery.io/templating-guide/protocols/headless/). + Data map[string]string `yaml:"args,omitempty"` + // description: | + // Name is the name assigned to the headless action. + // + // This can be used to execute code, for instance in browser + // DOM using script action, and get the result in a variable + // which can be matched upon by nuclei. An Example template [here](https://github.com/projectdiscovery/nuclei-templates/blob/master/headless/prototype-pollution-check.yaml). + Name string `yaml:"name,omitempty"` + // description: | + // Description is the optional description of the headless action + Description string `yaml:"description,omitempty"` + // description: | + // Action is the type of the action to perform. + // values: + // - "navigate" + // - "script" + // - "click" + // - "rightclick" + // - "text" + // - "screenshot" + // - "time" + // - "select" + // - "files" + // - "waitload" + // - "getresource" + // - "extract" + // - "setmethod" + // - "addheader" + // - "setheader" + // - "deleteheader" + // - "setbody" + // - "waitevent" + // - "keyboard" + // - "debug" + // - "sleep" + ActionType string `yaml:"action"` } // String returns the string representation of an action diff --git a/v2/pkg/protocols/headless/headless.go b/v2/pkg/protocols/headless/headless.go index 77a36931..e33effa6 100644 --- a/v2/pkg/protocols/headless/headless.go +++ b/v2/pkg/protocols/headless/headless.go @@ -11,7 +11,8 @@ import ( type Request struct { ID string `yaml:"id"` - // Steps is the list of actions to run for headless request + // description: | + // Steps is the list of actions to run for headless request Steps []*engine.Action `yaml:"steps"` // Operators for the current request go here. diff --git a/v2/pkg/protocols/http/http.go b/v2/pkg/protocols/http/http.go index ecd297f8..eae261f5 100644 --- a/v2/pkg/protocols/http/http.go +++ b/v2/pkg/protocols/http/http.go @@ -16,36 +16,110 @@ import ( type Request struct { // Operators for the current request go here. operators.Operators `yaml:",inline"` - // Path contains the path/s for the request + // description: | + // Path contains the path/s for the HTTP requests. It supports variables + // as placeholders. + // examples: + // - name: Some example path values + // value: > + // []string{"{{BaseURL}}", "{{BaseURL}}/+CSCOU+/../+CSCOE+/files/file_list.json?path=/sessions"} Path []string `yaml:"path"` - // Raw contains raw requests + // description: | + // Raw contains HTTP Requests in Raw format. + // examples: + // - name: Some example raw requests + // value: | + // []string{"GET /etc/passwd HTTP/1.1\nHost:\nContent-Length: 4", "POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.1\nHost: {{Hostname}}\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0\nContent-Length: 1\nConnection: close\n\necho\necho\ncat /etc/passwd 2>&1"} Raw []string `yaml:"raw"` - ID string `yaml:"id"` - // Name is the name of the request + // docgen:nodoc + ID string `yaml:"-"` + // description: | + // Name is the optional name of the request. + // + // If a name is specified, all the named request in a template can be matched upon + // in a combined manner allowing multirequest based matchers. Name string `yaml:"Name"` - // AttackType is the attack type - // Sniper, PitchFork and ClusterBomb. Default is Sniper + // description: | + // Attack is the type of payload combinations to perform. + // + // Sniper is each payload once, pitchfork combines multiple payload sets and clusterbomb generates + // permutations and combinations for all payloads. + // values: + // - "sniper" + // - "pitchfork" + // - "clusterbomb" AttackType string `yaml:"attack"` - // Method is the request method, whether GET, POST, PUT, etc + // description: | + // Method is the HTTP Request Method. + // values: + // - "GET" + // - "POST" + // - "PUT" + // - "DELETE" Method string `yaml:"method"` - // Body is an optional parameter which contains the request body for POST methods, etc + // description: | + // Body is an optional parameter which contains HTTP Request body. + // examples: + // - name: Same Body for a Login POST request + // value: "\"username=test&password=test\"" Body string `yaml:"body"` - // Path contains the path/s for the request variables + // description: | + // Payloads contains any payloads for the current request. + // + // Payloads support both key-values combinations where a list + // of payloads is provided, or optionally a single file can also + // be provided as payload which will be read on run-time. + // examples: + // - name: A payload list for Tomcat Bruteforce + // value: exampleTomcatUserPassPayload + // - name: A payload example of reading from file + // value: exampleFileBasedPayload Payloads map[string]interface{} `yaml:"payloads"` - // Headers contains headers to send with the request + // description: | + // Headers contains HTTP Headers to send with the request. + // examples: + // - value: | + // map[string]string{"Content-Type": "application/x-www-form-urlencoded", "Content-Length": "1", "Any-Header": "Any-Value"} Headers map[string]string `yaml:"headers"` - // RaceNumberRequests is the number of same request to send in race condition attack + // description: | + // RaceCount is the number of times to send a request in Race Condition Attack. + // examples: + // - name: Send a request 5 times + // value: "5" RaceNumberRequests int `yaml:"race_count"` - // MaxRedirects is the maximum number of redirects that should be followed. + // description: | + // MaxRedirects is the maximum number of redirects that should be followed. + // examples: + // - name: Follow upto 5 redirects + // value: "5" MaxRedirects int `yaml:"max-redirects"` - // PipelineConcurrentConnections is number of connections in pipelining + // description: | + // PipelineConcurrentConnections is number of connections to create during pipelining. + // examples: + // - name: Create 40 concurrent connections + // value: 40 PipelineConcurrentConnections int `yaml:"pipeline-concurrent-connections"` - // PipelineRequestsPerConnection is number of requests in pipelining + // description: | + // PipelineRequestsPerConnection is number of requests to send per connection when pipelining. + // examples: + // - name: Send 100 requests per pipeline connection + // value: 100 PipelineRequestsPerConnection int `yaml:"pipeline-requests-per-connection"` - // Threads specifies number of threads for sending requests + // description: | + // Threads specifies number of threads to use sending requests. This enables Connection Pooling. + // + // Connection: Close attribute must not be used in request while using threads flag, otherwise + // pooling will fail and engine will continue to close connections after requests. + // examples: + // - name: Send requests using 10 concurrent threads + // value: 10 Threads int `yaml:"threads"` - // MaxSize is the maximum size of http response body to read in bytes. + // description: | + // MaxSize is the maximum size of http response body to read in bytes. + // examples: + // - name: Read max 2048 bytes of the response + // value: 2048 MaxSize int `yaml:"max-size"` CompiledOperators *operators.Operators @@ -57,21 +131,36 @@ type Request struct { generator *generators.Generator // optional, only enabled when using payloads httpClient *retryablehttp.Client rawhttpClient *rawhttp.Client - // CookieReuse is an optional setting that makes cookies shared within requests + + // description: | + // CookieReuse is an optional setting that enables cookie reuse for + // all requests defined in raw section. CookieReuse bool `yaml:"cookie-reuse"` - // Redirects specifies whether redirects should be followed. + // description: | + // Redirects specifies whether redirects should be followed by the HTTP Client. + // + // This can be used in conjunction with `max-redirects` to control the HTTP request redirects. Redirects bool `yaml:"redirects"` - // Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining (race conditions/billions requests) - // All requests must be indempotent (GET/POST) + // description: | + // Pipeline defines if the attack should be performed with HTTP 1.1 Pipelining + // + // All requests must be indempotent (GET/POST). This can be used for race conditions/billions requests. Pipeline bool `yaml:"pipeline"` - // Specify in order to skip request RFC normalization + // description: | + // Unsafe specifies whether to use rawhttp engine for sending Non RFC-Compliant requests. + // + // This uses the [rawhttp](https://github.com/projectdiscovery/rawhttp) engine to achieve complete + // control over the request, with no normalization performed by the client. Unsafe bool `yaml:"unsafe"` - // Race determines if all the request have to be attempted at the same time - // The minimum number of requests is determined by threads + // description: | + // Race determines if all the request have to be attempted at the same time (Race Condition) + // + // The actual number of requests that will be sent is determined by the `race_count` field. Race bool `yaml:"race"` - // ReqCondition automatically assigns numbers to requests and preserves - // their history for being matched at the end. - // Currently only works with sequential http requests. + // description: | + // ReqCondition automatically assigns numbers to requests and preserves their history. + // + // This allows matching on them later for multi-request conditions. ReqCondition bool `yaml:"req-condition"` } diff --git a/v2/pkg/protocols/http/http_test.go b/v2/pkg/protocols/http/http_test.go index 9cc22a7c..1cf6b561 100644 --- a/v2/pkg/protocols/http/http_test.go +++ b/v2/pkg/protocols/http/http_test.go @@ -14,7 +14,6 @@ func TestHTTPCompile(t *testing.T) { testutils.Init(options) templateID := "testing-http" request := &Request{ - ID: templateID, Name: "testing", Payloads: map[string]interface{}{ "username": []string{"admin"}, diff --git a/v2/pkg/protocols/network/network.go b/v2/pkg/protocols/network/network.go index 196fcbcd..40619fca 100644 --- a/v2/pkg/protocols/network/network.go +++ b/v2/pkg/protocols/network/network.go @@ -17,19 +17,44 @@ import ( type Request struct { ID string `yaml:"id"` - // Address is the address to send requests to (host:port:tls combos generally) + // description: | + // Address is the address to send requests to. + // + // Usually it's set to `{{Hostname}}`. If you want to enable TLS for + // TCP Connection, you can use `tls://{{Hostname}}`. + // examples: + // - value: | + // []string{"{{Hostname}}"} Address []string `yaml:"host"` addresses []addressKV - // AttackType is the attack type - // Sniper, PitchFork and ClusterBomb. Default is Sniper + // description: | + // Attack is the type of payload combinations to perform. + // + // Sniper is each payload once, pitchfork combines multiple payload sets and clusterbomb generates + // permutations and combinations for all payloads. + // values: + // - "sniper" + // - "pitchfork" + // - "clusterbomb" AttackType string `yaml:"attack"` - // Path contains the path/s for the request variables + // description: | + // Payloads contains any payloads for the current request. + // + // Payloads support both key-values combinations where a list + // of payloads is provided, or optionally a single file can also + // be provided as payload which will be read on run-time. Payloads map[string]interface{} `yaml:"payloads"` - // Payload is the payload to send for the network request + // description: | + // Inputs contains inputs for the network socket Inputs []*Input `yaml:"inputs"` - // ReadSize is the size of response to read (1024 if not provided by default) + // description: | + // ReadSize is the size of response to read at the end + // + // Default value for read-size is 1024. + // examples: + // - value: "2048" ReadSize int `yaml:"read-size"` // Operators for the current request go here. @@ -51,13 +76,37 @@ type addressKV struct { // Input is the input to send on the network type Input struct { - // Data is the data to send as the input + // description: | + // Data is the data to send as the input. + // + // It supports DSL Helper Functions as well as normal expressions. + // examples: + // - value: "\"TEST\"" + // - value: "\"hex_decode('50494e47')\"" Data string `yaml:"data"` - // Type is the type of input - hex, text. + // description: | + // Type is the type of input specified in `data` field. + // + // Default value is text, but hex can be used for hex formatted data. + // values: + // - "hex" + // - "text" Type string `yaml:"type"` - // Read is the number of bytes to read from socket + // description: | + // Read is the number of bytes to read from socket. + // + // This can be used for protcols which expected an immediate response. You can + // read and write responses one after another and evetually perform matching + // on every data captured with `name` attribute. + // + // The [network docs](https://nuclei.projectdiscovery.io/templating-guide/protocols/network/) highlight more on how to do this. + // examples: + // - value: "1024" Read int `yaml:"read"` - // Name is the optional name of the input to provide matching on + // description: | + // Name is the optional name of the data read to provide matching on. + // examples: + // - value: "\"prefix\"" Name string `yaml:"name"` } diff --git a/v2/pkg/templates/templates.go b/v2/pkg/templates/templates.go index 12c135e4..1696cd0a 100644 --- a/v2/pkg/templates/templates.go +++ b/v2/pkg/templates/templates.go @@ -10,24 +10,56 @@ import ( "github.com/projectdiscovery/nuclei/v2/pkg/workflows" ) -// Template is a request template parsed from a yaml file +var ( + exampleTomcatUserPassPayload = map[string]interface{}{ + "username": []string{"tomcat", "admin"}, + "password": []string{"tomcat", "admin", "password"}, + } + exampleFileBasedPayload = map[string]interface{}{ + "data": "helpers/payloads/command-injection.txt", + } +) + +// Template is a YAML input file which defines the requests and +// others metadata for a scan template. type Template struct { - // ID is the unique id for the template + // description: | + // ID is the unique id for the template. IDs must be lowercase + // and must not contain spaces in it. + // + // #### Good IDs + // + // A good ID unqiuely identifies what the requests in the template + // are doing. Let's say you have a template that identifies a git-config + // file on the webservers, a good name would be `git-config-exposure`. Another + // example name is `azure-apps-nxdomain-takeover`. + // examples: + // - name: ID Example + // value: "\"cve-2021-19520\"" ID string `yaml:"id"` - // Info contains information about the template + // description: | + // Info contains metadata information about the template. At minimum, it + // should contain `name`, `author`, `severity`, `description`, `tags`. Optionally + // you can also specify a list of `references` for the template. Info map[string]interface{} `yaml:"info"` - // RequestsHTTP contains the http request to make in the template + // description: | + // Requests contains the http request to make in the template RequestsHTTP []*http.Request `yaml:"requests,omitempty" json:"requests"` - // RequestsDNS contains the dns request to make in the template + // description: | + // DNS contains the dns request to make in the template RequestsDNS []*dns.Request `yaml:"dns,omitempty" json:"dns"` - // RequestsFile contains the file request to make in the template + // description: | + // File contains the file request to make in the template RequestsFile []*file.Request `yaml:"file,omitempty" json:"file"` - // RequestsNetwork contains the network request to make in the template + // description: | + // Network contains the network request to make in the template RequestsNetwork []*network.Request `yaml:"network,omitempty" json:"network"` - // RequestsHeadless contains the headless request to make in the template. + // description: | + // Headless contains the headless request to make in the template. RequestsHeadless []*headless.Request `yaml:"headless,omitempty" json:"headless"` - // Workflows is a yaml based workflow declaration code. + // description: | + // Workflows is a yaml based workflow declaration code. workflows.Workflow `yaml:",inline,omitempty"` CompiledWorkflow *workflows.Workflow `yaml:"-" json:"-" jsonschema:"-"` diff --git a/v2/pkg/workflows/workflows.go b/v2/pkg/workflows/workflows.go index caae63a6..183093fc 100644 --- a/v2/pkg/workflows/workflows.go +++ b/v2/pkg/workflows/workflows.go @@ -4,7 +4,8 @@ import "github.com/projectdiscovery/nuclei/v2/pkg/protocols" // Workflow is a workflow to execute with chained requests, etc. type Workflow struct { - // Workflows is a yaml based workflow declaration code. + // description: | + // Workflows is a list of workflows to execute for a template. Workflows []*WorkflowTemplate `yaml:"workflows,omitempty"` Options *protocols.ExecuterOptions @@ -12,13 +13,22 @@ type Workflow struct { // WorkflowTemplate is a template to be ran as part of a workflow type WorkflowTemplate struct { - // Template is the template to run + // description: | + // Template is a single template or directory to execute as part of workflow. + // examples: + // - name: A single template + // value: "\"dns/worksites-detection.yaml\"" + // - name: A template directory + // value: "\"misconfigurations/aem\"" Template string `yaml:"template"` - // Tags to perform filtering of supplied templates on + // description: | + // Tags to run templates based on. Tags string `yaml:"tags"` - // Matchers perform name based matching to run subtemplates for a workflow. + // description: | + // Matchers perform name based matching to run subtemplates for a workflow. Matchers []*Matcher `yaml:"matchers"` - // Subtemplates are ran if the template matches. + // description: | + // Subtemplates are ran if the `template` field Template matches. Subtemplates []*WorkflowTemplate `yaml:"subtemplates"` // Executers perform the actual execution for the workflow template Executers []*ProtocolExecuterPair @@ -32,8 +42,10 @@ type ProtocolExecuterPair struct { // Matcher performs conditional matching on the workflow template results. type Matcher struct { - // Name is the name of the item to match. + // description: | + // Name is the name of the item to match. Name string `yaml:"name"` - // Subtemplates are ran if the name of matcher matches. + // description: | + // Subtemplates are ran if the name of matcher matches. Subtemplates []*WorkflowTemplate `yaml:"subtemplates"` }