Skip to content

gobusterfuzz: preserve percent-encoded sequences in wordlist words#647

Open
ChrisJr404 wants to merge 1 commit intoOJ:masterfrom
ChrisJr404:fix-issue-618-fuzz-percent-encoding
Open

gobusterfuzz: preserve percent-encoded sequences in wordlist words#647
ChrisJr404 wants to merge 1 commit intoOJ:masterfrom
ChrisJr404:fix-issue-618-fuzz-percent-encoding

Conversation

@ChrisJr404
Copy link
Copy Markdown

When a wordlist contains percent-encoded payloads (e.g. %2e%2e/etc/passwd for path-traversal fuzzing), gobuster fuzz currently double-encodes them on the wire. The substitution writes raw bytes into url.Path (which net/url treats as the decoded form), so the % characters get re-escaped to %25 by url.String() — producing requests like /cgi-bin/%252e%252e/etc/passwd that the target sees as the literal string %2e%2e, not ...

End-to-end repro before this PR (with the wordlist from #618):

$ printf '%%2e%%2e/opt/passwords\n' > wl.txt
$ ./gobuster fuzz -u 'http://127.0.0.1:18889/cgi-bin/FUZZ' -w wl.txt --no-progress -t 1
# Listener sees:  GET /cgi-bin/%252e%252e/opt/passwords

After this PR:

# Listener sees:  GET /cgi-bin/%2e%2e/opt/passwords    (matches what the user wrote, like curl --path-as-is)

The fix substitutes FUZZ in url.EscapedPath() instead of url.Path and re-assigns through a small helper (libgobuster.SetURLPathPreservingEncoding) that puts the encoded form in RawPath and the decoded form in Path. url.String() then emits RawPath verbatim, since it's a valid encoding of Path.

Plain wordlists (no %) are unaffected — EscapedPath() already returns the encoded form for plain paths, and the helper just round-trips it. Tests cover four cases: percent-encoded word, plain word, pre-existing %20 in the user URL, and invalid percent sequence (falls back to previous behavior).

The same fix could be applied to gobuster dir and gobuster vhost (which also concatenate raw bytes into url.Path), but the original issue only describes fuzz mode and I wanted to keep this PR minimal. Happy to extend in a follow-up if you'd like.

Fixes #618

When the user provides a wordlist that contains percent-encoded payloads
(e.g. %2e%2e/etc/passwd for path-traversal fuzzing), gobuster fuzz currently
double-encodes them on the wire because the FUZZ substitution writes raw
bytes into url.Path which is treated as the decoded form by net/url. The %
sign in the substituted Path then gets re-escaped to %25 by url.String(),
producing requests like /cgi-bin/%252e%252e/etc/passwd that the target
sees as the literal string "%2e%2e", not "..".

Substitute FUZZ in url.EscapedPath() (which preserves an already-set
RawPath) and re-assign through a small helper that puts the encoded form
in RawPath and the decoded form in Path. url.String() then uses RawPath
verbatim, matching what the user wrote and what curl --path-as-is or
wfuzz would send.

Adds a SetURLPathPreservingEncoding helper in libgobuster with table-driven
tests covering percent-encoded inputs, plain paths, paths with a
pre-existing encoded segment in the user URL, and inputs with an invalid
percent sequence (which falls back to the previous behavior).

Fixes OJ#618
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Automatic encoding of percent sign

1 participant