Path: blob/dev/pkg/protocols/headless/headless.go
2070 views
package headless12import (3"github.com/pkg/errors"45"github.com/projectdiscovery/nuclei/v3/pkg/fuzz"6useragent "github.com/projectdiscovery/nuclei/v3/pkg/model/types/userAgent"7"github.com/projectdiscovery/nuclei/v3/pkg/operators"8"github.com/projectdiscovery/nuclei/v3/pkg/protocols"9"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/generators"10"github.com/projectdiscovery/nuclei/v3/pkg/protocols/headless/engine"11uagent "github.com/projectdiscovery/useragent"12fileutil "github.com/projectdiscovery/utils/file"13)1415// Request contains a Headless protocol request to be made from a template16type Request struct {17// ID is the optional id of the request18ID string `yaml:"id,omitempty" json:"id,omitempty" jsonschema:"title=id of the request,description=Optional ID of the headless request"`1920// description: |21// Attack is the type of payload combinations to perform.22//23// Batteringram is inserts the same payload into all defined payload positions at once, pitchfork combines multiple payload sets and clusterbomb generates24// permutations and combinations for all payloads.25AttackType 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"`26// description: |27// Payloads contains any payloads for the current request.28//29// Payloads support both key-values combinations where a list30// of payloads is provided, or optionally a single file can also31// be provided as payload which will be read on run-time.32Payloads map[string]interface{} `yaml:"payloads,omitempty" json:"payloads,omitempty" jsonschema:"title=payloads for the headless request,description=Payloads contains any payloads for the current request"`3334// description: |35// Steps is the list of actions to run for headless request36Steps []*engine.Action `yaml:"steps,omitempty" json:"steps,omitempty" jsonschema:"title=list of actions for headless request,description=List of actions to run for headless request"`3738// descriptions: |39// User-Agent is the type of user-agent to use for the request.40UserAgent useragent.UserAgentHolder `yaml:"user_agent,omitempty" json:"user_agent,omitempty" jsonschema:"title=user agent for the headless request,description=User agent for the headless request"`4142// description: |43// If UserAgent is set to custom, customUserAgent is the custom user-agent to use for the request.44CustomUserAgent string `yaml:"custom_user_agent,omitempty" json:"custom_user_agent,omitempty" jsonschema:"title=custom user agent for the headless request,description=Custom user agent for the headless request"`45compiledUserAgent string46// description: |47// StopAtFirstMatch stops the execution of the requests and template as soon as a match is found.48StopAtFirstMatch bool `yaml:"stop-at-first-match,omitempty" json:"stop-at-first-match,omitempty" jsonschema:"title=stop at first match,description=Stop the execution after a match is found"`4950// Operators for the current request go here.51operators.Operators `yaml:",inline,omitempty" json:",inline,omitempty"`52CompiledOperators *operators.Operators `yaml:"-" json:"-"`5354// cache any variables that may be needed for operation.55options *protocols.ExecutorOptions56generator *generators.PayloadGenerator5758// Fuzzing describes schema to fuzz headless requests59Fuzzing []*fuzz.Rule `yaml:"fuzzing,omitempty" json:"fuzzing,omitempty" jsonschema:"title=fuzzin rules for http fuzzing,description=Fuzzing describes rule schema to fuzz headless requests"`6061// description: |62// SelfContained specifies if the request is self-contained.63SelfContained bool `yaml:"-" json:"-"`6465// description: |66// CookieReuse is an optional setting that enables cookie reuse67// Deprecated: This is default now. Use disable-cookie to disable cookie reuse. cookie-reuse will be removed in future releases.68CookieReuse bool `yaml:"cookie-reuse,omitempty" json:"cookie-reuse,omitempty" jsonschema:"title=optional cookie reuse enable,description=Optional setting that enables cookie reuse"`6970// description: |71// DisableCookie is an optional setting that disables cookie reuse72DisableCookie bool `yaml:"disable-cookie,omitempty" json:"disable-cookie,omitempty" jsonschema:"title=optional disable cookie reuse,description=Optional setting that disables cookie reuse"`73}7475// RequestPartDefinitions contains a mapping of request part definitions and their76// description. Multiple definitions are separated by commas.77// Definitions not having a name (generated on runtime) are prefixed & suffixed by <>.78var RequestPartDefinitions = map[string]string{79"template-id": "ID of the template executed",80"template-info": "Info Block of the template executed",81"template-path": "Path of the template executed",82"host": "Host is the input to the template",83"matched": "Matched is the input which was matched upon",84"type": "Type is the type of request made",85"req": "Headless request made from the client",86"resp,body,data": "Headless response received from client (default)",87}8889// Step is a headless protocol request step.90type Step struct {91// Action is the headless action to execute for the script92Action string `yaml:"action"`93}9495// GetID returns the unique ID of the request if any.96func (request *Request) GetID() string {97return request.ID98}99100// Compile compiles the protocol request for further execution.101func (request *Request) Compile(options *protocols.ExecutorOptions) error {102request.options = options103104// TODO: logic similar to network + http => probably can be refactored105// Resolve payload paths from vars if they exists106for name, payload := range options.Options.Vars.AsMap() {107payloadStr, ok := payload.(string)108// check if inputs contains the payload109if ok && fileutil.FileExists(payloadStr) {110if request.Payloads == nil {111request.Payloads = make(map[string]interface{})112}113request.Payloads[name] = payloadStr114}115}116117if len(request.Payloads) > 0 {118var err error119request.generator, err = generators.New(request.Payloads, request.AttackType.Value, options.TemplatePath, options.Catalog, options.Options.AttackType, request.options.Options)120if err != nil {121return errors.Wrap(err, "could not parse payloads")122}123}124125// Compile User-Agent126switch request.UserAgent.Value {127case useragent.Off:128request.compiledUserAgent = " "129case useragent.Default:130request.compiledUserAgent = ""131case useragent.Custom:132if request.CustomUserAgent == "" {133return errors.New("please set custom_user_agent in the template")134}135request.compiledUserAgent = request.CustomUserAgent136case useragent.Random:137userAgent := uagent.PickRandom()138request.compiledUserAgent = userAgent.Raw139}140141if len(request.Matchers) > 0 || len(request.Extractors) > 0 {142compiled := &request.Operators143compiled.ExcludeMatchers = options.ExcludeMatchers144compiled.TemplateID = options.TemplateID145if err := compiled.Compile(); err != nil {146return errors.Wrap(err, "could not compile operators")147}148request.CompiledOperators = compiled149}150151if len(request.Fuzzing) > 0 {152for _, rule := range request.Fuzzing {153if fuzzingMode := options.Options.FuzzingMode; fuzzingMode != "" {154rule.Mode = fuzzingMode155}156if fuzzingType := options.Options.FuzzingType; fuzzingType != "" {157rule.Type = fuzzingType158}159if err := rule.Compile(request.generator, request.options); err != nil {160return errors.Wrap(err, "could not compile fuzzing rule")161}162}163}164165return nil166}167168// Requests returns the total number of requests the YAML rule will perform169func (request *Request) Requests() int {170return 1171}172173// UpdateOptions replaces this request's options with a new copy174func (r *Request) UpdateOptions(opts *protocols.ExecutorOptions) {175r.options.ApplyNewEngineOptions(opts)176}177178179