WhatWeb
WhatWeb fires a few HTTP requests at a web target and tells you what is running behind the response: the server, the framework or CMS, JavaScript libraries, cookies, headers, and redirects. Reach for it the moment Nmap shows an open web port and you need the stack before you decide what to test next, whether that is one CTF box or a list of freshly discovered vhosts. A thirty-second fingerprint usually points you straight at the right follow-up tool.
Mental model: whatweb [options] TARGET. A bare host gets http:// prepended; everything else is one flag away.
New to fingerprinting? Core concepts
- Target: a URL, IP, hostname, CIDR range, or
-i fileof targets; a bare host getshttp://prepended - Plugin: the unit that matches one technology (server, CMS, JS library, header, cookie); WhatWeb ships hundreds
- Aggression (
-a): how hard it tries.1stealthy (one request),3aggressive (confirm matches),4heavy (probe plugin URLs) - Fingerprint: the bracketed list of matched plugins with best-effort versions, for example
Apache[2.4.41] - Confidence: a match is a clue, not proof; banners can be stripped, faked, or simply wrong
- Redirect handling (
--follow-redirect): stop at the first hop, or chase each3xxto the real app - Logging (
--log-*): brief one-liners, verbose evidence, or structured XML/JSON/SQL/MagicTree for tooling
When to reach for WhatWeb (and when not)
Reach for it as the first read of a web port after Nmap, to triage a pile of discovered vhosts, to inventory your own stack, or to confirm a reverse proxy or WAF is really hiding the server banner you expected it to hide.
Reach for something else when you already know the stack and just want to talk to the app (curl, a browser, Burp), when you need paths or parameters (gobuster, ffuf, feroxbuster), when you need to confirm vulnerabilities rather than name tech (nikto, nuclei), or when you need probing at massive scale (httpx).
Install, update, verify#
sudo apt install -y whatweb # Debian / Ubuntu / Kali
sudo gem install whatweb # RubyGems (often newer than distro repos)
sudo apt install --only-upgrade -y whatweb # update
whatweb --version # version string
command -v whatweb # confirm it is on PATH
whatweb --list-plugins | wc -l # how many plugins this copy carries
Most of WhatWeb’s value lives in its plugins. For the newest signatures, git clone https://github.com/urbanadventurer/WhatWeb.git and run ./whatweb in place; a fresh clone usually detects more than an older distro package on the same target.
Flags you’ll actually use#
Skim these first; the cheat sheet below is these flags combined.
| Flag | Does | Flag | Does |
|---|---|---|---|
-v | Verbose, per-plugin evidence | -H | Add a request header (e.g. Host:) |
-a 1 | Stealthy, one request | -c | Send cookies name=value |
-a 3 | Aggressive, confirm matches | --user | HTTP basic auth user:pass |
-a 4 | Heavy, probe plugin URLs | -U | Set the User-Agent |
-i | Read targets from a file | --proxy | Route through a proxy |
--no-errors | Hide dead-host error lines | -p | Run only chosen plugins |
--follow-redirect= | never / same-site / always | -g | Grep responses for a string |
--max-redirects | Cap the redirect chain | --log-brief | One line per target to a file |
-t | Threads (default 25) | --log-json | Machine-readable JSON output |
--wait | Seconds between connections | --log-verbose | Full evidence to a file |
Cheat sheet#
Every block starts simple and adds one flag at a time, so you can stop at the line that does the job.
# Build up a scan: stop at the line you need
whatweb URL # 1. one-line fingerprint
whatweb -v URL # 2. + per-plugin evidence
whatweb -v -a 3 URL # 3. + confirmation requests (versions)
whatweb -v -a 3 --follow-redirect=always URL # 4. + chase redirects to the real app
# Aggression levels (noise vs depth)
whatweb -a 1 URL # stealthy, one request per target
whatweb -a 3 URL # aggressive, confirm level-1 matches with extra requests
whatweb -a 4 URL # heavy, request every plugin URL (loud, can break weak apps)
# Targets and lists
whatweb TARGET_IP # bare host, whatweb prepends http://
whatweb https://DOMAIN/ # explicit scheme + path (use https:// to hit 443)
whatweb 10.0.0.0/24 # a whole CIDR range
whatweb -i urls.txt # one target per line from a file
whatweb --no-errors 10.0.0.0/24 # sweep a range, hide dead-host error lines
# Redirects
whatweb --follow-redirect=always URL # follow every hop to the final app
whatweb --follow-redirect=never URL # stay on the first response
whatweb --max-redirects=3 URL # cap the chain length
# Identity: headers, cookies, user-agent, auth
whatweb -U 'Mozilla/5.0' URL # set the User-Agent
whatweb -H 'Host: internal.local' http://TARGET_IP/ # hit a name-based vhost by IP
whatweb -c 'session=PLACEHOLDER' URL # send a session cookie
whatweb --user admin:PLACEHOLDER URL # HTTP basic auth
# Through a proxy (lands in Burp / ZAP history)
whatweb --proxy 127.0.0.1:8080 URL
whatweb --proxy 127.0.0.1:8080 --proxy-user u:p URL # authenticated proxy
# Plugins and grep
whatweb --list-plugins # every plugin name
whatweb --info-plugins=word # details on plugins matching a search
whatweb -p Apache,PHP,WordPress URL # run only these plugins
whatweb -g 'admin' URL # grep the response body, report via the Grep plugin
# Save output for notes and tooling
whatweb URL --log-brief scans/web.txt # one line per target
whatweb -v URL --log-verbose scans/web.txt # full evidence to a file
whatweb URL --log-json scans/web.json # machine-readable JSON
whatweb URL --log-xml scans/web.xml # XML for tooling / MagicTree
# Tune speed and noise
whatweb -t 50 -i urls.txt # 50 threads for a big list
whatweb --wait=2 -i urls.txt # pause 2s between connections (quieter)
whatweb --open-timeout=10 --read-timeout=30 URL # bump timeouts on a slow host
Command breakdowns#
Each block below explains one situation, the exact command, and what to expect back.
Fingerprint a single web target#
whatweb http://TARGET_IP/
Prints one summary line: the status, the server banner, and a few bracketed plugin hits. The fastest single-shot read of an unknown stack.
Get per-plugin evidence with verbose output#
whatweb -v http://TARGET_IP/
-v expands each hit into a block showing the plugin, the version guess, and the evidence string it matched on. Use it when the one-liner is too thin to act on.
Stay quiet with a single-request pass#
whatweb -a 1 http://TARGET_IP/
Level 1 sends one request per target and still follows redirects. The lowest-noise first touch on a fragile or rate-sensitive service.
Confirm guesses with an aggressive pass#
whatweb -a 3 -v http://TARGET_IP/
When a level-1 plugin matches, level 3 fires extra requests to confirm the guess and pin a version. More plugin hits, more lines in the target’s logs.
Follow redirects to the real application#
whatweb --follow-redirect=always http://TARGET_IP/
Many targets 301/302 to the actual app. This chases every hop and fingerprints the final destination instead of stopping at the redirect page.
Fingerprint a name-based virtual host#
whatweb -H 'Host: internal.local' http://TARGET_IP/
whatweb http://DOMAIN/
The Host header reaches a name-based vhost by IP, so the app can differ from what the bare IP shows. If DNS resolves the name, point WhatWeb straight at the hostname.
Scan a list of discovered URLs#
whatweb -i urls.txt --log-brief scans/triage.txt
urls.txt holds one in-scope target per line. The brief log gives one comparable line per host, easy to skim and sort later.
Sweep a subnet without drowning in errors#
whatweb --no-errors 10.0.0.0/24
--no-errors hides the connection-error lines from dead hosts, so the output is only the machines that actually answered on the web port.
Route traffic through Burp or ZAP#
whatweb --proxy 127.0.0.1:8080 http://TARGET_IP/
Same fingerprint, but every request now lands in your proxy history for inspection and replay. Add --proxy-user u:p if the proxy needs auth.
Fingerprint a page behind a login#
whatweb -c 'session=PLACEHOLDER' -U 'Mozilla/5.0' http://TARGET_IP/dashboard
-c sends a session cookie and -U sets a normal User-Agent, so WhatWeb reads the page that only renders for a logged-in browser.
Save structured JSON and extract the tech list#
whatweb http://TARGET_IP/ --log-json scans/web.json
jq '.[].plugins | keys' scans/web.json
The JSON log is stable and diffable. jq turns it into a clean list of detected plugin names you can sort, compare over time, or feed to the next tool.
Grep the response for a string#
whatweb -g 'admin' http://TARGET_IP/
-g searches the raw HTTP response for a string or regex and reports matches through the Grep plugin. Handy for spotting a keyword, path, or comment the built-in plugins ignore.
Run only the plugins you care about#
whatweb -p Apache,PHP,WordPress http://TARGET_IP/
Limits the scan to the named plugins, which cuts noise and time when you only need to confirm one or two suspected technologies. Use --list-plugins to see the exact names.
Slow the scan down to reduce noise#
whatweb --wait=2 -i urls.txt
--wait pauses between connections so a list scan trickles instead of bursting. Pairs well with -a 1 and a realistic -U when you want the smallest footprint.
Speed up a large list with more threads#
whatweb -t 50 -i urls.txt --no-errors --log-brief scans/bulk.txt
-t raises the thread count from the default 25 to churn through a big in-scope list faster. Drop it back down for fragile targets.
Reading the output#
A WhatWeb line looks like http://TARGET_IP/ [200 OK] Apache[2.4.41], HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], Title[Login], IP[TARGET_IP]. Each bracket is one finding.
| Field | Meaning | Do next |
|---|---|---|
[200 OK] / [301 Moved] / [403 Forbidden] | HTTP status of the response | Non-2xx shapes the next step (follow, auth, or move on) |
HTTPServer[...] | Raw server banner | Note it, then confirm the version by hand |
Apache[2.4.41], jQuery[3.6.0] | Named tech + best-effort version guess | Treat the version as a lead, not a fact |
X-Powered-By[PHP/7.4], Cookies[...] | Framework or session leaked in a header | Often the real stack tell when the page looks generic |
Title[...] | The HTML <title> | Fast context for what the page is |
RedirectLocation[...] | Where a 3xx points | Chase it with --follow-redirect=always |
IP[...], Country[...] | Resolved address and GeoIP guess | Sanity-check you are hitting the right host |
A sparse result is not an empty target: a stripped banner or a proxy can hide the stack, so still test by hand.
Troubleshooting#
| Problem | Cause | Fix |
|---|---|---|
command not found | Not installed / stale PATH | Reinstall; open a fresh shell; or run ./whatweb from a clone |
No address associated with hostname | DNS cannot resolve the target | Add the lab host to /etc/hosts, or use the IP with -H 'Host:' |
Connection refused | Wrong port or service down | Confirm the web port with Nmap first |
| Hangs or very slow | High aggression or a slow host | Drop to -a 1; raise --open-timeout/--read-timeout |
Only a http:// scan, never 443 | Bare host defaults to http:// | Pass the full https://DOMAIN/ |
| Empty or one-line result | Banner stripped or proxy in front | Add -v, follow redirects, test the app manually |
| TLS/SSL handshake error | Old protocol or bad certificate | Try the http:// URL, or update WhatWeb/Ruby |
| Floods of error lines on a range | Dead hosts in the sweep | Add --no-errors |
Gotchas#
- A bracketed version is pattern-matched, never queried. Banners can be stripped or spoofed, so never start version-specific research on a WhatWeb guess alone; confirm it with
curlor the app itself. - A bare host is always
http://.whatweb DOMAINnever touches port 443, so give the fullhttps://DOMAIN/when you mean TLS. - Default aggression is level 1. A plain scan follows redirects but skips the confirmation probes that reveal versions; add
-a 3when a hit looks thin, but expect more log noise. - The default User-Agent announces WhatWeb. It lands in access logs and trips scanner signatures; set
-Uto a realistic string whenever the footprint matters. -a 4(heavy) requests known paths and files per plugin. That can tip over a fragile lab service and lights up a WAF, so reserve it for hosts you are sure can take it.- Same app, different vhost. The bare IP and a
Host:-targeted name can fingerprint as two different stacks; always try the real hostname before calling a target bland.
Pairs with#
Run nmap first to find which hosts have web ports open, then WhatWeb reads the stack on each. gobuster, ffuf, and feroxbuster take over for directory and vhost discovery once you know the tech. Use curl to confirm by hand what a plugin reported, and --proxy into Burp or ZAP to test the app interactively. For friendlier browser-side fingerprinting reach for Wappalyzer; for detection at huge scale httpx is faster but shallower; for known-issue and misconfiguration checks (not quiet fingerprinting) nikto overlaps but is far noisier.