mirror of
https://github.com/projectdiscovery/nuclei.git
synced 2025-12-17 20:55:28 +00:00
feat(ytt): add ytt files var + add vars from cli and config
This commit is contained in:
parent
3eb3f66897
commit
248548e075
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/projectdiscovery/utils/env"
|
"github.com/projectdiscovery/utils/env"
|
||||||
_ "github.com/projectdiscovery/utils/pprof"
|
_ "github.com/projectdiscovery/utils/pprof"
|
||||||
stringsutil "github.com/projectdiscovery/utils/strings"
|
stringsutil "github.com/projectdiscovery/utils/strings"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/projectdiscovery/goflags"
|
"github.com/projectdiscovery/goflags"
|
||||||
"github.com/projectdiscovery/gologger"
|
"github.com/projectdiscovery/gologger"
|
||||||
@ -261,6 +262,7 @@ on extensive configurability, massive extensibility and ease of use.`)
|
|||||||
flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"),
|
flagSet.BoolVarP(&options.FormatUseRequiredOnly, "required-only", "ro", false, "use only required fields in input format when generating requests"),
|
||||||
flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"),
|
flagSet.BoolVarP(&options.SkipFormatValidation, "skip-format-validation", "sfv", false, "skip format validation (like missing vars) when parsing input file"),
|
||||||
flagSet.BoolVarP(&options.VarsTextTemplating, "vars-text-templating", "vtt", false, "enable text templating for vars in input file (only for yaml input mode)"),
|
flagSet.BoolVarP(&options.VarsTextTemplating, "vars-text-templating", "vtt", false, "enable text templating for vars in input file (only for yaml input mode)"),
|
||||||
|
flagSet.StringSliceVarP(&options.VarsFilePaths, "var-file-paths", "vfp", nil, "list of yaml file contained vars to inject into yaml input", goflags.CommaSeparatedStringSliceOptions),
|
||||||
)
|
)
|
||||||
|
|
||||||
flagSet.CreateGroup("templates", "Templates",
|
flagSet.CreateGroup("templates", "Templates",
|
||||||
@ -569,6 +571,7 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
|
|||||||
config.DefaultConfig.SetConfigDir(customConfigDir)
|
config.DefaultConfig.SetConfigDir(customConfigDir)
|
||||||
readFlagsConfig(flagSet)
|
readFlagsConfig(flagSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfgFile != "" {
|
if cfgFile != "" {
|
||||||
if !fileutil.FileExists(cfgFile) {
|
if !fileutil.FileExists(cfgFile) {
|
||||||
gologger.Fatal().Msgf("given config file '%s' does not exist", cfgFile)
|
gologger.Fatal().Msgf("given config file '%s' does not exist", cfgFile)
|
||||||
@ -577,6 +580,34 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
|
|||||||
if err := flagSet.MergeConfigFile(cfgFile); err != nil {
|
if err := flagSet.MergeConfigFile(cfgFile); err != nil {
|
||||||
gologger.Fatal().Msgf("Could not read config: %s\n", err)
|
gologger.Fatal().Msgf("Could not read config: %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !options.Vars.IsEmpty() {
|
||||||
|
// Maybe we should add vars to the config file as well?
|
||||||
|
file, err := os.Open(cfgFile)
|
||||||
|
if err != nil {
|
||||||
|
gologger.Fatal().Msgf("Could not open config file: %s\n", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
data := make(map[string]interface{})
|
||||||
|
err = yaml.NewDecoder(file).Decode(&data)
|
||||||
|
if err != nil {
|
||||||
|
gologger.Fatal().Msgf("Could not decode config file: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
variables := data["var"]
|
||||||
|
if variables != nil {
|
||||||
|
for _, value := range variables.([]interface{}) {
|
||||||
|
if strVal, ok := value.(string); ok {
|
||||||
|
options.Vars.Set(strVal)
|
||||||
|
} else {
|
||||||
|
gologger.Warning().Msgf("Skipping non-string variable in config: %#v", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gologger.Warning().Msgf("No 'var' section found in config file: %s", cfgFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if options.NewTemplatesDirectory != "" {
|
if options.NewTemplatesDirectory != "" {
|
||||||
config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory)
|
config.DefaultConfig.SetTemplatesDir(options.NewTemplatesDirectory)
|
||||||
|
|||||||
38
integration_tests/fuzz/fuzz-body.yaml
Normal file
38
integration_tests/fuzz/fuzz-body.yaml
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
id: fuzz-body
|
||||||
|
|
||||||
|
info:
|
||||||
|
name: fuzzing error sqli payloads in http req body
|
||||||
|
author: pdteam
|
||||||
|
severity: info
|
||||||
|
description: |
|
||||||
|
This template attempts to find SQL injection vulnerabilities by fuzzing http body
|
||||||
|
It automatically handles and parses json,xml,multipart form and x-www-form-urlencoded data
|
||||||
|
and performs fuzzing on the value of every key
|
||||||
|
|
||||||
|
http:
|
||||||
|
- pre-condition:
|
||||||
|
- type: dsl
|
||||||
|
dsl:
|
||||||
|
- method != "GET"
|
||||||
|
- method != "HEAD"
|
||||||
|
condition: and
|
||||||
|
|
||||||
|
payloads:
|
||||||
|
injection:
|
||||||
|
- "'"
|
||||||
|
- "\""
|
||||||
|
- ";"
|
||||||
|
|
||||||
|
fuzzing:
|
||||||
|
- part: body
|
||||||
|
type: postfix
|
||||||
|
mode: single
|
||||||
|
fuzz:
|
||||||
|
- '{{injection}}'
|
||||||
|
|
||||||
|
stop-at-first-match: true
|
||||||
|
matchers:
|
||||||
|
- type: word
|
||||||
|
words:
|
||||||
|
- "unrecognized token:"
|
||||||
|
- "null"
|
||||||
@ -32,6 +32,8 @@ type InputFormatOptions struct {
|
|||||||
// this is used for text templating of variables based on carvel ytt
|
// this is used for text templating of variables based on carvel ytt
|
||||||
// Only available for Yaml formats
|
// Only available for Yaml formats
|
||||||
VarsTextTemplating bool
|
VarsTextTemplating bool
|
||||||
|
// VarsFilePaths is the path to the file containing variables
|
||||||
|
VarsFilePaths []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format is an interface implemented by all input formats
|
// Format is an interface implemented by all input formats
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
#@ load("@ytt:data", "data")
|
#@ load("@ytt:data", "data")
|
||||||
#@ load("@ytt:assert", "assert")
|
#@ load("@ytt:json", "json")
|
||||||
|
|
||||||
#@ def get_value(key, default=""):
|
#@ def get_value(key, default=""):
|
||||||
#@ if hasattr(data.values, key):
|
#@ if hasattr(data.values, key):
|
||||||
#@ value = getattr(data.values, key)
|
#@ return str(getattr(data.values, key))
|
||||||
#@ return str(value)
|
|
||||||
#@ else:
|
#@ else:
|
||||||
#@ return default
|
#@ return default
|
||||||
#@ end
|
#@ end
|
||||||
@ -17,10 +16,10 @@ request:
|
|||||||
raw: |+
|
raw: |+
|
||||||
POST /users/3 HTTP/1.1
|
POST /users/3 HTTP/1.1
|
||||||
Host: ginandjuice.shop
|
Host: ginandjuice.shop
|
||||||
Authorization: Bearer 3x4mpl3t0k3n
|
Authorization: Bearer (@= get_value("token") @)
|
||||||
Accept-Encoding: gzip
|
Accept-Encoding: gzip
|
||||||
Content-Type: application/x-www-form-urlencoded
|
Content-Type: application/x-www-form-urlencoded
|
||||||
Connection: close
|
Connection: close
|
||||||
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
|
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
|
||||||
|
|
||||||
foo=(@= get_value("foo") @)&bar=(@= get_value("bar") @)
|
foo=(@= get_value("foo") @)&bar=(@= get_value("bar") @)&debug=(@= get_value("debug", "false") @)
|
||||||
10
pkg/input/formats/testdata/ytt/ytt-profile.yaml
vendored
Normal file
10
pkg/input/formats/testdata/ytt/ytt-profile.yaml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
list: pkg/input/formats/testdata/ytt/ginandjuice.ytt.yaml
|
||||||
|
input-mode: yaml
|
||||||
|
templates:
|
||||||
|
- integration_tests/fuzz/fuzz-body.yaml
|
||||||
|
var:
|
||||||
|
- debug=true
|
||||||
|
vars-text-templating: true
|
||||||
|
var-file-paths:
|
||||||
|
- pkg/input/formats/testdata/ytt/ytt-vars.yaml
|
||||||
|
dast: true
|
||||||
3
pkg/input/formats/testdata/ytt/ytt-vars.yaml
vendored
Normal file
3
pkg/input/formats/testdata/ytt/ytt-vars.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
foo: tata
|
||||||
|
bar: foo
|
||||||
|
token: TOKEN-BEARER
|
||||||
@ -56,7 +56,7 @@ func (j *YamlMultiDocFormat) Parse(input io.Reader, resultsCb formats.ParseReqRe
|
|||||||
}
|
}
|
||||||
tpl := []string{string(data)}
|
tpl := []string{string(data)}
|
||||||
dvs := mapToKeyValueSlice(j.opts.Variables)
|
dvs := mapToKeyValueSlice(j.opts.Variables)
|
||||||
finalInput, err = ytt(tpl, dvs)
|
finalInput, err = ytt(tpl, dvs, j.opts.VarsFilePaths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "could not apply ytt templating")
|
return errors.Wrap(err, "could not apply ytt templating")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ytt(tpl, dvs []string) (io.Reader, error) {
|
func ytt(tpl, dvs []string, varFiles []string) (io.Reader, error) {
|
||||||
// create and invoke ytt "template" command
|
// create and invoke ytt "template" command
|
||||||
templatingOptions := yttcmd.NewOptions()
|
templatingOptions := yttcmd.NewOptions()
|
||||||
|
|
||||||
@ -21,6 +21,11 @@ func ytt(tpl, dvs []string) (io.Reader, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(varFiles) > 0 {
|
||||||
|
// Load vaarFiles into the templating options.
|
||||||
|
templatingOptions.DataValuesFlags.FromFiles = varFiles
|
||||||
|
}
|
||||||
|
|
||||||
// equivalent to `--data-value-yaml`
|
// equivalent to `--data-value-yaml`
|
||||||
templatingOptions.DataValuesFlags.KVsFromYAML = dvs
|
templatingOptions.DataValuesFlags.KVsFromYAML = dvs
|
||||||
|
|
||||||
|
|||||||
@ -117,6 +117,7 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
|
|||||||
SkipFormatValidation: opts.Options.SkipFormatValidation,
|
SkipFormatValidation: opts.Options.SkipFormatValidation,
|
||||||
RequiredOnly: opts.Options.FormatUseRequiredOnly,
|
RequiredOnly: opts.Options.FormatUseRequiredOnly,
|
||||||
VarsTextTemplating: opts.Options.VarsTextTemplating,
|
VarsTextTemplating: opts.Options.VarsTextTemplating,
|
||||||
|
VarsFilePaths: opts.Options.VarsFilePaths,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -421,6 +421,8 @@ type Options struct {
|
|||||||
SkipFormatValidation bool
|
SkipFormatValidation bool
|
||||||
// VarsTextTemplating is used to inject variables into yaml input files
|
// VarsTextTemplating is used to inject variables into yaml input files
|
||||||
VarsTextTemplating bool
|
VarsTextTemplating bool
|
||||||
|
// VarsFilePaths is used to inject variables into yaml input files from a file
|
||||||
|
VarsFilePaths goflags.StringSlice
|
||||||
// PayloadConcurrency is the number of concurrent payloads to run per template
|
// PayloadConcurrency is the number of concurrent payloads to run per template
|
||||||
PayloadConcurrency int
|
PayloadConcurrency int
|
||||||
// ProbeConcurrency is the number of concurrent http probes to run with httpx
|
// ProbeConcurrency is the number of concurrent http probes to run with httpx
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user