diff --git a/v2/pkg/protocols/common/expressions/expressions.go b/v2/pkg/protocols/common/expressions/expressions.go index 7f27b88a3..5a4ba2f3a 100644 --- a/v2/pkg/protocols/common/expressions/expressions.go +++ b/v2/pkg/protocols/common/expressions/expressions.go @@ -18,6 +18,21 @@ var templateExpressionRegex = regexp.MustCompile(`(?m)\{\{[^}]+\}\}["'\)\}]*`) // The provided keys from finalValues will be used as variable names // for substitution inside the expression. func Evaluate(data string, base map[string]interface{}) (string, error) { + return evaluate(data, base) +} + +// EvaluateByte checks if the match contains a dynamic variable, for each +// found one we will check if it's an expression and can +// be compiled, it will be evaluated and the results will be returned. +// +// The provided keys from finalValues will be used as variable names +// for substitution inside the expression. +func EvaluateByte(data []byte, base map[string]interface{}) ([]byte, error) { + finalData, err := evaluate(string(data), base) + return []byte(finalData), err +} + +func evaluate(data string, base map[string]interface{}) (string, error) { data = replacer.Replace(data, base) dynamicValues := make(map[string]interface{}) @@ -37,30 +52,3 @@ func Evaluate(data string, base map[string]interface{}) (string, error) { // Replacer dynamic values if any in raw request and parse it return replacer.Replace(data, dynamicValues), nil } - -// EvaluateByte checks if the match contains a dynamic variable, for each -// found one we will check if it's an expression and can -// be compiled, it will be evaluated and the results will be returned. -// -// The provided keys from finalValues will be used as variable names -// for substitution inside the expression. -func EvaluateByte(data []byte, base map[string]interface{}) ([]byte, error) { - final := replacer.Replace(string(data), base) - - dynamicValues := make(map[string]interface{}) - for _, match := range templateExpressionRegex.FindAllString(final, -1) { - expr := generators.TrimDelimiters(match) - - compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expr, dsl.HelperFunctions()) - if err != nil { - continue - } - result, err := compiled.Evaluate(base) - if err != nil { - continue - } - dynamicValues[expr] = result - } - // Replacer dynamic values if any in raw request and parse it - return []byte(replacer.Replace(final, dynamicValues)), nil -} diff --git a/v2/pkg/protocols/common/generators/generators.go b/v2/pkg/protocols/common/generators/generators.go index dcca16f55..07c72d200 100644 --- a/v2/pkg/protocols/common/generators/generators.go +++ b/v2/pkg/protocols/common/generators/generators.go @@ -2,6 +2,8 @@ package generators +import "github.com/pkg/errors" + // Generator is the generator struct for generating payloads type Generator struct { Type Type @@ -12,8 +14,8 @@ type Generator struct { type Type int const ( - // Sniper replaces each variable with values at a time. - Sniper Type = iota + 1 + // Sniper replaces one iteration of the payload with a value. + BatteringRam Type = iota + 1 // PitchFork replaces variables with positional value from multiple wordlists PitchFork // ClusterBomb replaces variables with all possible combinations of values @@ -22,9 +24,9 @@ const ( // StringToType is a table for conversion of attack type from string. var StringToType = map[string]Type{ - "sniper": Sniper, - "pitchfork": PitchFork, - "clusterbomb": ClusterBomb, + "batteringram": BatteringRam, + "pitchfork": PitchFork, + "clusterbomb": ClusterBomb, } // New creates a new generator structure for payload generation @@ -41,6 +43,12 @@ func New(payloads map[string]interface{}, payloadType Type, templatePath string) generator.Type = payloadType generator.payloads = compiled + // Validate the sniper/batteringram payload set + if payloadType == BatteringRam { + if len(payloads) != 1 { + return nil, errors.New("sniper/batteringram must have single payload set") + } + } return generator, nil } @@ -87,7 +95,7 @@ func (i *Iterator) Remaining() int { func (i *Iterator) Total() int { count := 0 switch i.Type { - case Sniper: + case BatteringRam: for _, p := range i.payloads { count += len(p.values) } @@ -110,19 +118,19 @@ func (i *Iterator) Total() int { // Value returns the next value for an iterator func (i *Iterator) Value() (map[string]interface{}, bool) { switch i.Type { - case Sniper: - return i.sniperValue() + case BatteringRam: + return i.batteringRamValue() case PitchFork: return i.pitchforkValue() case ClusterBomb: return i.clusterbombValue() default: - return i.sniperValue() + return i.batteringRamValue() } } -// sniperValue returns a list of all payloads for the iterator -func (i *Iterator) sniperValue() (map[string]interface{}, bool) { +// batteringRamValue returns a list of all payloads for the iterator +func (i *Iterator) batteringRamValue() (map[string]interface{}, bool) { values := make(map[string]interface{}, 1) currentIndex := i.msbIterator @@ -132,7 +140,7 @@ func (i *Iterator) sniperValue() (map[string]interface{}, bool) { if i.msbIterator == len(i.payloads) { return nil, false } - return i.sniperValue() + return i.batteringRamValue() } values[payload.name] = payload.value() payload.incrementPosition() diff --git a/v2/pkg/protocols/common/generators/generators_test.go b/v2/pkg/protocols/common/generators/generators_test.go index a19f53114..de37ca62d 100644 --- a/v2/pkg/protocols/common/generators/generators_test.go +++ b/v2/pkg/protocols/common/generators/generators_test.go @@ -6,11 +6,10 @@ import ( "github.com/stretchr/testify/require" ) -func TestSniperGenerator(t *testing.T) { +func TestBatteringRamGenerator(t *testing.T) { usernames := []string{"admin", "password"} - moreUsernames := []string{"login", "test"} - generator, err := New(map[string]interface{}{"username": usernames, "aliases": moreUsernames}, Sniper, "") + generator, err := New(map[string]interface{}{"username": usernames}, BatteringRam, "") require.Nil(t, err, "could not create generator") iterator := generator.NewIterator() @@ -22,7 +21,7 @@ func TestSniperGenerator(t *testing.T) { } count++ } - require.Equal(t, len(usernames)+len(moreUsernames), count, "could not get correct sniper counts") + require.Equal(t, len(usernames), count, "could not get correct batteringram counts") } func TestPitchforkGenerator(t *testing.T) { diff --git a/v2/pkg/protocols/http/http.go b/v2/pkg/protocols/http/http.go index 5558e7035..201804c96 100644 --- a/v2/pkg/protocols/http/http.go +++ b/v2/pkg/protocols/http/http.go @@ -1,6 +1,7 @@ package http import ( + "fmt" "strings" "github.com/pkg/errors" @@ -225,9 +226,13 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error { if len(r.Payloads) > 0 { attackType := r.AttackType if attackType == "" { - attackType = "sniper" + attackType = "batteringram" + } + var ok bool + r.attackType, ok = generators.StringToType[attackType] + if !ok { + return fmt.Errorf("invalid attack type provided: %s", attackType) } - r.attackType = generators.StringToType[attackType] // Resolve payload paths if they are files. for name, payload := range r.Payloads { diff --git a/v2/pkg/protocols/network/network.go b/v2/pkg/protocols/network/network.go index 3ad431ed0..244041c5d 100644 --- a/v2/pkg/protocols/network/network.go +++ b/v2/pkg/protocols/network/network.go @@ -1,6 +1,7 @@ package network import ( + "fmt" "net" "strings" @@ -153,9 +154,13 @@ func (r *Request) Compile(options *protocols.ExecuterOptions) error { if len(r.Payloads) > 0 { attackType := r.AttackType if attackType == "" { - attackType = "sniper" + attackType = "batteringram" + } + var ok bool + r.attackType, ok = generators.StringToType[attackType] + if !ok { + return fmt.Errorf("invalid attack type provided: %s", attackType) } - r.attackType = generators.StringToType[attackType] // Resolve payload paths if they are files. for name, payload := range r.Payloads {