⚠️ Educational Use Only — Directory brute-forcing against systems you don't own generates large numbers of requests and may be considered unauthorized access or a denial of service. Only perform this against systems you own, have written authorization to test, or dedicated lab environments.
When to Use
- During the information gathering phase of an authorized web application pentest
- In CTF challenges where a hidden path, admin panel, or backup file contains the flag
- When performing authorized reconnaissance to map an application's full attack surface
- As a prerequisite for finding hidden admin panels, API endpoints, backup files (
config.php.bak,.git/), and developer artifacts - When validating that a WAF or server configuration correctly denies access to sensitive paths
Prerequisites
- Software: Docker + Docker Compose (ffuf, gobuster, dirb pre-installed in lab)
- Knowledge: Basic understanding of HTTP status codes (200 OK, 301 Redirect, 403 Forbidden, 404 Not Found)
- Lab:
labs/web-application/sqli-basics(shares environment) - Difficulty: Beginner
- Time: 20–30 minutes
Workflow
Step 1: Start the Lab
agentlab start sqli-basics
agentlab exec sqli-basics bash
# Target: http://target:80
Step 2: Basic Directory Fuzzing with ffuf
# Fast directory discovery
ffuf -u http://target:80/FUZZ \
-w /usr/share/wordlists/dirb/common.txt \
-mc 200,301,302,403
# With file extensions
ffuf -u http://target:80/FUZZ \
-w /usr/share/wordlists/dirb/common.txt \
-e .php,.html,.txt,.bak,.old \
-mc 200,301,302,403
Step 3: Recursive Enumeration
# Recursively fuzz found directories
ffuf -u http://target:80/FUZZ \
-w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
-recursion -recursion-depth 2 \
-mc 200,301,302
Step 4: Filter Noise
# Filter by response size to remove false positives
ffuf -u http://target:80/FUZZ \
-w /usr/share/wordlists/dirb/common.txt \
-mc 200,301 \
-fs 1234 # Filter responses of this exact size (false positives)
# Filter by word count
ffuf -u http://target:80/FUZZ \
-w /usr/share/wordlists/dirb/common.txt \
-fw 10 # Filter responses with exactly 10 words
Step 5: Virtual Host Discovery
# Discover subdomains/vhosts by fuzzing the Host header
ffuf -u http://target:80/ \
-H "Host: FUZZ.target" \
-w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
-mc 200 \
-fs 0 # Filter empty responses
Step 6: Common High-Value Targets
Always check these manually after directory fuzzing:
for path in ".git" ".env" "admin" "backup" "config" "api" "swagger" "robots.txt" ".htaccess" "wp-login.php" "phpinfo.php" "server-status"; do
code=$(curl -o /dev/null -s -w "%{http_code}" "http://target:80/$path")
echo "$code $path"
done
Step 7: Capture the Flag
A hidden admin directory contains the flag:
ffuf -u http://target:80/FUZZ -w /usr/share/wordlists/dirb/common.txt -mc 200
# Finds: /admin-secret (200 OK)
curl http://target:80/admin-secret/
# FLAG{hidden_directory_found}
Key Concepts
| Concept | Definition |
|---|---|
| Fuzzing | Automated testing by trying many inputs from a wordlist |
| Wordlist | File of paths/names to test against (rockyou, SecLists, dirb/common.txt) |
| Status Code 403 | Forbidden — directory exists but access is denied (still valuable to document) |
| Content Discovery | Finding undocumented or unlinked parts of a web application |
| T1595.003 | MITRE ATT&CK: Active Scanning — Wordlist Scanning |
Tools
| Tool | Purpose | Lab Availability |
|---|---|---|
ffuf |
Fast web fuzzer — highly configurable, best for filtering | ✅ Pre-installed |
gobuster |
Go-based directory/DNS/vhost brute forcer | ✅ Pre-installed |
dirb |
Classic directory brute forcer | ✅ Pre-installed |
| SecLists | Comprehensive wordlist collection | ✅ Pre-installed |
Output / Verification
agentlab verify sqli-basics "FLAG{hidden_directory_found}"