Back to All Modules

Web Enumeration

#Overview

Web enumeration involves systematically discovering directories, files, virtual hosts, API endpoints, and technologies running on HTTP/HTTPS services. This is the most common attack surface in modern penetration tests, as web applications often expose vulnerabilities that lead to initial foothold. The process includes directory/file brute-forcing, virtual host discovery, technology fingerprinting, SSL/TLS inspection, and source code analysis.

#Prerequisites

  • Tools: gobuster, ffuf, feroxbuster, dirb, whatweb, curl, wget, Burp Suite
  • Wordlists: SecLists (raft-large-words, directory-list-2.3-medium, common.txt, big.txt), bitquark-subdomains-top100000.txt
  • Access Level: Network access to target web server (HTTP/HTTPS)
  • Recommended: Browser with Wappalyzer extension, Burp Suite for request inspection

#Detection & Enumeration

#Adding Discovered Domains to /etc/hosts

Essential first step when nmap or initial browsing reveals domain names:

# Add single domain
echo "10.10.11.11 board.htb" | sudo tee -a /etc/hosts

# Add multiple domains
echo "10.10.10.161 htb.local FOREST.htb.local" | sudo tee -a /etc/hosts

# Add subdomain discovered during enumeration
echo "10.10.11.11 crm.board.htb" | sudo tee -a /etc/hosts
echo "10.10.11.194 soc-player.soccer.htb" | sudo tee -a /etc/hosts

# Add domain controller and FQDN
echo "10.129.178.26 support.htb dc.support.htb" | sudo tee -a /etc/hosts
BASH

#Technology Fingerprinting

# whatweb -- fast technology identification
whatweb http://10.10.10.175
whatweb -a 3 http://board.htb  # Aggression level 3 (more thorough)

# curl headers inspection
curl -I http://10.10.10.175
curl -s -D- http://10.10.10.175 | head -20

# Inspect SSL/TLS certificate for virtual hosts and SANs
openssl s_client -connect 10.10.10.161:443 </dev/null 2>/dev/null | openssl x509 -noout -text | grep DNS

# Check robots.txt and sitemap.xml
curl -s http://target.htb/robots.txt
curl -s http://target.htb/sitemap.xml
BASH

whatweb flags:

  • -a : Aggression level (1=passive, 3=aggressive/heavy, 4=very heavy)
  • No flags: Default balanced scan identifies CMS, frameworks, server software

#Directory and File Brute-Forcing

gobuster (Fast, Go-based)

# Basic directory scan with common wordlist
gobuster dir -u http://soccer.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

# With extensions and status code filtering
gobuster dir -u http://board.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-words.txt -x php,txt,html,bak,zip -o gobuster_scan.txt

# Ignore specific status codes and add delay for stealth
gobuster dir -u http://target.htb -w /usr/share/wordlists/dirb/common.txt -x aspx,asp,php -b 404,403 --delay 500ms

# Common options:
#   -x : Extensions to append (php,aspx,txt,html,bak,zip,old)
#   -b : Blacklist status codes (ignore these)
#   -o : Output file
#   -t : Threads (default 10)
#   -k : Skip SSL certificate validation
#   --delay : Delay between requests
BASH

ffuf (Fast, Flexible, Rust-based)

# Basic directory fuzzing
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://10.10.10.175/FUZZ

# With size filtering (ignore baseline response size)
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://board.htb/FUZZ -fs 15949

# Extension brute-force
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-words.txt -u http://target.htb/FUZZ -e .php,.aspx,.txt,.html,.bak

# With match codes (only show specific HTTP codes)
ffuf -w /path/to/wordlist -u http://target.htb/FUZZ -mc 200,301,302,403

# Recursive depth
ffuf -w /path/to/wordlist -u http://target.htb/FUZZ -recursion -recursion-depth 2

# Rate limiting (requests/sec)
ffuf -w /path/to/wordlist -u http://target.htb/FUZZ -rate 50
BASH

feroxbuster (Recursive, Rust-based)

# Basic recursive scan
feroxbuster -u http://target.htb

# With extensions and depth control
feroxbuster -u http://target.htb -x php,html,txt,bak -d 3

# Quiet mode with output
feroxbuster -u http://target.htb -x php -q -o ferox_scan.txt
BASH

dirb (Classic, Slower)

# Basic scan
dirb http://target.htb

# With custom wordlist and extensions
dirb http://target.htb /usr/share/wordlists/dirb/big.txt -X .php,.html,.txt
BASH

#Wordlist Selection Guide

WordlistSizeBest For
dirb/common.txt~4,600Quick initial scan
dirbuster/directory-list-2.3-medium.txt~220,000Thorough directory discovery
seclists/Discovery/Web-Content/raft-large-words.txt~120,000Broad word coverage
seclists/Discovery/Web-Content/big.txt~20,000Medium coverage
seclists/Discovery/Web-Content/common.txt~4,700Quick scan with good coverage
seclists/Discovery/Web-Content/CGIs.txt~3,500CGI script discovery

#Virtual Host (VHOST) Discovery

# ffuf VHOST fuzzing (subdomain enumeration via Host header)
ffuf -w /usr/share/wordlists/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt:FUZZ \
  -u http://board.htb/ -H 'Host: FUZZ.board.htb' -fs 15949

# Multi-level subdomain discovery
ffuf -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ \
  -u http://domain.htb/ -H 'Host: FUZZ.domain.htb' -mc 200,301,302,403

# VHOST discovery with gobuster
gobuster vhost -u http://board.htb -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
BASH

Key VHOST flags:

  • -H 'Host: FUZZ.domain.htb' : The FUZZ keyword is replaced with each wordlist entry in the Host header.
  • -fs : Filter by response size (ignore the baseline/default response size).
  • -mc : Match specific HTTP status codes.
  • VHOST enumeration works because the web server returns different content based on the Host header.

#SSL/TLS Certificate Inspection

SSL certificates often leak internal hostnames, subdomains, and organizational information:

# Full certificate dump
openssl s_client -connect 10.10.10.161:443 </dev/null 2>/dev/null | openssl x509 -noout -text

# Extract Subject Alternative Names (SANs) -- reveals vhosts
openssl s_client -connect target.htb:8443 </dev/null 2>/dev/null | \
  openssl x509 -noout -text | grep -A1 "Subject Alternative Name"

# Check certificate expiry
echo | openssl s_client -connect target.htb:443 2>/dev/null | \
  openssl x509 -noout -dates

# Nmap SSL certificate script
nmap --script ssl-cert -p 443,8443 target.htb
BASH

#Source Code Inspection

# Download page and grep for comments, hidden fields, and secrets
curl -s http://target.htb | grep -i '<!--\|hidden\|password\|api\|key\|token\|secret'

# Extract all JavaScript files for review
curl -s http://target.htb | grep -oP 'src="[^"]*\.js"' | cut -d'"' -f2

# View page source for hidden input fields and comments
curl -s http://target.htb | grep -E '<input.*type="hidden"|<form|<script'

# Inspect WebSocket endpoints in source
curl -s http://target.htb | grep -i 'ws://\|wss://\|WebSocket'

# Find .git directory exposure
curl -s http://target.htb/.git/HEAD
curl -s http://target.htb/.git/config

# Git dumping when .git is exposed
git-dumper http://target.htb/.git/ ./dumped-git/
BASH

#API Endpoint Discovery

# Common API paths
curl -s http://target.htb/api/
curl -s http://target.htb/api/v1/
curl -s http://target.htb/swagger/
curl -s http://target.htb/graphql
curl -s http://target.htb/.well-known/

# REST API fuzzing with ffuf
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/api-endpoints.txt \
  -u http://target.htb/FUZZ -mc 200,403,401

# Swagger/OpenAPI documentation discovery
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/swagger.txt \
  -u http://target.htb/FUZZ
BASH

#WebSocket Enumeration

WebSocket services may run on non-standard ports and can be vulnerable to injection attacks:

# Identify WebSocket endpoints from JavaScript
curl -s http://target.htb | grep -oP "ws://[^'\"]+|wss://[^'\"]+"

# Test WebSocket connectivity
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" http://target.htb:9091/

# sqlmap can test WebSocket services for SQL injection
sqlmap -u "ws://soc-player.soccer.htb:9091" --data '{"id": "*"}' --dbs --threads 10 --level 5 --risk 3 --batch
BASH

#CMS-Specific Enumeration

# WordPress
wpscan --url http://target.htb --enumerate p,u,t  # plugins, users, themes

# Drupal
droopescan scan drupal -u http://target.htb

# Joomla
joomscan -u http://target.htb

# Dolibarr (ERP/CRM) -- default credentials admin:admin
# Check version from page footer or admin dashboard
BASH

#Additional Web Scanning Tools

# nikto -- Web vulnerability scanner (extremely noisy, well-signatured)
nikto -h http://10.10.10.10
nikto -h http://10.10.10.10 -Tuning 1234   # Run specific test categories
# Warning: nikto is very noisy and its User-Agent is widely signatured by WAFs/IDS
# Best for: Quick vulnerability overview on non-monitored targets

# dirsearch -- Alternative directory brute-forcer
dirsearch -u http://10.10.10.10 -w /usr/share/seclists/Discovery/Web-Content/common.txt
dirsearch -u http://10.10.10.10 -e php,html,js,txt

# nmap http-enum for initial path discovery
nmap --script http-enum -p 80,443 10.10.10.10

# ffuf API fuzzing with JSON content type
ffuf -u http://10.10.10.10/api/FUZZ -H 'Content-Type: application/json' -w /usr/share/seclists/Discovery/Web-Content/api/api-endpoints.txt
BASH

#Common Pitfalls

  • Forgetting to add domains/subdomains to /etc/hosts before scanning. Services like Kerberos, SMB, IIS, and VHOSTs require proper name resolution.
  • Using the wrong wordlist size for the context. raft-large-words.txt is great for thorough scans but takes much longer than common.txt.
  • Not filtering by response size (-fs) in ffuf, causing false positives where the server returns the same default page for all missing paths.
  • Ignoring 403 Forbidden responses. A 403 means the resource exists but access is denied -- this is actionable intel.
  • Not checking for file extension variations. A backup file like config.php.bak or web.config.old can leak credentials.
  • Using HTTP when the server redirects to HTTPS. Always check both and handle redirects.
  • Not reviewing SSL certificate SAN entries. These often reveal internal subdomains not listed anywhere else.
  • Overlooking WebSocket endpoints in JavaScript source. They often run without authentication.
  • Not attempting default credentials for discovered CMS/platforms (e.g., admin:admin for Dolibarr, admin:admin@123 for Tiny File Manager).

#OPSEC Considerations

  • Directory brute-forcing generates hundreds to thousands of HTTP requests in a short period. This is a clear signal to any WAF, IDS, or log monitoring system. Use rate limiting (--delay in gobuster, -rate in ffuf) for stealth.
  • 403 Forbidden responses from WAFs may indicate your IP is being throttled or blocked. If you start getting 403s universally, the WAF has likely blacklisted you.
  • User-Agent strings identify your tooling. gobuster defaults to "gobuster/version", ffuf uses "Fuzz Faster U Fool". Customize with -H 'User-Agent: Mozilla/5.0 ...' to blend in.
  • VHOST brute-forcing with Host headers is logged by the web server and may trigger alerts for DNS rebinding or host header attacks.
  • Technology fingerprinting (whatweb) sends identifiable request patterns. Use passive mode (-a 1) for lower profile.
  • SSL certificate inspection is passive and generates no application-layer logs. It is one of the stealthiest enumeration techniques.
  • Checking for .git exposure (curl http://target/.git/HEAD) is a single request and relatively stealthy, but repeated checks for many paths add up.
  • CMS scanners like wpscan are extremely noisy and well-signatured. They should only be used with authorization in non-stealth engagements.
  • OPSEC: feroxbuster uses a distinctive User-Agent -- can be flagged by WAFs.
  • OPSEC: nikto is one of the most well-signatured scanning tools -- almost all WAFs detect it.
  • OPSEC: dirsearch is quieter than nikto but still creates distinctive request patterns.

#Post-Exploitation Value

  • Web enumeration commonly reveals admin panels, configuration files, and backup archives that lead to initial foothold.
  • Discovered directories often expose the technology stack (framework, CMS, language) which guides vulnerability research.
  • Source code comments and hidden HTML fields may contain credentials, API keys, or internal paths.
  • Virtual hosts discovered through VHOST enumeration often host less-secure applications or development instances.
  • Internal web applications accessible only post-exploitation (on localhost or internal subnets) often have weaker security.
  • Configuration files (conf.php, web.config, .env) in web roots frequently contain database credentials that can be reused for lateral movement.

#Cross-References

#Tool References

ToolDescriptionLink
gobusterDirectory/VHOST/DNS brute-force (Go)https://github.com/OJ/gobuster
ffufFast web fuzzer (Rust)https://github.com/ffuf/ffuf
feroxbusterRecursive content discovery (Rust)https://github.com/epi052/feroxbuster
dirbClassic directory brute-forcer (C)Built into Kali
whatwebWebsite technology fingerprintinghttps://github.com/urbanadventurer/WhatWeb
WappalyzerBrowser extension for technology identificationhttps://www.wappalyzer.com/
git-dumperDownloads exposed .git repositorieshttps://github.com/arthaud/git-dumper
wpscanWordPress vulnerability scannerhttps://wpscan.com/wordpress-security-scanner
droopescanDrupal/SilverStripe scannerhttps://github.com/SamJoan/droopescan
sqlmapSQL injection detection/exploitation (including WebSocket)https://sqlmap.org/
curlCommand-line HTTP clientBuilt into most systems
Burp SuiteWeb application security testing platformhttps://portswigger.net/burp

#Source Machines

  • BoardLight (Easy, Linux) -- ffuf VHOST discovery finds crm.board.htb, Dolibarr default credentials lead to RCE
  • Sauna (Easy, AD) -- ffuf web scan, usernames derived from "About" page, ASREPRoasting
  • Soccer (Easy, Linux) -- gobuster finds /tiny directory, default Tiny File Manager credentials, WebSocket SQLi on port 9091
  • Support (Easy, Windows) -- No web server, shifted directly to SMB/LDAP enumeration
  • Broker (Easy, Linux) -- nmap identifies ActiveMQ, web enumeration confirms version 5.15.15 for CVE targeting
  • Authority (Medium, AD/Windows) -- HTTPS on 8443 reveals PWM password manager, SSL certificate inspection