Gobuster

Fast directory, DNS, and virtual host brute-forcer written in Go. Simpler than ffuf, built for quick directory enumeration and subdomain discovery. The go-to for rapid web surface mapping.

Web
LevelBeginner. Simpler than ffuf, so a good first brute-forcing tool.
Know firstWhat a URL path and an HTTP status code are, and what a wordlist is.
You will learn torun directory, DNS and virtual-host scans, and know when to pick it over ffuf.

What is it?

Gobuster brute-forces web directories, DNS subdomains, and virtual hosts by sending thousands of requests using a wordlist. It's written in Go, making it fast and concurrent by default. Unlike ffuf, Gobuster has three distinct modes, each purpose-built:

  • dir mode: discovers hidden files and directories on a web server
  • dns mode: enumerates subdomains of a domain
  • vhost mode: discovers virtual hosts on a web server (different from DNS subdomains)

Gobuster's simplicity is its strength. Where ffuf is a general-purpose fuzzer that can inject payloads anywhere, Gobuster focuses on doing three things extremely well. For quick directory enumeration, many pentesters reach for Gobuster first because its syntax is simpler and the output is cleaner.

Run this first

In dir mode gobuster requests each word from the wordlist as a path and reports the ones that exist.

bash: your first directory scan
$ gobuster dir -u http://10.10.10.10 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
  • dir is the mode: directory and file brute-forcing. The other modes are dns and vhost.
  • -u is the target URL.
  • -w is the wordlist.

Each result shows a status code and a size. Add -x php,txt to look for files with those extensions, and -t 50 to raise the thread count from the default of 10.

When do you use it?

Whenever Nmap reveals an HTTP/HTTPS service (ports 80, 443, 8080, 8443, or any web server), directory enumeration is one of your first steps. Gobuster maps out the web application's structure by finding pages and directories that aren't linked from the main site.

  • You found port 80/443 open: immediately start a dir scan while you browse the site manually
  • The main page is a default install: there might be hidden admin panels or applications in subdirectories
  • You need subdomains: many targets host different apps on different subdomains (e.g., dev.target.com, staging.target.com)
  • The TLS certificate shows a hostname: try vhost enumeration to find other virtual hosts sharing the same IP
What hidden directories reveal
  • /admin, /administrator, /panel: admin interfaces, often with weak or default credentials
  • /api, /api/v1, /swagger: API endpoints that might not require authentication
  • /backup, /old, /bak: backup files, potentially containing source code or config files
  • /.git, /.svn: exposed version control directories. Dump with git-dumper
  • /phpmyadmin, /adminer: database management interfaces
  • /wp-admin, /wp-content: WordPress (run wpscan next)

dir mode: directory scanning

The most common mode. Brute-forces files and directories on a web server.

bash: basic directory scan
# Standard directory enumeration
$ gobuster dir -u http://10.10.10.10 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.10
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Status codes:            200,204,301,302,307,401,403
===============================================================
/images               (Status: 301) [Size: 315] [--> http://10.10.10.10/images/]
/admin                (Status: 301) [Size: 314] [--> http://10.10.10.10/admin/]  <-- admin panel, try default creds
/uploads              (Status: 301) [Size: 316] [--> http://10.10.10.10/uploads/]  <-- check for unauthenticated file upload
/api                  (Status: 200) [Size: 42]
/server-status        (Status: 403) [Size: 279]  <-- Apache status page, worth a look if you can get access

Adding file extensions

bash: scan with extensions
# Check for PHP, HTML, TXT, BAK files (critical for finding source code)
$ gobuster dir -u http://10.10.10.10 -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -x php,html,txt,bak,old,conf

# Flags breakdown:
# -x = file extensions to append to each word
# So if the wordlist has "config", gobuster tries:
#   /config, /config.php, /config.html, /config.txt, /config.bak, /config.old, /config.conf

Useful flags

bash: common flag combinations
# Increase threads for faster scanning (default: 10)
$ gobuster dir -u http://10.10.10.10 -w wordlist.txt -t 50

# Follow redirects
$ gobuster dir -u http://10.10.10.10 -w wordlist.txt -r

# Skip TLS certificate verification (self-signed certs)
$ gobuster dir -u https://10.10.10.10 -w wordlist.txt -k

# Add cookies (for authenticated scanning)
$ gobuster dir -u http://10.10.10.10 -w wordlist.txt -c "PHPSESSID=abc123"

# Custom status codes to consider as "found" (add 500 for errors that leak info)
# -s fails on its own in 3.6 because -b (a blacklist of 404) is set by default, so clear it with -b ""
$ gobuster dir -u http://10.10.10.10 -w wordlist.txt -s "200,204,301,302,307,403,500" -b ""

# Filter by response size (hide 404 pages that return 200 with custom error)
$ gobuster dir -u http://10.10.10.10 -w wordlist.txt --exclude-length 1234

# Save output to file
$ gobuster dir -u http://10.10.10.10 -w wordlist.txt -o gobuster_results.txt

dns mode: subdomain enumeration

Discovers subdomains by querying DNS for each word in the wordlist prepended to the target domain.

bash: DNS subdomain enumeration
# Find subdomains of target.com
$ gobuster dns -d target.com -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt

===============================================================
[+] Domain:     target.com
[+] Threads:    10
[+] Resolver:   8.8.8.8
===============================================================
Found: www.target.com
Found: mail.target.com
Found: dev.target.com  <-- dev/staging boxes often skip hardening
Found: staging.target.com
Found: vpn.target.com

# Use a specific DNS resolver (useful for internal DNS)
$ gobuster dns -d corp.local -w wordlist.txt -r 172.16.1.10:53

# Show IP addresses alongside results
$ gobuster dns -d target.com -w wordlist.txt -i
DNS vs Vhost

DNS mode queries actual DNS records, the subdomain must exist in DNS. Vhost mode sends HTTP requests with different Host headers, the subdomain only needs to exist as a virtual host on the web server, even if there's no DNS record. In pentesting, you often need both: DNS mode first for real subdomains, then vhost mode on each IP to find unregistered virtual hosts.

vhost mode: virtual host discovery

Virtual host enumeration sends requests with different Host: headers to find web applications sharing an IP that aren't in DNS.

bash: vhost enumeration
# Discover virtual hosts
$ gobuster vhost -u http://10.10.10.10 -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain --domain target.com

===============================================================
Found: dev.target.com Status: 200 [Size: 5832]
Found: staging.target.com Status: 200 [Size: 2341]
Found: internal.target.com Status: 302 [Size: 0] [--> /login]  <-- a whole app DNS never told you about

# Filter out false positives by response size
$ gobuster vhost -u http://10.10.10.10 -w wordlist.txt --append-domain --domain target.com --exclude-length 301
Add found vhosts to /etc/hosts

When you find a virtual host like dev.target.com, add it to your /etc/hosts file: echo "10.10.10.10 dev.target.com" >> /etc/hosts. Otherwise your browser can't reach it, the web server only serves the right content when the Host header matches.

Wordlist selection guide

The wordlist determines what you find. A bad wordlist = wasted time. Here are the ones that matter:

WordlistSizeUse case
raft-medium-directories.txt~30kBest general-purpose directory list. Start here
directory-list-2.3-medium.txt~220kThorough directory scan when raft-medium misses things
raft-medium-files.txt~25kFiles specifically (with extensions)
common.txt~4.7kQuick initial scan: fast and catches low-hanging fruit
subdomains-top1million-5000.txt~5kDNS/vhost subdomain discovery (fast)
subdomains-top1million-20000.txt~20kMore thorough subdomain scan
big.txt~20kAlternative general-purpose list (SecLists)
Extension strategy by technology

Match your -x extensions to the tech stack. PHP site: -x php,phps,php.bak. ASP.NET: -x aspx,asp,config. Java: -x jsp,do,action. Always add txt,bak,old,conf,log regardless: backup files leak source code and credentials.

Gobuster vs ffuf

FeatureGobusterffuf
Primary purposeDir/DNS/vhost brute-forcingGeneral web fuzzer (dirs, params, headers, anything)
SyntaxSimple, mode-specific flagsFUZZ keyword placement (more flexible, steeper curve)
SpeedFastVery fast (Go, async)
RecursionNo built-in recursionSupports recursive scanning
Multiple wordlistsOne at a timeCan fuzz multiple positions simultaneously
Parameter fuzzingNot supportedPowerful: fuzz GET/POST params, headers, cookies
FilteringStatus codes, sizeStatus, size, words, lines, regex (much more flexible)
Output formatsTextText, JSON, CSV, HTML
Best forQuick dir scans, DNS, vhostsComplex fuzzing, parameter discovery, chaining
Decision: Gobuster or ffuf?

Use Gobuster when you just need directories and subdomains, it's faster to type and understand. Switch to ffuf when you need parameter fuzzing, recursive scanning, multiple injection points, or more sophisticated filtering. For CPTS, know both.

Common mistakes

Things that go wrong
  • Not using extensions: Without -x, gobuster only finds directories. On a PHP site, /config.php won't be found unless you add -x php
  • Using too small a wordlist: common.txt (4.7k words) misses a lot. Use raft-medium-directories.txt or directory-list-2.3-medium.txt for thorough scanning
  • Ignoring status 403: Forbidden doesn't mean empty: it means the directory exists but you can't list it. Try accessing files within it
  • Not checking HTTPS separately: http://target and https://target might serve different content. Scan both
  • Forgetting -k for self-signed certs: HTTPS with a self-signed certificate fails without -k
  • Not filtering custom 404 pages: Some servers return 200 for everything with a custom "not found" page. Use --exclude-length to filter by response size
  • Running too many threads against WAFs: 50+ threads might trigger rate limiting. Start with 10, increase if the server handles it

Check yourself

Answer each question out loud or on paper first, then open it. Retrieving the answer teaches you more than rereading the page.

What are gobuster's three modes used for?
dir finds directories and files on a web server. dns finds subdomains by resolving names. vhost finds virtual hosts by changing the Host header.
You run gobuster dir with -s "200,301" and it exits with an error. Why?
In 3.6 a 404 blacklist (-b) is set by default, and gobuster refuses to use both lists at once. Clear it with -b "".
In vhost mode with an IP address as the URL, which flags make it build hostnames?
--append-domain and --domain target.com, so each word becomes word.target.com in the Host header.
When would you pick ffuf over gobuster?
When the unknown part is not just a path: POST bodies, parameters or headers. ffuf puts FUZZ anywhere. gobuster is simpler and covers directories, subdomains and vhosts.
Many results come back with the same size. What does that usually mean?
The server returns a custom "not found" page with a 200 status. Filter that size with --exclude-length.