feat(ytt): add ytt files var + add vars from cli and config

This commit is contained in:
Alban Stourbe 2025-06-24 18:32:45 +02:00
parent 3eb3f66897
commit 248548e075
10 changed files with 98 additions and 7 deletions

View File

@ -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)

View 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"

View File

@ -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

View File

@ -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") @)

View 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

View File

@ -0,0 +1,3 @@
foo: tata
bar: foo
token: TOKEN-BEARER

View File

@ -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")
} }

View File

@ -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

View File

@ -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,
}, },
}) })
} }

View File

@ -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