Skip to content

Commit

Permalink
Merge pull request #6 from Buzz2d0/PR#5
Browse files Browse the repository at this point in the history
feat: add mix payload with url package
  • Loading branch information
ac0d3r authored May 13, 2022
2 parents 976a19b + 135a83d commit 1fa95f5
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 79 deletions.
89 changes: 10 additions & 79 deletions pkg/chrome/xss/dom/fuzz.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import (
"strings"

"github.com/gokitx/pkgs/random"
"github.com/gokitx/pkgs/urlx"

"github.com/Buzz2d0/xssfinder/pkg/mix"
)

type VulPoint struct {
Expand Down Expand Up @@ -55,86 +56,16 @@ func GenPocUrls(point VulPoint) ([]FuzzUrl, error) {
return nil, err
}

oriQuery := u.Query()
if len(oriQuery) != 0 {
for k := range oriQuery {
for _, pre := range fuzzPrefixes {
pre, rand := genRand(pre)
// append query
aq := urlx.CloneUrlValues(oriQuery)
aq.Set(k, pre+aq.Get(k))
u.RawQuery = aq.Encode()
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})

// replace query
rq := urlx.CloneUrlValues(oriQuery)
rq.Set(k, rq.Get(k)+pre)
u.RawQuery = rq.Encode()
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})
}
for _, suf := range fuzzSuffixes {
suf, rand := genRand(suf)
// append query
aq := urlx.CloneUrlValues(oriQuery)
aq.Set(k, aq.Get(k)+suf)
u.RawQuery = aq.Encode()
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})

// replace query
rq := urlx.CloneUrlValues(oriQuery)
rq.Set(k, suf)
u.RawQuery = rq.Encode()
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})
}
}
// 还原query
u.RawQuery = oriQuery.Encode()
prefixURLs := mix.Payloads(*u, fuzzPrefixes, []mix.Rule{mix.RuleAppendPrefix, mix.RuleReplace}, mix.DefaultScopes)
for _, u := range prefixURLs {
furl, rand := genRand(u.String())
payloads = append(payloads, FuzzUrl{Url: furl, Rand: rand})
}

hash := u.Fragment
if hash != "" {
for _, pre := range fuzzPrefixes {
pre, rand := genRand(pre)
// append fragment
u.Fragment = pre + hash
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})
// replace fragment
u.Fragment = pre
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})
}
for _, suf := range fuzzSuffixes {
suf, rand := genRand(suf)
// append fragment
u.Fragment = hash + suf
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})
// replace fragment
u.Fragment = suf
payloads = append(payloads, FuzzUrl{
Url: u.String(),
Rand: rand,
})
}
suffixURLs := mix.Payloads(*u, fuzzSuffixes, []mix.Rule{mix.RuleAppendSuffix, mix.RuleReplace}, mix.DefaultScopes)
for _, u := range suffixURLs {
furl, rand := genRand(u.String())
payloads = append(payloads, FuzzUrl{Url: furl, Rand: rand})
}

// TODO referrer
Expand Down
3 changes: 3 additions & 0 deletions pkg/chrome/xss/dom/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func TestGenPocUrls(t *testing.T) {
// Url: "http://localhost:8080/dom_test.html#12323",
})
logurls(urls)

t.Log(fuzzPrefixes)
t.Log(fuzzSuffixes)
}

func logurls(urls []FuzzUrl) {
Expand Down
149 changes: 149 additions & 0 deletions pkg/mix/mixpayloads.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Package mix used to mix payload with different rules and scopes
package mix

import (
"net/url"
"path"
"strings"

"github.com/gokitx/pkgs/urlx"
)

func Payloads(u url.URL, payloads []string, rules []Rule, scopes []Scope) []url.URL {
var urls []url.URL
for _, scope := range scopes {
switch scope {
case ScopeQuery:
urls = append(urls, mixQuery(u, payloads, rules)...)
case ScopePath:
urls = append(urls, mixPath(u, payloads, rules)...)
case ScopeFragment:
urls = append(urls, mixFragment(u, payloads, rules)...)
}
}
return urls
}

func mixQuery(u url.URL, payloads []string, rules []Rule) []url.URL {
if len(u.Query()) == 0 {
return nil
}
baseQuery := u.Query()
urls := make([]url.URL, len(payloads)*len(rules)*len(baseQuery))

var index int
for _, payload := range payloads {
for key := range baseQuery {
for _, rule := range rules {
u.RawQuery = generateQueryWithRule(
urlx.CloneUrlValues(baseQuery),
key, payload, rule,
).Encode()
urls[index] = u
index++
}
}
}
return urls
}

func generateQueryWithRule(query url.Values, key, payload string, rule Rule) url.Values {
switch rule {
case RuleAppendPrefix:
query.Set(key, payload+query.Get(key))
return query
case RuleAppendSuffix:
query.Set(key, query.Get(key)+payload)
return query
case RuleReplace:
query.Set(key, payload)
return query
}
return query
}

func mixPath(u url.URL, payloads []string, rules []Rule) []url.URL {
var urls []url.URL
paths := strings.Split(u.Path, "/")
if len(paths) <= 1 {
return nil
}
for _, payload := range payloads {
for index := range paths {
for _, rule := range rules {
if paths[index] == "" {
continue
}
brefore := paths[index]
paths[index] = generateStrWithRule(brefore, payload, rule)
u.Path = path.Join(paths...)
paths[index] = brefore
urls = append(urls, u)
}
}
}
return urls
}

func generateStrWithRule(old, payload string, rule Rule) string {
switch rule {
case RuleAppendPrefix:
return payload + old
case RuleAppendSuffix:
return old + payload
case RuleReplace:
return payload
}
return old
}

func mixFragment(u url.URL, payloads []string, rules []Rule) []url.URL {
var urls []url.URL
if u.Fragment == "" {
return nil
}
fragment := u.Fragment
for _, payload := range payloads {
for _, rule := range rules {
u.Fragment = generateStrWithRule(fragment, payload, rule)
urls = append(urls, u)
}
}
return urls
}

// mixFilter decides whether a payload or url is allowed to be mixed or not.
// TODO: filter numeric or string types
type mixFilter int

const (
FilterNumeric mixFilter = iota + 1
FilterString
FilterIP
FilterDomain
FilterURI
FilterEmail
)

type Rule int

const (
// RuleAppendPrefix appends the payload to the beginning of the string
RuleAppendPrefix Rule = iota + 1
// RuleAppendSuffix appends the payload to the end of the string
RuleAppendSuffix
// RuleReplace replaces the string with the payload
RuleReplace
)

var DefaultMixRules = []Rule{RuleAppendPrefix, RuleAppendSuffix, RuleReplace}

type Scope int

const (
ScopeQuery Scope = iota + 1
ScopePath
ScopeFragment
)

var DefaultScopes = []Scope{ScopeQuery, ScopeFragment}
94 changes: 94 additions & 0 deletions pkg/mix/mixpayloads_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package mix

import (
"fmt"
"net/url"
"strings"
"testing"
)

var urlTestCases = []struct {
urlOBJ url.URL
}{
{
urlOBJ: url.URL{
Scheme: "https",
Host: "www.hackerone.com",
Path: "/pathA/pathB/pathC",
RawQuery: "queryA=111&queryB=222",
Fragment: "fragment",
},
},
}

var payloads = []string{
"moond4rk",
"buzz2d0",
}

func TestMixPayloads(t *testing.T) {
t.Parallel()
var urls []url.URL
for _, testCase := range urlTestCases {
urls = Payloads(testCase.urlOBJ, payloads, DefaultMixRules, DefaultScopes)
}
for _, v := range urls {
fmt.Println(v.String())
}
}

func TestPathMixPayloads(t *testing.T) {
t.Parallel()
var urls []url.URL
for _, testCase := range urlTestCases {
urls = Payloads(testCase.urlOBJ, payloads, DefaultMixRules, []Scope{ScopePath})
}
for _, v := range urls {
fmt.Println(v.String())
}
}

func TestMixQuery(t *testing.T) {
t.Parallel()
var urls []url.URL
var queryIndex int
for _, tc := range urlTestCases {
queryIndex += len(tc.urlOBJ.Query())
urls = append(urls, mixQuery(tc.urlOBJ, payloads, DefaultMixRules)...)
}
if len(urls) != len(urlTestCases)*len(payloads)*len(DefaultMixRules)*queryIndex {
t.Errorf("Expected %d urls, got %d", len(urlTestCases)*len(payloads)*len(DefaultMixRules)*queryIndex, len(urls))
}
}

func TestMixPath(t *testing.T) {
t.Parallel()
var urls []url.URL
pathIndex := 0
for _, tc := range urlTestCases {
for _, p := range strings.Split(tc.urlOBJ.Path, "/") {
if p != "" {
pathIndex++
}
}
urls = append(urls, mixPath(tc.urlOBJ, payloads, DefaultMixRules)...)
}
if len(urls) != len(urlTestCases)*len(payloads)*len(DefaultMixRules)*pathIndex {
t.Errorf("Expected %d urls, got %d", len(urlTestCases)*len(payloads)*len(DefaultMixRules)*pathIndex, len(urls))
}
}

func TestMixFragment(t *testing.T) {
t.Parallel()
var urls []url.URL
var index int
for _, tc := range urlTestCases {
if tc.urlOBJ.Fragment != "" {
index++
}
urls = append(urls, mixFragment(tc.urlOBJ, payloads, DefaultMixRules)...)
}
if len(urls) != len(urlTestCases)*len(payloads)*len(DefaultMixRules)*index {
t.Errorf("Expected %d urls, got %d", len(urlTestCases)*len(payloads)*len(DefaultMixRules), len(urls))
}
}

0 comments on commit 1fa95f5

Please sign in to comment.