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/pprof"
stringsutil "github.com/projectdiscovery/utils/strings"
"gopkg.in/yaml.v2"
"github.com/projectdiscovery/goflags"
"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.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.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",
@ -569,6 +571,7 @@ Additional documentation is available at: https://docs.nuclei.sh/getting-started
config.DefaultConfig.SetConfigDir(customConfigDir)
readFlagsConfig(flagSet)
}
if cfgFile != "" {
if !fileutil.FileExists(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 {
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 != "" {
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
// Only available for Yaml formats
VarsTextTemplating bool
// VarsFilePaths is the path to the file containing variables
VarsFilePaths []string
}
// Format is an interface implemented by all input formats

View File

@ -1,10 +1,9 @@
#@ load("@ytt:data", "data")
#@ load("@ytt:assert", "assert")
#@ load("@ytt:json", "json")
#@ def get_value(key, default=""):
#@ if hasattr(data.values, key):
#@ value = getattr(data.values, key)
#@ return str(value)
#@ return str(getattr(data.values, key))
#@ else:
#@ return default
#@ end
@ -17,10 +16,10 @@ request:
raw: |+
POST /users/3 HTTP/1.1
Host: ginandjuice.shop
Authorization: Bearer 3x4mpl3t0k3n
Authorization: Bearer (@= get_value("token") @)
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
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
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)}
dvs := mapToKeyValueSlice(j.opts.Variables)
finalInput, err = ytt(tpl, dvs)
finalInput, err = ytt(tpl, dvs, j.opts.VarsFilePaths)
if err != nil {
return errors.Wrap(err, "could not apply ytt templating")
}

View File

@ -12,7 +12,7 @@ import (
"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
templatingOptions := yttcmd.NewOptions()
@ -21,6 +21,11 @@ func ytt(tpl, dvs []string) (io.Reader, error) {
return nil, err
}
if len(varFiles) > 0 {
// Load vaarFiles into the templating options.
templatingOptions.DataValuesFlags.FromFiles = varFiles
}
// equivalent to `--data-value-yaml`
templatingOptions.DataValuesFlags.KVsFromYAML = dvs

View File

@ -117,6 +117,7 @@ func NewInputProvider(opts InputOptions) (InputProvider, error) {
SkipFormatValidation: opts.Options.SkipFormatValidation,
RequiredOnly: opts.Options.FormatUseRequiredOnly,
VarsTextTemplating: opts.Options.VarsTextTemplating,
VarsFilePaths: opts.Options.VarsFilePaths,
},
})
}

View File

@ -421,6 +421,8 @@ type Options struct {
SkipFormatValidation bool
// VarsTextTemplating is used to inject variables into yaml input files
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 int
// ProbeConcurrency is the number of concurrent http probes to run with httpx