Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions transform/transform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package transform

import (
crand "crypto/rand"
"math"
"math/big"
"math/rand"
"net/url"
"strings"
"testing"

"github.com/vulncheck-oss/go-exploit/output"
)

// ShuffleURLParameters will take a URL or path with URL parameters and extract the query parameters and cryptographically shuffle the parameters.
func ShuffleURLParameters(request string) string {
p, err := url.Parse(request)
if err != nil {
if !testing.Testing() {
output.PrintfFrameworkError("Could not parse URL: %s", err.Error())
}

return ""
}
// this feels a bit hacky, but net/url.Values is a map[string][]string which has some side effects:
// the map is "randomized" already but if there are multiple of the same parameters they will be
// returned together in order since the slice is not randomized. My solution to actually randomize
// the whole thing is to split the raw values into an []string and then shuffle that.

b, _ := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
r := rand.New(rand.NewSource(b.Int64()))
a := []string{}
for key, value := range p.Query() {
for _, v := range value {
a = append(a, key+`=`+v)
}
}
r.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
p.RawQuery = strings.Join(a, "&")

return p.String()
}
61 changes: 61 additions & 0 deletions transform/transform_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package transform

import (
"testing"
)

func TestShuffleParameters(t *testing.T) {
unsorted := "/?a=1&b=2&c=3&d=4&e=5&f=6&g=7&h=8&j=9&k=10&j=11&k=12&l=13&m=14&n=15&o=16&p=17&q=18&r=19&s=20&t=21&u=22&v=23&w=24&x=25&y=26&z=27&xxx=AAAA&xxx=BBBB&xxx=CCCC&xxx=DDDD"
triggered := 0
for range 10 {
s := ShuffleURLParameters(unsorted)
if s == unsorted {
t.Error("Parameters are in order... it's possible but unlikely. Go buy a lotto ticket", s)
triggered++
} else {
break
}
}
if triggered > 2 {
t.Fatal("Multiple sort generations is unlikely, something is wrong with randomness")
}
}

func TestShuffleParametersFullURL(t *testing.T) {
unsorted := "vulncheck.com/?a=1&b=2&c=3&d=4&e=5&f=6&g=7&h=8&j=9&k=10&j=11&k=12&l=13&m=14&n=15&o=16&p=17&q=18&r=19&s=20&t=21&u=22&v=23&w=24&x=25&y=26&z=27&xxx=AAAA&xxx=BBBB&xxx=CCCC&xxx=DDDD"
triggered := 0
for range 10 {
s := ShuffleURLParameters(unsorted)
if s == unsorted {
t.Error("Parameters are in order... it's possible but unlikely. Go buy a lotto ticket", s)
triggered++
} else {
break
}
}
if triggered > 2 {
t.Fatal("Multiple sort generations is unlikely, something is wrong with randomness")
}
unsorted = "https://vulncheck.com/?a=1&b=2&c=3&d=4&e=5&f=6&g=7&h=8&j=9&k=10&j=11&k=12&l=13&m=14&n=15&o=16&p=17&q=18&r=19&s=20&t=21&u=22&v=23&w=24&x=25&y=26&z=27&xxx=AAAA&xxx=BBBB&xxx=CCCC&xxx=DDDD"
triggered = 0
for range 10 {
s := ShuffleURLParameters(unsorted)
if s == unsorted {
t.Error("Parameters are in order... it's possible but unlikely. Go buy a lotto ticket", s)
triggered++
} else {
break
}
}
if triggered > 2 {
t.Fatal("Multiple sort generations is unlikely, something is wrong with randomness")
}
}

func TestShuffleParametersInvalid(t *testing.T) {
unsorted := "!:!!!!!!"
s := ShuffleURLParameters(unsorted)
if s != "" {
t.Fatal("Invalid URL should be empty", s)
}
}