Gobuster is the brute-forcer most pentesters reach for when they need to enumerate directories, DNS subdomains, or virtual hosts. It's fast, scriptable, and the syntax is consistent across modes. Here's the working tutorial.
TL;DR
gobuster diris the directory brute-forcer (replaces the olddirb/dirbusterworkflow).gobuster dnsenumerates subdomains by querying DNS directly.gobuster vhostdiscovers virtual hosts on a single IP.- Wordlist choice and threads matter more than any flag.
Install
# macOS
brew install gobuster
# Go (latest)
go install github.com/OJ/gobuster/v3@latest
# Debian / Ubuntu
sudo apt install gobuster
# Verify
gobuster version
You'll also need wordlists. The community standard is SecLists:
git clone --depth 1 https://github.com/danielmiessler/SecLists.git ~/SecLists
That repo is referenced in nearly every Gobuster command you'll find online.
Mode 1: directory brute-forcing (gobuster dir)
Find files and directories that exist but aren't linked:
gobuster dir \
-u https://target.example.com \
-w ~/SecLists/Discovery/Web-Content/common.txt \
-t 50
Output:
/admin (Status: 301) [Size: 178]
/.git/HEAD (Status: 200) [Size: 23]
/backup.zip (Status: 200) [Size: 18432]
Flags worth knowing:
| Flag | Effect |
|------|--------|
| -u | Target URL |
| -w | Wordlist |
| -t | Threads (default 10; bump to 50–100 on solid targets) |
| -x | Extensions to append (-x php,html,bak) |
| -s | Status codes to show (default 200,204,301,302,307,401,403) |
| -b | Status codes to ignore (-b 404) |
| -r | Follow redirects |
| -k | Don't verify TLS cert (useful for self-signed) |
| -H | Custom headers (-H "Cookie: session=abc") |
| -o | Output to file |
| --no-error | Suppress connection errors |
| --exclude-length | Hide responses of a given byte length (handy for soft-404s) |
Practical examples
# Look for backup and config files
gobuster dir -u https://target.example.com \
-w ~/SecLists/Discovery/Web-Content/common.txt \
-x bak,old,backup,conf,config,zip,tar.gz \
-t 50
# Authenticated brute force (cookie-based)
gobuster dir -u https://target.example.com/account \
-w ~/SecLists/Discovery/Web-Content/raft-large-words.txt \
-H "Cookie: session=eyJhbGciOiJI..." \
-t 30
# Skip the noisy soft-404 responses
gobuster dir -u https://target.example.com \
-w ~/SecLists/Discovery/Web-Content/raft-small-words.txt \
--exclude-length 1234
Wordlist choice
Wordlists matter more than flag tuning. Reasonable starting points from SecLists:
Discovery/Web-Content/common.txt— ~4,700 entries, great first passDiscovery/Web-Content/raft-small-words.txt— well-curated, mid-sizeDiscovery/Web-Content/raft-large-words.txt— bigger, broader coverageDiscovery/Web-Content/directory-list-2.3-medium.txt— large, slowerDiscovery/Web-Content/CMS/— CMS-specific lists (WordPress, Joomla, Drupal)
For a typical engagement: common.txt for the first sweep, then a CMS-specific list once you know the stack.
Mode 2: DNS subdomain enumeration (gobuster dns)
Brute-force subdomains by querying the authoritative DNS:
gobuster dns \
-d example.com \
-w ~/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
-t 50
Output:
Found: api.example.com
Found: dev.example.com
Found: staging.example.com
Found: vpn.example.com
Flags specific to DNS mode:
| Flag | Effect |
|------|--------|
| -d | Target domain |
| -r | Use a specific resolver (-r 8.8.8.8) |
| -i | Show IPs of resolved subdomains |
| --wildcard | Force wildcard handling (rare; usually auto) |
Practical examples
# Standard subdomain sweep with IP resolution
gobuster dns -d example.com \
-w ~/SecLists/Discovery/DNS/subdomains-top1million-20000.txt \
-i -t 100
# Use a specific resolver to dodge DNS rate limits
gobuster dns -d example.com \
-w big-list.txt -r 1.1.1.1 -t 100
DNS brute-forcing is faster than HTTP brute-forcing — push threads up to 100+ if your resolver can keep up. Be mindful of rate limits from public resolvers; consider running your own (unbound, etc.) for big sweeps.
Mode 3: vhost discovery (gobuster vhost)
When multiple sites share an IP, the responding application depends on the Host: header. vhost mode brute-forces hostnames against a single endpoint:
gobuster vhost \
-u http://203.0.113.10 \
-w ~/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
--append-domain example.com \
-t 50
Output (only when the response differs from the baseline):
Found: secret-admin.example.com Status: 200 [Size: 2341]
Flags specific to vhost mode:
| Flag | Effect |
|------|--------|
| -u | Target IP / URL |
| --append-domain | Append this to each wordlist entry |
| --exclude-length | Hide responses matching given lengths |
When you'd use it
- You've found an IP that hosts multiple apps, but only the main vhost is in DNS.
- You're testing internal infrastructure where vhosts aren't publicly resolvable.
- You suspect a "hidden" admin vhost behind the same load balancer as the public site.
vhost mode is overlooked compared to dir / dns mode, but it's where you find admin panels that aren't linked from the main site or in DNS.
Threading guidance
Threading is the biggest knob for speed. Realistic defaults:
| Target | Threads | |--------|---------| | Public web app on managed infra | 30–50 | | Public web app on shared hosting | 10–20 | | DNS brute force (your resolver) | 100+ | | DNS brute force (public resolver) | 20–50 | | Internal target | 50–100 |
If you start seeing connection errors or 5xx responses, dial threads down. Brute-forcing isn't useful if half your responses time out.
Output and resuming
Save to file with -o:
gobuster dir -u https://target -w wordlist.txt -o results.txt
Resume an interrupted run:
gobuster dir -u https://target -w wordlist.txt --resume
This reads the existing output file and skips already-tested entries. Essential for long DNS sweeps.
Common pitfalls
- Soft 404s. Many sites return
200 OKwith a "page not found" body. You'll get hundreds of false positives. Use--exclude-lengthafter a baseline run to filter them out. - Default wordlist for everything.
common.txtis fine for a first pass but misses CMS-specific endpoints. Switch wordlists when you fingerprint the stack. - Forgetting extensions.
gobuster dirdoesn't append extensions by default./adminwill be found;/admin.phpwon't unless you set-x php. - Hitting rate limits unnoticed. A WAF that silently rate-limits you produces a stream of 200/empty responses. Always sanity-check by running a known-good URL against the same target mid-scan.
- Threading too aggressively on shared hosting. You'll either get banned or trigger their abuse desk.
When you'd use something else
ffufis faster and has more flexible fuzzing (multiple wordlists per request, recursion, etc.). Many pentesters have switched.dirsearchis a Python-based alternative with a built-in dictionary.subfinder+httpxis the modern pairing for subdomain enumeration — passive sources first, then HTTP-probe the results. Faster and stealthier than DNS brute force for most targets.- Nuclei with the
exposures/template set finds many of the same misconfigured directories Gobuster would, plus content-aware matching.
Gobuster's strength is its simplicity. For a quick brute force without a configuration learning curve, it remains the easy reach.
Further reading
- Gobuster project — github.com/OJ/gobuster
- SecLists — github.com/danielmiessler/SecLists
- Related: our Nuclei templates guide for exposure-style checks