PEN-200 Series, Part 2: Passive and Active Information Gathering
What you can learn without sending a single packet, what leaks through HTTP headers, a verified nmap service fingerprint against a real target, and a live recon example run against eresus-ctf-lab.
PEN-200 Series, Part 2: Passive and Active Information Gathering
The series plan is in the OSCP+ preparation guide; Part 1 covered note-taking and report writing. Now the module where your notes actually start filling up: information gathering.
PEN-200 splits this into passive (never touching the target) and active (talking to it directly). The split isn't cosmetic — what you learn passively decides which ports you scan first, in what order, and how loud you're willing to be during the active phase.
Passive: without sending a single packet
WHOIS
Domain registration data: registration date, registrar, sometimes name servers. Older WHOIS records can leak a real employee's name through a technical contact email — useful for social engineering or username guessing later.
whois target-domain.comSearch engine dorks
site:, filetype:, and inurl: find pages that are indexed but never linked from the target's own navigation:
site:target.com filetype:pdf
site:target.com inurl:admin
site:target.com "index of /"Netcraft and certificate transparency
Netcraft shows a site's hosting history and technology stack. Certificate transparency logs (crt.sh) are the real find: every TLS certificate ever issued for a target, which routinely surfaces subdomains like staging., dev., or internal- that were never announced anywhere else.
curl -s "https://crt.sh/?q=target.com&output=json" | jq -r '.[].name_value' | sort -u(Many restricted or corporate networks — including the sandbox this
series is written in — block outbound access to crt.sh specifically. If
that command hangs or the connection is refused, that's the network, not
the syntax; confirm with curl -v before assuming the technique doesn't
work.) The CT log approach beats brute-forcing subdomains because it only
ever returns names that genuinely had a certificate issued — no
wordlist, no false negatives from a list that didn't happen to contain
the right word.
DNS zone transfer (AXFR) — worth trying, rarely open
A misconfigured name server will hand you its entire zone file — every record it holds — to anyone who asks:
dig axfr @ns1.target.com target.comCorrectly configured DNS restricts AXFR to secondary name servers only,
so most attempts return Transfer failed or time out. That's not a
reason to skip it — the configuration mistake is common enough that
checking takes one command, and PEN-200's own module calls this out
explicitly as a step worth never skipping, precisely because it's free
when it fails and total when it doesn't.
Shodan
A search engine over internet-facing services, their banners, and usually their version strings. If you know the target's IP range, Shodan has already scanned it for you — no packets from your own machine required.
Security headers and TLS
This one you can verify right now, against a real site — it's entirely passive, a single ordinary HTTP request:
$ curl -sI https://anthropic.com
HTTP/1.1 200 Connection Established
HTTP/2 301
content-security-policy: default-src 'self'; script-src 'self' 'unsafe-inline' ...
strict-transport-security: max-age=3600
server: cloudflareserver and x-powered-by leak the stack. A missing content-security-policy (or a loose one with unsafe-inline) answers "why does this matter" the moment you later write up an XSS finding. A missing strict-transport-security is its own finding, no further digging required.
Active: talking to the target
From here, every example is run against my own eresus-ctf-lab repo — a target I own and control.
DNS enumeration
$ dig A github.com +short
140.82.114.4An A record resolves everywhere; MX, TXT, and NS queries get filtered on some networks. Verify what your own environment allows before exam night, not during it. Check every subdomain you find at both the DNS and HTTP layer — some exist in DNS with nothing behind them, and some respond over HTTP via virtual-host routing without ever showing up in DNS at all.
Port scanning
Fast and wide first, across every port; a detailed scan only on what's open. Order matters: running -sV across all 65535 ports is slow and needlessly loud.
$ nmap -Pn -sT -p 8080,8081 127.0.0.1
PORT STATE SERVICE
8080/tcp open http-proxy
8081/tcp open blackice-icecap
$ nmap -Pn -sT -sV -p 8080 127.0.0.1
PORT STATE SERVICE VERSION
8080/tcp open http Node.js Express framework-sV correctly fingerprinted what's actually running (Node.js/Express) in the second scan — verify this yourself by running eresus-ctf-lab with npm start and the same command.
The detail that matters here: I'm scanning the lab from the same machine it's running on, which is why 8081 (the internal service) shows up at all. From a different machine, that port would never appear — it's bound to 127.0.0.1, closed to the outside. The NoSQL injection series' SSRF section exploits exactly this gap: reaching a service that isn't externally reachable by making the server itself act as the proxy.
NSE: nmap's scripting engine
-sC runs nmap's default script set — a curated, low-risk subset of the
full NSE library (the default and safe categories; nmap also ships
vuln, exploit, brute, dos, and others you opt into explicitly,
and --script-help <name> shows which category any script belongs to
and exactly what it checks). Against the lab, three scripts fired
automatically and all three told us something real:
$ nmap -Pn -sT -sC -sV -p 8080 127.0.0.1
PORT STATE SERVICE VERSION
8080/tcp open http Node.js Express framework
|_http-title: Eresus Internal Portal
| http-robots.txt: 2 disallowed entries
|_/api/legacy/ /internal/
|_http-open-proxy: Proxy might be redirecting requestshttp-title and http-robots.txt are exactly what they sound like —
and note that http-robots.txt did the recon from the earlier section
for you, automatically, as a side effect of a routine -sC scan.
http-open-proxy is more interesting: it's a false positive. The lab
isn't an open proxy; the script's heuristic (send a request that looks
like a proxy request, see if the response looks forwarded) got tripped
up by something else in how Express responds. This is normal and
important to internalize early: NSE scripts are heuristics, not ground
truth. Every flagged result needs a manual check before it goes in a
report — confirming (or ruling out) http-open-proxy here takes one
manual curl through the "proxy" to see it doesn't actually forward
anywhere.
For a known CVE against a fingerprinted service, the vuln category is
the next step, run deliberately and separately from the default scan
because some of its scripts are intrusive enough to crash a fragile
service:
nmap -Pn -p 8080 --script vuln 127.0.0.1Content discovery: default scans miss POST-only routes
This is the part that catches people who treat content-discovery tools
as infallible. gobuster, ffuf, feroxbuster, and friends default to
GET requests. A route that only responds to POST is invisible to a
default scan — even with the exact correct path in your wordlist:
$ curl -s -o /dev/null -w "%{http_code}\n" localhost:8080/api/legacy/v1/session
404
$ echo -n "legacy/v1/session" > exact.txt
$ gobuster dir -u http://127.0.0.1:8080/api -w exact.txt -q
# (no output — gobuster's default GET request 404s, same as curl above)
$ curl -s -o /dev/null -w "%{http_code}\n" -X POST localhost:8080/api/legacy/v1/session \
-H 'Content-Type: application/json' -d '{}'
400Same exact path, two different HTTP methods, two different results. The
route is real — 400 means it received the request and rejected the
body, not that it doesn't exist — but a GET-only brute force reports it
as a miss. This is also why the robots.txt leak from the passive
section mattered more here than brute-forcing: it told you the path
and that it belonged to a legacy session API, which is enough to guess
POST is worth trying even before you've confirmed the method any other
way. When a content-discovery scan comes back emptier than you expected
on a target that uses a JSON API, that's the first thing to check —
rerun with -m POST (or your tool's equivalent) before concluding
nothing is there.
A second gap worth knowing: a flat wordlist of single segments
(admin, api, internal, legacy, backup) found nothing at all
against the bare root of this app, because every real route here is
nested two or three segments deep (/api/legacy/v1/session,
/internal/healthz). Flat wordlists find flat applications; a modern
API needs either a wordlist built from the application's own naming
conventions (framework defaults, the client-side JS bundle's route
strings, API documentation left exposed) or a recursive scan that brute
forces one segment, then brute forces again inside whatever it found.
SMB, SMTP, SNMP enumeration
The rest of PEN-200's active information gathering module. Standard syntax:
# SMB — shares, logon policy, OS version
smbclient -N -L //$TARGET
enum4linux-ng -A $TARGET
# SMTP — username validation (VRFY/EXPN still open on some servers)
nc $TARGET 25
VRFY root
# SNMP — often left open with the "public" community string
snmpwalk -v2c -c public $TARGETSNMP (161/udp) is especially valuable: when it's open, it often dumps every network interface, the routing table, and sometimes the running process list in plaintext — no exploit required at all.
Combining passive and active: an example from our own lab
eresus-ctf-lab's home page (passive — one HTTP request) hands you a support email:
$ curl -s localhost:8080/ | grep -A1 support@
Having trouble signing in? Contact
<a href="mailto:support@eresus.lab">support@eresus.lab</a>.robots.txt (also passive) points at two more directories:
$ curl -s localhost:8080/robots.txt
User-agent: *
Disallow: /api/legacy/
Disallow: /internal/Those two passive observations — a username hint (support) and a legacy endpoint path — are the starting point of the entire chain in NoSQL Injection, Part 1. The passive phase told you where to aim before the active phase discovered anything at all, which is exactly why PEN-200 teaches them as separate modules.
What goes in your notes
Per Part 1's template, this stage fills in the "Ports" and "Services" subsections under "Enumeration." Paste the raw nmap output verbatim, then add one line above it: which port led where. Someone reading your report six months later — or you, exhausted on exam night — should be able to rebuild your methodology from that one line alone.
Part 3 covers vulnerability scanning: systematically checking what each service you found might be vulnerable to, with Nessus and nmap's NSE scripting engine.
What do you think?
React to show your appreciation