2021-08-03 22:33:50 +05:30
//go:generate dstdocgen -path "" -structure Template -output templates_doc.go -package templates
2020-04-04 00:17:57 +05:30
package templates
import (
2021-12-16 11:09:38 +01:00
"encoding/json"
validate "github.com/go-playground/validator/v10"
2021-07-12 17:20:01 +03:00
"github.com/projectdiscovery/nuclei/v2/pkg/model"
2020-12-29 16:33:25 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols"
2022-03-31 00:54:35 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/common/variables"
2020-12-29 15:38:14 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/dns"
2021-01-01 15:28:28 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/file"
2021-02-21 16:31:34 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/headless"
2020-12-29 15:38:14 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/http"
2023-06-09 19:52:56 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/multi"
2020-12-30 14:54:20 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/network"
2021-11-03 02:34:48 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/ssl"
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/websocket"
2021-12-16 17:08:02 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/protocols/whois"
2021-11-03 17:18:35 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/templates/types"
2020-12-29 15:38:14 +05:30
"github.com/projectdiscovery/nuclei/v2/pkg/workflows"
2023-03-21 00:48:35 +05:30
errorutil "github.com/projectdiscovery/utils/errors"
2021-12-16 11:09:38 +01:00
"go.uber.org/multierr"
"gopkg.in/yaml.v2"
2020-04-04 00:17:57 +05:30
)
2021-08-04 14:20:48 +05:30
// Template is a YAML input file which defines all the requests and
// other metadata for a template.
2020-04-04 00:17:57 +05:30
type Template struct {
2021-07-27 16:03:56 +05:30
// description: |
2021-09-01 15:48:01 +05:30
// ID is the unique id for the template.
2021-07-27 16:03:56 +05:30
//
// #### Good IDs
//
2021-08-03 20:36:26 +05:30
// A good ID uniquely identifies what the requests in the template
2021-07-27 16:03:56 +05:30
// 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
2021-09-01 15:53:30 +05:30
// value: "\"CVE-2021-19520\""
2023-02-07 16:10:40 +08:00
ID string ` yaml:"id" json:"id" jsonschema:"title=id of the template,description=The Unique ID for the template,example=cve-2021-19520,pattern=^([a-zA-Z0-9]+[-_])*[a-zA-Z0-9]+$" `
2021-07-27 16:03:56 +05:30
// description: |
2021-08-19 16:51:02 +05:30
// Info contains metadata information about the template.
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleInfoStructure
2023-02-07 16:10:40 +08:00
Info model . Info ` yaml:"info" json:"info" jsonschema:"title=info for the template,description=Info contains metadata for the template" `
2021-07-27 16:03:56 +05:30
// description: |
2021-08-04 14:20:48 +05:30
// Requests contains the http request to make in the template.
2023-03-21 00:48:35 +05:30
// WARNING: 'requests' will be deprecated and will be removed in a future release. Please use 'http' instead.
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalHTTPRequest
2021-08-23 23:50:45 +05:30
RequestsHTTP [ ] * http . Request ` yaml:"requests,omitempty" json:"requests,omitempty" jsonschema:"title=http requests to make,description=HTTP requests to make for the template" `
2021-07-27 16:03:56 +05:30
// description: |
2023-03-21 00:48:35 +05:30
// HTTP contains the http request to make in the template.
// examples:
// - value: exampleNormalHTTPRequest
// RequestsWithHTTP is placeholder(internal) only, and should not be used instead use RequestsHTTP
2023-06-09 19:52:56 +05:30
// Deprecated: Use RequestsHTTP instead.
2023-03-21 00:48:35 +05:30
RequestsWithHTTP [ ] * http . Request ` yaml:"http,omitempty" json:"http,omitempty" jsonschema:"title=http requests to make,description=HTTP requests to make for the template" `
// description: |
2021-07-27 16:03:56 +05:30
// DNS contains the dns request to make in the template
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalDNSRequest
2021-08-23 23:50:45 +05:30
RequestsDNS [ ] * dns . Request ` yaml:"dns,omitempty" json:"dns,omitempty" jsonschema:"title=dns requests to make,description=DNS requests to make for the template" `
2021-07-27 16:03:56 +05:30
// description: |
// File contains the file request to make in the template
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalFileRequest
2021-08-23 23:50:45 +05:30
RequestsFile [ ] * file . Request ` yaml:"file,omitempty" json:"file,omitempty" jsonschema:"title=file requests to make,description=File requests to make for the template" `
2021-07-27 16:03:56 +05:30
// description: |
// Network contains the network request to make in the template
2023-03-21 00:48:35 +05:30
// WARNING: 'network' will be deprecated and will be removed in a future release. Please use 'tcp' instead.
2021-08-04 14:20:48 +05:30
// examples:
// - value: exampleNormalNetworkRequest
2021-08-23 23:50:45 +05:30
RequestsNetwork [ ] * network . Request ` yaml:"network,omitempty" json:"network,omitempty" jsonschema:"title=network requests to make,description=Network requests to make for the template" `
2021-07-27 16:03:56 +05:30
// description: |
2023-03-21 00:48:35 +05:30
// TCP contains the network request to make in the template
// examples:
// - value: exampleNormalNetworkRequest
// RequestsWithTCP is placeholder(internal) only, and should not be used instead use RequestsNetwork
2023-06-09 19:52:56 +05:30
// Deprecated: Use RequestsNetwork instead.
2023-03-21 00:48:35 +05:30
RequestsWithTCP [ ] * network . Request ` yaml:"tcp,omitempty" json:"tcp,omitempty" jsonschema:"title=network(tcp) requests to make,description=Network requests to make for the template" `
// description: |
2021-07-27 16:03:56 +05:30
// Headless contains the headless request to make in the template.
2021-08-23 23:50:45 +05:30
RequestsHeadless [ ] * headless . Request ` yaml:"headless,omitempty" json:"headless,omitempty" jsonschema:"title=headless requests to make,description=Headless requests to make for the template" `
2021-09-22 22:41:07 +05:30
// description: |
// SSL contains the SSL request to make in the template.
RequestsSSL [ ] * ssl . Request ` yaml:"ssl,omitempty" json:"ssl,omitempty" jsonschema:"title=ssl requests to make,description=SSL requests to make for the template" `
2021-09-27 18:02:49 +05:30
// description: |
// Websocket contains the Websocket request to make in the template.
RequestsWebsocket [ ] * websocket . Request ` yaml:"websocket,omitempty" json:"websocket,omitempty" jsonschema:"title=websocket requests to make,description=Websocket requests to make for the template" `
2021-02-04 01:09:29 +05:30
2021-12-16 17:08:02 +05:30
// description: |
// WHOIS contains the WHOIS request to make in the template.
RequestsWHOIS [ ] * whois . Request ` yaml:"whois,omitempty" json:"whois,omitempty" jsonschema:"title=whois requests to make,description=WHOIS requests to make for the template" `
2021-07-27 16:03:56 +05:30
// description: |
// Workflows is a yaml based workflow declaration code.
2021-08-23 23:50:45 +05:30
workflows . Workflow ` yaml:",inline,omitempty" jsonschema:"title=workflows to run,description=Workflows to run for the template" `
2021-05-01 18:28:24 +05:30
CompiledWorkflow * workflows . Workflow ` yaml:"-" json:"-" jsonschema:"-" `
2020-12-30 13:26:55 +05:30
2021-10-19 21:29:18 +05:30
// description: |
2021-10-19 22:28:48 +05:30
// Self Contained marks Requests for the template as self-contained
2023-02-07 16:10:40 +08:00
SelfContained bool ` yaml:"self-contained,omitempty" json:"self-contained,omitempty" jsonschema:"title=mark requests as self-contained,description=Mark Requests for the template as self-contained" `
2021-11-29 16:01:06 +05:30
// description: |
// Stop execution once first match is found
2023-02-07 16:10:40 +08:00
StopAtFirstMatch bool ` yaml:"stop-at-first-match,omitempty" json:"stop-at-first-match,omitempty" jsonschema:"title=stop at first match,description=Stop at first match for the template" `
2021-10-19 21:29:18 +05:30
2021-11-17 01:28:35 +01:00
// description: |
// Signature is the request signature method
// values:
// - "AWS"
2023-02-07 16:10:40 +08:00
Signature http . SignatureTypeHolder ` yaml:"signature,omitempty" json:"signature,omitempty" jsonschema:"title=signature is the http request signature method,description=Signature is the HTTP Request signature Method,enum=AWS" `
2021-10-19 21:29:18 +05:30
2022-03-31 00:54:35 +05:30
// description: |
// Variables contains any variables for the current request.
2023-02-07 16:10:40 +08:00
Variables variables . Variable ` yaml:"variables,omitempty" json:"variables,omitempty" jsonschema:"title=variables for the http request,description=Variables contains any variables for the current request" `
2022-03-31 00:54:35 +05:30
2023-05-25 18:32:35 +02:00
// description: |
// Constants contains any scalar costant for the current template
Constants map [ string ] interface { } ` yaml:"constants,omitempty" json:"constants,omitempty" jsonschema:"title=constant for the template,description=constants contains any constant for the template" `
2020-12-29 18:02:45 +05:30
// TotalRequests is the total number of requests for the template.
2021-05-01 18:28:24 +05:30
TotalRequests int ` yaml:"-" json:"-" `
2020-12-29 18:02:45 +05:30
// Executer is the actual template executor for running template requests
2021-05-01 18:28:24 +05:30
Executer protocols . Executer ` yaml:"-" json:"-" `
2021-06-05 23:00:59 +05:30
Path string ` yaml:"-" json:"-" `
2023-02-25 23:24:46 +01:00
// Verified defines if the template signature is digitally verified
Verified bool ` yaml:"-" json:"-" `
2021-10-27 15:53:04 +05:30
2023-06-09 19:52:56 +05:30
// MultiProtoRequest (Internal) contains multi protocol request if multiple protocols are used
MultiProtoRequest multi . Request ` yaml:"-" json:"-" `
2021-10-27 15:53:04 +05:30
}
// Type returns the type of the template
2021-11-25 16:57:43 +02:00
func ( template * Template ) Type ( ) types . ProtocolType {
2021-10-27 15:53:04 +05:30
switch {
2023-06-09 19:52:56 +05:30
case len ( template . MultiProtoRequest . Queue ) > 0 :
return types . MultiProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsDNS ) > 0 :
2021-11-03 17:18:35 +05:30
return types . DNSProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsFile ) > 0 :
2021-11-03 17:18:35 +05:30
return types . FileProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsHTTP ) > 0 :
2021-11-03 17:18:35 +05:30
return types . HTTPProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsHeadless ) > 0 :
2021-11-03 17:18:35 +05:30
return types . HeadlessProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsNetwork ) > 0 :
2021-11-03 17:18:35 +05:30
return types . NetworkProtocol
2021-11-25 16:57:43 +02:00
case len ( template . Workflow . Workflows ) > 0 :
2021-11-03 17:18:35 +05:30
return types . WorkflowProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsSSL ) > 0 :
2021-11-03 18:58:00 +05:30
return types . SSLProtocol
2021-11-25 16:57:43 +02:00
case len ( template . RequestsWebsocket ) > 0 :
2021-11-03 18:58:00 +05:30
return types . WebsocketProtocol
2021-12-16 17:08:02 +05:30
case len ( template . RequestsWHOIS ) > 0 :
return types . WHOISProtocol
2021-10-27 15:53:04 +05:30
default :
2021-11-03 17:18:35 +05:30
return types . InvalidProtocol
2021-10-27 15:53:04 +05:30
}
}
2021-12-16 11:09:38 +01:00
// MarshalYAML forces recursive struct validation during marshal operation
func ( template * Template ) MarshalYAML ( ) ( [ ] byte , error ) {
out , marshalErr := yaml . Marshal ( template )
errValidate := validate . New ( ) . Struct ( template )
return out , multierr . Append ( marshalErr , errValidate )
}
// MarshalYAML forces recursive struct validation after unmarshal operation
func ( template * Template ) UnmarshalYAML ( unmarshal func ( interface { } ) error ) error {
type Alias Template
alias := & Alias { }
err := unmarshal ( alias )
if err != nil {
return err
}
* template = Template ( * alias )
2023-03-21 00:48:35 +05:30
2023-05-04 01:43:41 +05:30
if len ( template . RequestsHTTP ) > 0 || len ( template . RequestsNetwork ) > 0 {
2023-06-09 02:28:40 +08:00
_ = deprecatedProtocolNameTemplates . Set ( template . ID , true )
2023-05-04 01:43:41 +05:30
}
2023-03-21 00:48:35 +05:30
if len ( alias . RequestsHTTP ) > 0 && len ( alias . RequestsWithHTTP ) > 0 {
return errorutil . New ( "use http or requests, both are not supported" ) . WithTag ( "invalid template" )
}
if len ( alias . RequestsNetwork ) > 0 && len ( alias . RequestsWithTCP ) > 0 {
return errorutil . New ( "use tcp or network, both are not supported" ) . WithTag ( "invalid template" )
}
if len ( alias . RequestsWithHTTP ) > 0 {
template . RequestsHTTP = alias . RequestsWithHTTP
}
if len ( alias . RequestsWithTCP ) > 0 {
template . RequestsNetwork = alias . RequestsWithTCP
}
2023-06-09 19:52:56 +05:30
err = validate . New ( ) . Struct ( template )
if err != nil {
return err
}
// check if the template contains a multi protocols
if template . isMultiProtocol ( ) {
var tempmap yaml . MapSlice
err = unmarshal ( & tempmap )
if err != nil {
return errorutil . NewWithErr ( err ) . Msgf ( "failed to unmarshal multi protocol template %s" , template . ID )
}
arr := [ ] string { }
for _ , v := range tempmap {
key , ok := v . Key . ( string )
if ! ok {
continue
}
arr = append ( arr , key )
}
// add protocols to the protocol stack (the idea is to preserve the order of the protocols)
template . addProtocolsToQueue ( arr ... )
}
return nil
}
// Internal function to create a protocol stack from a template if the template is a multi protocol template
func ( template * Template ) addProtocolsToQueue ( keys ... string ) {
for _ , key := range keys {
switch key {
case types . DNSProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsDNS ) ... )
case types . FileProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsFile ) ... )
case types . HTTPProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsHTTP ) ... )
case types . HeadlessProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsHeadless ) ... )
case types . NetworkProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsNetwork ) ... )
case types . SSLProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsSSL ) ... )
case types . WebsocketProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsWebsocket ) ... )
case types . WHOISProtocol . String ( ) :
template . MultiProtoRequest . Queue = append ( template . MultiProtoRequest . Queue , template . convertRequestToProtocolsRequest ( template . RequestsWHOIS ) ... )
}
}
}
// isMultiProtocol checks if the template is a multi protocol template
func ( template * Template ) isMultiProtocol ( ) bool {
counter := len ( template . RequestsDNS ) + len ( template . RequestsFile ) +
len ( template . RequestsHTTP ) + len ( template . RequestsHeadless ) +
len ( template . RequestsNetwork ) + len ( template . RequestsSSL ) +
len ( template . RequestsWebsocket ) + len ( template . RequestsWHOIS )
return counter > 1
2021-12-16 11:09:38 +01:00
}
// MarshalJSON forces recursive struct validation during marshal operation
func ( template * Template ) MarshalJSON ( ) ( [ ] byte , error ) {
out , marshalErr := json . Marshal ( template )
errValidate := validate . New ( ) . Struct ( template )
return out , multierr . Append ( marshalErr , errValidate )
}
// UnmarshalJSON forces recursive struct validation after unmarshal operation
func ( template * Template ) UnmarshalJSON ( data [ ] byte ) error {
type Alias Template
alias := & Alias { }
err := json . Unmarshal ( data , alias )
if err != nil {
return err
}
* template = Template ( * alias )
2023-06-09 19:52:56 +05:30
err = validate . New ( ) . Struct ( template )
if err != nil {
return err
}
// check if template contains multiple protocols
if template . isMultiProtocol ( ) {
var tempMap map [ string ] interface { }
err = json . Unmarshal ( data , & tempMap )
if err != nil {
return errorutil . NewWithErr ( err ) . Msgf ( "failed to unmarshal multi protocol template %s" , template . ID )
}
arr := [ ] string { }
for k := range tempMap {
arr = append ( arr , k )
}
template . addProtocolsToQueue ( arr ... )
}
return nil
2021-12-16 11:09:38 +01:00
}