# Virtual Host Enumeration

> Discover hidden virtual hosts on web servers by fuzzing Host headers, identifying subdomains and concealed services sharing the same IP address.

- **URL:** https://hackindex.io/services/web/enumeration/virtual-host-enumeration
- **Path:** HTTP/HTTPS > Enumeration
- **Up:** [Enumeration](https://hackindex.io/services/web/enumeration.md)
- **Published:** 2026-01-23
- **Updated:** 2026-08-11

Virtual host enumeration finds applications routed by hostname on the same IP. When a server returns different content depending on the Host header, there are likely multiple apps running: some not linked from the main site. Run this after [tech fingerprinting](https://hackindex.io/services/web/enumeration/http-tech-fingerprinting) confirms Host header sensitivity, or after [subdomain bruteforce](https://hackindex.io/services/web/reconnaissance/subdomain-bruteforce) returns names resolving to the same IP.

## Confirm Virtual Host Routing First

Before bruteforcing, verify the server responds differently to different Host headers:

```bash
curl -sk http://$TARGET_IP/ | wc -c
# 612
```

```bash
curl -sk http://$TARGET_IP/ -H "Host: $DOMAIN" | wc -c
# 14832
```

Interpreting the results:

- Different response sizes: vhost routing is active, proceed with bruteforce
- Same size but different content: routing may exist, compare body content instead of size
- Identical responses: no vhost routing, or the server falls back to a default for unknown hosts
- Connection refused or timeout on one: the server may filter by Host header at the network level

## ffuf Virtual Host Bruteforce

ffuf injects wordlist entries into the Host header. The key is filtering out the default response size so you only see results that differ from the baseline:

```bash
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u http://$TARGET_IP/ -H "Host: FUZZ.$DOMAIN" -mc 200,204,301,302,307,401,403
```

Filter the default response size to remove noise. Measure it first, then add `-fs`:

```bash
curl -sk http://$TARGET_IP/ -H "Host: invalid.invalid" | wc -c
# 612
```

```bash
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u http://$TARGET_IP/ -H "Host: FUZZ.$DOMAIN" -mc 200,204,301,302,307,401,403 -fs 612
# dev                     [Status: 200, Size: 14832, Words: 1234]
# admin                   [Status: 302, Size: 0, Words: 0]
```

Any result with a size different from the baseline is a valid virtual host. Add the discovered names to /etc/hosts and browse them directly:

```bash
echo "$TARGET_IP dev.$DOMAIN" | sudo tee -a /etc/hosts
echo "$TARGET_IP admin.$DOMAIN" | sudo tee -a /etc/hosts
```

## gobuster vhost Mode

gobuster has a dedicated vhost mode that also measures response differences. Useful as a second pass when ffuf results look incomplete:

```bash
gobuster vhost -u http://$TARGET_IP/ -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt --append-domain -t 50
```

The `--append-domain` flag appends the base domain to each wordlist entry, producing `dev.example.com` rather than just `dev`. Required for most modern setups.

## HTTPS Virtual Hosts

For HTTPS targets, add `-k` to skip certificate validation and specify the full HTTPS URL:

```bash
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u https://$TARGET_IP/ -H "Host: FUZZ.$DOMAIN" -mc 200,204,301,302,307,401,403 -fs 612 -k
```

## Non-Standard Ports

When the target runs on a non-standard port, specify it in both the URL and the Host header:

```bash
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -u http://$TARGET_IP:$PORT/ -H "Host: FUZZ.$DOMAIN:$PORT" -mc 200,204,301,302,307,401,403 -fs 612
```

After discovering virtual hosts, run [content discovery](https://hackindex.io/services/web/enumeration/content-discovery) separately against each vhost: they often have completely different directory structures and applications.

## References

- [ffuf](https://github.com/ffuf/ffuf) - Host header fuzzing, size filtering, and output options
- [Gobuster](https://github.com/OJ/gobuster) - vhost mode usage and append-domain flag
- [SecLists: DNS subdomains wordlists](https://github.com/danielmiessler/SecLists) - subdomains-top1million wordlists for vhost bruteforce
