web hacking

Wfuzz: Web fuzzing of directories, parameters, headers, and VHosts

Wfuzz: Web fuzzing of directories, parameters, headers, and VHosts

Wfuzz for web fuzzing: directory and parameter commands, VHost discovery, headers, cookies, filters, SecLists, encoders, and WAF bypass techniques.

  • Posted on 2026-08-16
  • Reading time: 9 min

Wfuzz: Guide to Web Fuzzing, Parameter Fuzzing, Directory and Brute Force #

wfuzz is a Python web fuzzer that replaces the keyword FUZZ with every wordlist entry anywhere in an HTTP request — URLs, GET/POST parameters, headers, cookies, JSON bodies. While gobuster and feroxbuster are optimized for brute force directory entry, wfuzz is completely genericYou can fuze any field, with multiple simultaneous wordlists and built-in encoders. This makes it the perfect tool when you need to test for injection points, hidden parameters, vhosts, or any non-standard scenario.

Prerequisites: wordlist (install with SecLists ) and Burp Suite as a proxy to inspect requests.


What is Wfuzz? #

Wfuzz is an open source web fuzzer written in Python that allows you to replace a position FUZZ within an HTTP request with the values ​​of a wordlist. It can be used on directories and files, GET/POST parameters, headers, cookies, virtual hosts, and generally on any HTTP input point reachable in a request.

How does Wfuzz work? #

text
Wordlist
   ↓
Ogni entry sostituisce FUZZ nella request
   ↓
Request inviata al target
   ↓
Response ricevuta
   ↓
Filtri (--hc, --sc, --hl, --hw, --hh, --hs, --ss)
   ↓
Risultati interessanti

In practice: write a request with FUZZ Instead of the value you want to test, you attach a wordlist, and wfuzz sends a request for each row in the wordlist. Filters are used to filter out the noise (thousands of identical/irrelevant answers) and highlight only what matters.


Wfuzz vs ffuf vs feroxbuster vs gobuster #

Before you begin: These tools do similar things, but with different strengths. Choose based on the task at hand.

toolLanguageSwift Multi-fuzzingencodersRecursionWhen to use it
wfuzzPython★★★✅ FUZZ+FUZ2Z+FUZ3Z✅ manyManual -RMaximum flexibility, parameter fuzzing, encoders
fufGo★ ★ ★ ★ ★✅ -w w1:K1 -w w2:K2BaseCars --recursionFast directory fuzzing, everyday use
feroxbusterPeace★ ★ ★ ★ ★❌❌Car, aggressiveDeep recursion, maximum speed
gobusterGo★ ★ ★ ★❌❌❌Simplicity, subdomain DNS, S3 bucket
dirbusterJava★★❌❌✅ GUILegacy, GUI for those who prefer visual

Is wfuzz better than ffuf? Not at all: ffuf is generally preferable for fast directory fuzzing, while wfuzz is more interesting when you need multi-position, parameter fuzzing, header/cookie fuzzing, and encoders—the others just can't do that.

Wfuzz vs Burp Intruder? Burp Intruder is more convenient for manual, iterative fuzzing within the Burp workflow (with token/CSRF management via macros). Wfuzz is better suited when you want to automate from the command line, integrate it into scripts, or launch mass scans without going through the UI.

If you have to…Usa
Quick Directoryfuf
Parameter fuzzingwfuzz
Multi-positionwfuzz
Encoderwfuzz
Aggressive recursionferoxbuster
Simple DNS/VHostgobuster

Installation #

Kali already includes it. If it's missing:

bash
sudo apt install wfuzz -y
# oppure
pip3 install wfuzz

The default wordlists are in /usr/share/wfuzz/wordlist/. For serious fuzzing use SecLists in /usr/share/seclists/.


Basic syntax and mandatory filters #

bash
wfuzz [opzioni] -w WORDLIST URL_CON_FUZZ

The options you will always use:

FlagWhat does he do
-w wordlistSpecify wordlist (repeat for multi-position)
-cColored output
-t NThread (default 10)
--hc NHide responses with status code N — always use it
--sc NShow only responses with status code N
--hl NHide answers with N lines
--hw NHide answers with N words
--hh NHide responses with exactly N characters
--hs "stringa"Hide responses that contain that string
--ss "stringa"Show only responses that contain that string
-d "data"Body POST
-H "Header: val"Custom HTTP headers
-b "cookie=val"Cookie
-p proxyProxy (Burp Suite: 127.0.0.1:8080)
-f file,formatoSave output (json, csv, html)

Without --hc 404, wfuzz prints every response, and the output is unusable. This is the first filter you should always add. The exact behavior of some flags (delay, recursion) may vary between versions of wfuzz. Always check wfuzz -h on your build before blindly relying on these commands in a real-world engagement.


Wfuzz for directory and file fuzzing #

bash
# Base — il punto di partenza su qualsiasi target
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/common.txt \
  --hc 404 http://target.com/FUZZ
text
ID    Response   Lines    Word    Chars    Payload
================================================================
00042:  C=200     12 L     45 W    512 Ch    "admin"
00137:  C=301      9 L     28 W    319 Ch    "backup"
00891:  C=403      7 L     22 W    285 Ch    "config"

C=301 It's a redirect — follow it with your browser. C=403 It exists but is forbidden — still interesting, often bypassable.

bash
# Fuzza con estensione specifica
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/common.txt \
  --hc 404 http://target.com/FUZZ.php

# Fuzza path + estensione contemporaneamente (FUZZ + FUZ2Z)
wfuzz -c \
  -w /usr/share/seclists/Discovery/Web-Content/common.txt \
  -w /usr/share/seclists/Fuzzing/Extensions/Web-Extensions.fuzz.txt \
  --hc 404 "http://target.com/FUZZ.FUZ2Z"

# Ricorsivo (depth 2) — dopo aver trovato /admin, entra dentro
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt \
  --hc 404 -R 2 http://target.com/FUZZ/

Recommended wordlists for directories:

WordlistEntryWhen
common.txt4.723Initial quick win
directory-list-2.3-medium.txt220.000Standard Assessment
directory-list-2.3-big.txt1.27MIn-depth assessment
api/api-endpoints.txt13.000REST API

Typical mistake: throwing it right away directory-list-2.3-big.txt on target in production. Start with common.txt, then scale. With 1.27 million highly threaded requests, you can trigger rate limits or accidental DoS.


Wfuzz for GET and POST parameter fuzzing #

Wfuzz excels where ffuf and feroxbuster don't easily reach: uncovering hidden parameters and testing injection points on any field.

GET parameter discovery #

bash
# Fuzza il nome del parametro — cosa accetta questa pagina?
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
  --hh 0 "http://target.com/search.php?FUZZ=test"
text
00234:  C=200    45 L    120 W   1823 Ch    "query"
00891:  C=200    12 L     34 W    412 Ch    "debug"

--hh 0 Hides empty responses (parameter ignored by the server). Everything else has a different response → valid parameter.

IDOR and injection testing #

bash
# IDOR — testa accesso a risorse di altri utenti
wfuzz -c -z range,1-1000 --hc 404,403 \
  "http://target.com/api/user/FUZZ/profile"

# Testa injection SQL su parametro id (vedi la guida a SQL injection)
wfuzz -c -w /usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt \
  --hs "not found" \
  "http://target.com/item.php?id=FUZZ"

POST parameter fuzzing #

bash
# Login form — fuzza la password con username fisso
wfuzz -c -w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
  --hc 302 \
  -d "username=admin&password=FUZZ" \
  http://target.com/login.php

--hc 302 Hides failure redirects. When a 200 response appears, password found.

bash
# Se il server risponde sempre 200 — filtra per testo di errore
wfuzz -c -w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
  --hs "Invalid credentials" \
  -d "username=admin&password=FUZZ" \
  http://target.com/login.php

JSON parameter fuzzing #

bash
# API JSON POST
wfuzz -c -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer TOKEN" \
  -d '{"action":"FUZZ"}' \
  --hc 404,400 http://target.com/api/v1

Typical JSON API error: forgetting -H "Content-Type: application/json"Without it, almost all APIs return 400, making it impossible to distinguish valid results.


Wfuzz for virtual host and subdomain discovery #

A single IP can host dozens of vhosts — admin panel, staging, internal APIs — that are not reachable from the main URL.

bash
# Misura prima la dimensione della risposta di default
curl -s http://TARGET_IP/ | wc -c
# Output: 1423

# Virtual host discovery — nascondi baseline, mostra tutto il resto
wfuzz -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  -H "Host: FUZZ.target.com" \
  --hh 1423 http://TARGET_IP/
text
00089:  C=200   312 L   1024 W   18432 Ch   "admin"
00234:  C=200    45 L    120 W    4821 Ch   "staging"
bash
# Subdomain fuzzing (DNS)
wfuzz -c -Z \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  http://FUZZ.target.com/

-Z ignore connection error (subdomain that does not exist → timeout, fuzzer does not crash).


bash
# Fuzza X-Forwarded-For — bypass IP whitelist su admin panel
wfuzz -c -w /usr/share/seclists/Fuzzing/IP-addresses.txt \
  -H "X-Forwarded-For: FUZZ" \
  --sc 200 http://target.com/admin/

# Fuzza User-Agent — aggira blocchi anti-bot
wfuzz -c -w /usr/share/seclists/Fuzzing/User-Agents/UserAgents.fuzz.txt \
  -H "User-Agent: FUZZ" \
  --hc 403 http://target.com/

# Fuzza session cookie — IDOR su sessioni numeriche
wfuzz -c -z range,1-50000 \
  -b "sessionid=FUZZ" \
  --hc 302,401 http://target.com/dashboard/

HTTP Basic Auth #

bash
# Brute force Basic Auth
wfuzz -c -w /usr/share/seclists/Passwords/Common-Credentials/top-passwords-shortlist.txt \
  --basic "admin:FUZZ" --hc 401 \
  http://target.com/protected/

# Fuzza anche username
wfuzz -c \
  -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
  -w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
  --basic "FUZZ:FUZ2Z" --hc 401 \
  http://target.com/protected/

What are FUZZ, FUZ2Z and FUZ3Z in Wfuzz? #

FUZZ identifies the first fuzzing position, FUZ2Z the second e FUZ3Z the third. Each position is associated with the corresponding wordlist based on the order in which you pass the parameters. -w: the first -w feed FUZZ, the second FUZ2Z, and so on.

bash
# Path + estensione
wfuzz -c \
  -w /usr/share/seclists/Discovery/Web-Content/common.txt \
  -w /usr/share/seclists/Fuzzing/Extensions/Web-Extensions.fuzz.txt \
  --hc 404 "http://target.com/FUZZ.FUZ2Z"

# Username + password su login
wfuzz -c \
  -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt \
  -w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \
  -d "user=FUZZ&pass=FUZ2Z" --hc 302 \
  http://target.com/login

The number of requests = len(w1) × len(w2)Two wordlists of 5.000 entries → 25 million requests. Calculate this first, especially on rate-limited targets.


Wfuzz Encoders: Encoding and Testing WAF Filters #

Encoders transform the payload before sending it. They don't guarantee bypass—they're used to test how the application (or any WAF running behind it) normalizes and interprets the encoded input, which is useful for both offensive and defensive normalization analysis.

bash
# Elenco encoder disponibili
wfuzz -e encoders
text
  base64       – Encodes the given string as base64
  md5          – Returns the md5 hash of the string
  urlencode    – URL-encodes special characters
  html_escape  – HTML entity encoding
  hexlify      – Converts string to hex
  sha1         – Returns sha1 hash
bash
# URL encoding (caratteri speciali nei payload SQLi)
wfuzz -c -z file,/usr/share/seclists/Fuzzing/SQLi/Generic-SQLi.txt,urlencode \
  --hs "error" "http://target.com/?id=FUZZ"

# Double URL encoding (test di normalizzazione a doppio layer)
wfuzz -c -z file,sqli.txt,urlencode-urlencode \
  "http://target.com/?id=FUZZ"

# Base64 (API che accettano parametri encodati)
wfuzz -c -z file,payloads.txt,base64 \
  -d "token=FUZZ" http://target.com/api/

# MD5 di ogni password (form che hashano lato server)
wfuzz -c -z file,passwords.txt,md5 \
  -d "hash=FUZZ" http://target.com/login

How to filter Wfuzz results #

Filtering is essential because wfuzz can generate thousands of seemingly valid answers. Filters --hc, --sc, --hl, --hw, --hh, --hs e --ss They serve to isolate interesting responses from noise.

FilterFlagWhen to use it
By status code--hc 404,403 / --sc 200,301Always — first filter
By lines--hl NAll 404s have the same number of lines
For words--hw NAll 404s have the same number of words
By character--hh NHide answers of exact size N
Regex show--ss "pattern"You only want responses containing a string
Regex hide--hs "error page"Hide replies with specific text
Expression--filter "c==200 and l>10"Advanced combined filter
bash
# Filtro combinato: status 200 E più di 10 linee
wfuzz -c -w wordlist.txt \
  --filter "c==200 and l>10" http://target.com/FUZZ

# Salva output JSON per analisi successiva
wfuzz -c -w wordlist.txt --hc 404 \
  -f /tmp/results.json,json http://target.com/FUZZ

Wfuzz with Burp Suite and rate limiting #

bash
# Passa tutto per Burp Suite (ispeziona ogni request)
wfuzz -c -w wordlist.txt --hc 404 \
  -p 127.0.0.1:8080 http://target.com/FUZZ

# Target lento o con rate limiting
wfuzz -c -w wordlist.txt --hc 404 \
  -t 5 -s 0.5 http://target.com/FUZZ
# -t 5: 5 thread (default 10)
# -s 0.5: delay tra request (verifica l'unità sulla tua versione)

# User-Agent legittimo + cookie sessione (fuzzing da autenticato)
wfuzz -c -w wordlist.txt --hc 302,403 \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \
  -H "Cookie: sessionid=abc123; PHPSESSID=xyz789" \
  http://target.com/FUZZ

When to use Wfuzz #

Wfuzz is especially useful when the fuzzing point isn't limited to the URL path. For standard directory discovery, tools like ffuf are often faster; wfuzz becomes the right choice when you need to check parameters, headers, cookies, body, or multiple locations at once—that's where its generality pays off.


How to Use Wfuzz During a Web Pentest #

text
1. DIRECTORY QUICK WIN
   └─ common.txt + --hc 404
   └─ File fuzzing con .php, .bak, .zip, .txt

2. APPROFONDIMENTO SU PATH TROVATI
   └─ medium.txt su /admin/, /api/, /backup/
   └─ Ricorsione -R 2

3. VHOST / SUBDOMAIN
   └─ Misura baseline → fuzza Host header con --hh N
   └─ DNS subdomain con -Z

4. PARAMETER DISCOVERY
   └─ burp-parameter-names.txt su endpoint trovati
   └─ IDOR range numerico su /api/user/FUZZ/

5. INJECTION TESTING
   └─ SQLi wordlist su parametri trovati (collega con guida SQL injection)
   └─ XSS payloads su input fields

6. AUTH BRUTEFORCE
   └─ Identifica risposta di errore → configura --hs o --hc
   └─ Lancia con 10k-most-common.txt

7. OUTPUT
   └─ -f risultati.json,json → analisi in Burp/Dradis

Troubleshooting #

ProblemCauseSolution
Output flood of resultsManca --hc 404Always add --hc 404 as a baseline
All answers same sizeServer responds the same for each pathUsa --hl o --hw in place of --hc
IP banned quicklyToo many threads / rate limit-t 5 -s 0.5
HTTPS — Invalid certificateSelf-signed SSLAdd --no-check-certificate
VHost finds nothingUnfiltered baselineMeasure with curl -s http://IP/ | wc -c then --hh N
Wrong encodingSpecial characters in the wordlistencoder: -z file,list.txt,urlencode
Very slow multi-positionHuge Cartesian productReduce wordlist or accept duration
Wfuzz crashes with no outputTarget is not respondingReduce thread, add --req-delay 5

FAQ #

What is Wfuzz? An open source web fuzzer in Python that replaces a position FUZZ in an HTTP request with the values ​​of a wordlist.

What is Wfuzz used for? To discover directories, files, hidden parameters, vhosts, and to test headers, cookies, login forms, and injection points—basically any field in an HTTP request.

Wfuzz or ffuf for directory fuzzing? Ffuf is significantly faster (Go vs. Python) and has cleaner output. For standard directories, use ffuf. Wfuzz comes in handy when you need encoders, advanced multi-positioning, or header/cookie fuzzing.

How to use FUZZ in Wfuzz? Enter the keyword FUZZ at the point of the request you want to test (URL, header, body, cookie) and connect a wordlist with -w. Wfuzz replaces FUZZ with each line of the wordlist, one request at a time.

What are FUZ2Z and FUZ3Z? They are the second and third fuzzing positions in a multi-position command, each fed by their respective wordlist passed with -w, in the order you specify it.

How do I filter Wfuzz responses? With --hc/--sc for status code, --hl/--hw/--hh for lines/words/characters, --hs/--ss for textual content, or --filter for combined expressions.

Does Wfuzz support POST fuzzing? Yes with -d "campo=FUZZ" for form-encoded or JSON body.

Can Wfuzz fuze headers and cookies? Yes with -H "Header: FUZZ" for headers and -b "cookie=FUZZ" for cookies.

How do I fuzz on an authenticated application? Capture the post-login session cookie with Burp Suite, then use it with -H "Cookie: session=abc123" in every request.

How do I handle CSRF tokens? Wfuzz doesn't handle dynamic CSRF. For that, use Burp Intruder with macros, or a Python script with requests that extracts the token before each request.

What is the best wordlist? common.txt for quick win, directory-list-2.3-medium.txt for complete assessment, burp-parameter-names.txt for parameter discovery. All in SecLists.

How do I save the results for the report? -f output.json,json for automated parsing, -f output.html,html for immediate readability. JSON is convenient for importing into reporting tools like Dradis.


Wfuzz Cheat Sheet #

text
=== DIRECTORY ===
Base:        wfuzz -c -w common.txt --hc 404 http://target/FUZZ
+Estensione: wfuzz -c -w common.txt --hc 404 http://target/FUZZ.php
Multi-ext:   wfuzz -c -w names.txt -w ext.txt --hc 404 "http://target/FUZZ.FUZ2Z"
Ricorsivo:   wfuzz -c -w medium.txt --hc 404 -R 2 http://target/FUZZ/

=== PARAMETER ===
GET nome:    wfuzz -c -w burp-params.txt --hh 0 "http://target/page?FUZZ=test"
GET valore:  wfuzz -c -z range,1-1000 --hc 404 "http://target/item?id=FUZZ"
POST:        wfuzz -c -w passwords.txt -d "user=admin&pass=FUZZ" --hc 302 http://target/login
JSON POST:   wfuzz -c -w endpoints.txt -H "Content-Type: application/json" -d '{"a":"FUZZ"}' --hc 400 http://target/api

=== VHOST / SUBDOMAIN ===
VHost:       wfuzz -c -w subdomains.txt -H "Host: FUZZ.target.com" --hh BASELINE http://IP/
Subdomain:   wfuzz -c -Z -w subdomains.txt http://FUZZ.target.com/

=== HEADER / COOKIE ===
Header:      wfuzz -c -w ips.txt -H "X-Forwarded-For: FUZZ" --sc 200 http://target/admin/
Cookie:      wfuzz -c -z range,1-50000 -b "session=FUZZ" --hc 302 http://target/dashboard/

=== AUTH ===
Basic:       wfuzz -c -w passwords.txt --basic admin:FUZZ --hc 401 http://target/protected/
Login:       wfuzz -c -w passwords.txt -d "u=admin&p=FUZZ" --hs "Invalid" http://target/login

=== MULTI-POSITION ===
Doppio:      wfuzz -c -w list1.txt -w list2.txt "http://target/FUZZ/FUZ2Z"
Login 2D:    wfuzz -c -w users.txt -w passwords.txt -d "u=FUZZ&p=FUZ2Z" --hc 302 http://target/login

=== ENCODERS ===
URL:         -z file,list.txt,urlencode
Double URL:  -z file,list.txt,urlencode-urlencode
Base64:      -z file,list.txt,base64
MD5:         -z file,list.txt,md5

=== FILTRI ===
--hc 404,403       Hide status code
--sc 200,301       Show solo status code
--hl N             Hide risposte con N linee
--hh N             Hide risposte con N caratteri
--hs "stringa"     Hide contenente stringa
--ss "stringa"     Show contenente stringa
--filter "c==200 and l>5"   Espressione combinata

=== PROXY / EVASION ===
Burp:        -p 127.0.0.1:8080
Delay:       -s 0.5
Thread:      -t 5 (default 10)
UA custom:   -H "User-Agent: Mozilla/5.0..."
Con cookie:  -H "Cookie: session=abc123"

=== OUTPUT ===
JSON:        -f output.json,json
HTML:        -f output.html,html

Related guides on hackita.it:

References #

#WAF bypass #directoryfuzzing #Wfuzz #webfuzzing

leave a message

I'm not a robot