Recon Part 3: Content Discovery and Attack Surface

Part 1 built a silent map. Part 2 made it live: you know which hosts answer, where they point, what ports are open, and what they run. But a live host is still not a place to hunt. The bug is rarely on the homepage. It is on the hidden admin panel, the forgotten API endpoint, the parameter nobody validates, the secret left in a JavaScript file. Part 3 is where you find those, and where the whole recon block pays off by turning the map into a ranked list of exactly where to start hunting.
This closes the three part recon block:
- Part 1: passive recon and subdomain enumeration
- Part 2: live hosts, DNS, port scanning, fingerprinting
- Part 3, today: content discovery, parameter mining, JavaScript secrets, attack surface prioritization
Everything here is active, so it stays inside scope. Content discovery sends many requests to the target, so respect rate limits and any scanning rules the program sets.
Content discovery: finding the hidden paths
A web server serves far more than it links to. Old admin panels, backup files, config files, API documentation, test endpoints, all sit at paths you have to guess. Content discovery is guessing them systematically with a wordlist.
Directory and file bruteforcing with ffuf:
# fuzz paths on a host using a wordlist; FUZZ is the injection point
ffuf -u https://target.example.com/FUZZ \
-w /path/to/wordlist.txt \
-mc 200,201,301,302,401,403 \
-o ffuf_target.json
Flags that matter:
-u with FUZZ marks where each word is inserted
-w is your wordlist, the quality of this decides your results
-mc 200,201,301,302,401,403 matches these status codes, note 401 and 403 are included on purpose, a forbidden path is a found path, often the most interesting
-o saves results
Wordlists matter more than the tool. The standard starting set is SecLists. For a first pass use a common paths list, then escalate to larger ones on hosts that look promising:
# clone the standard wordlist collection once
git clone https://github.com/danielmiessler/SecLists.git
# good general starting wordlist:
# SecLists/Discovery/Web-Content/raft-medium-directories.txt
Filter the noise. Many hosts return 200 for everything, a soft 404. If results look uniform, filter by response size or word count instead of status:
# filter out the common false-positive size (replace 1234 with the noise size)
ffuf -u https://target.example.com/FUZZ -w wordlist.txt -fs 1234
Interesting hits: anything with admin, backup, config, .git, api, debug, test, old, or dev in the path.
JavaScript recon: the richest source
Modern web apps put enormous logic in JavaScript, and that JS reveals API endpoints, internal paths, parameter names, and sometimes hardcoded secrets. You pulled a js_files.txt back in Part 1. Now you rip it apart.
Extract endpoints from JS files:
# download all JS files
mkdir -p js && cd js
while read url; do
wget -q "$url" 2>/dev/null
done < ../js_files.txt
cd ..
# pull URL-like and path-like strings out of them
grep -rohE '"(/[a-zA-Z0-9_/.-]+)"' js/ | tr -d '"' | sort -u > js_endpoints.txt
grep -rohE 'https?://[a-zA-Z0-9._/-]+' js/ | sort -u >> js_endpoints.txt
sort -u js_endpoints.txt -o js_endpoints.txt
wc -l js_endpoints.txt
Hunt for secrets in JS. Developers leak API keys, tokens, and internal URLs in frontend code:
# grep for common secret patterns
grep -roiE '(api[_-]?key|secret|token|password|aws_access|bearer)[^,}"]{0,40}' js/ | sort -u
Any live key here is often a direct finding. Even if the key is dead, the names and internal URLs expand your map.
Mine parameter names from JS and historical URLs. Hidden parameters are where injection, IDOR, and logic bugs hide:
# extract likely parameter names from JS
grep -rohE '[?&][a-zA-Z0-9_]+=' js/ | tr -d '?&=' | sort -u > params.txt
Parameter discovery on live endpoints
Beyond what JS reveals, you can actively discover parameters an endpoint accepts but does not advertise.
Fuzz for hidden parameters with ffuf or a dedicated tool:
# test which parameter names an endpoint actually responds to differently
ffuf -u "https://target.example.com/api/user?FUZZ=test" \
-w params.txt \
-fs 0
A parameter that changes the response when the others do not is a parameter the developer handles, which means it is a parameter you can test for IDOR, injection, and access control bugs in the coming weeks.
Putting it together: the attack surface map
Now you assemble everything into the artifact that actually drives hunting. Your target folder is complete:
target/
scope.txt
all_subs.txt # Part 1
live_hosts.txt # Part 2
interesting.txt # Part 2
cnames.txt # Part 2 (takeover leads)
nmap_deep.* # Part 2
ffuf_*.json # Part 3 hidden paths
js_endpoints.txt # Part 3 endpoints from JS
params.txt # Part 3 parameter names
attack_surface.md # Part 3 the ranked hunting list
Build attack_surface.md: the ranked list. This is the deliverable of all three parts. For each promising target, write what it is and why it is worth testing, ranked by how likely a bug is:
Attack Surface, ranked
High priority
staging.example.com/admin -> 200, admin panel, no obvious auth, PHP
api.example.com/v1/users -> IDOR candidate, takes id param (from JS)
old.example.com -> Apache, outdated, directory listing on
Medium
cdn.example.com CNAME -> unclaimed S3 -> takeover candidate (verify)
api.example.com/debug -> 403, forbidden but present
Endpoints to test (from JS)
/api/v1/account/export
/internal/report
…
How to rank. Prioritize by three signals:
- Forgotten. Old, staging, dev, acquired infrastructure gets the least defensive attention.
- Sensitive function. Anything touching auth, payments, user data, file upload, or admin.
- Attack surface richness. Endpoints with many parameters, file uploads, or complex logic have more to go wrong.
The host that is forgotten, handles sensitive data, and exposes many parameters is where you start. That ranked list is the entire point of recon. Everything from Day 1 Part 1 to here existed to produce it.
The mindset payoff
Three parts of recon and you have not exploited a single bug, and that is correct. You have built something most hunters never build: a complete, prioritized map of a target, from passive subdomain to ranked endpoint. When the series moves into actual vulnerability classes, you will not be wandering a homepage like everyone else. You will be working down a list of forgotten, sensitive, parameter rich endpoints that you found and others did not.
That is the edge. Recon is not the boring part before hacking. Recon is the part that decides whether you find anything at all.
Tools to install for Part 3
# ffuf for fuzzing
go install github.com/ffuf/ffuf/v2@latest
# wordlists
git clone https://github.com/danielmiessler/SecLists.git
# wget, grep, sort already present on most systems
Homework for Part 3
- Pick your top three hosts from Part 2’s
interesting.txt. Confirm scanning is in scope.
- Run ffuf content discovery on each with a medium wordlist, matching 200, 301, 401, 403. Note every admin, config, backup, api, or debug hit.
- Download your JS files, extract endpoints, parameter names, and grep for secrets. Fold the endpoints into your map.
- Fuzz one API endpoint for hidden parameters.
- Build
attack_surface.md: a ranked list of every target worth testing, with one line each on what it is and why it ranks where it does.
By the end you have the complete recon artifact for a target, a ranked attack surface map built from passive enumeration all the way to hidden endpoints. That map is what the rest of the series hunts on.
Day 4 begins actual vulnerability hunting. We take the first and most beginner friendly high value class, IDOR, Insecure Direct Object Reference, and point it at the parameter rich endpoints your recon just surfaced, with a real disclosed report broken down end to end.