Pentest Methodology & Recon · beginner · ~11 min
**What you will learn** - Read a WHOIS record and pull out the useful facts: registrant organization, name servers, and key dates. - Enumerate the core DNS record types (A/AAAA, MX, NS, TXT, CNAME) with `dig` and `host`, and explain what each one tells you about a target's footprint. - Discover subdomains **passively** using Certificate Transparency logs, and understand why active DNS brute force is a different, noisier technique. - Separate passive recon (querying third-party datasets) from active recon (sending packets to the target's own resolvers). - Apply the rule *found ≠ in scope*, and keep a defender's view: know which of these lookups a target can and cannot see in its logs.
Security objective: the asset you are mapping is an organization's external attack surface — every host, mail server, and subdomain that faces the internet. The threat is that attackers enumerate this footprint (often silently, from public data) and find forgotten or under-protected systems: an old staging box, an exposed admin panel, a stale VPN endpoint. In this lesson you learn to build that same map the way an authorized tester or a defender would, so you can detect exposed assets and reduce the surface before an attacker exploits it.
This lesson builds directly on your two prerequisites. From Passive vs active reconnaissance you already know the key distinction: passive recon touches only third-party data and leaves no trace on the target, while active recon sends packets the target can log. DNS and WHOIS recon straddles that line — WHOIS and Certificate Transparency are passive, but DNS brute force is active. From DNS: how names become addresses you know that a domain name resolves through a hierarchy of records (A, MX, NS, and so on); here you turn that lookup process into a mapping tool.
WHOIS tells you who owns a domain and where its DNS lives. A DNS record sweep tells you what services the domain runs. Certificate Transparency and (in a lab) DNS brute force reveal the subdomains where most of the real attack surface hides. Together they give you a footprint of the target without a single exploit.
In authorized professional work — a penetration test, a red-team engagement, or an attack-surface-management program — recon is where the engagement lives or dies. A tester who maps the footprint well finds the forgotten staging. box that the developers never patched; a tester who skips it spends the week poking at the hardened front door while the side gate stands open.
Several realities make DNS and WHOIS recon high-value:
internal-billing.example.com has effectively announced that hostname to the world — whether they meant to or not.The professional discipline here is scope. Finding an asset is not permission to test it. A good report maps everything but attacks only what the rules of engagement authorize.
Each concept below is taught on its own: what it is, how it works, when it applies, and a pitfall.
Definition. WHOIS is a query/response protocol (and the databases behind it) that returns the registration record for a domain name or an IP address block.
Plain explanation. When someone registers example.com, the registrar records who registered it, when, when it expires, and which name servers are authoritative for it. WHOIS lets you read (parts of) that record.
How it works. A WHOIS client connects to the appropriate registry/registrar WHOIS server and asks about a name. For IP blocks the answer comes from a Regional Internet Registry (ARIN, RIPE, APNIC, etc.). Useful fields include the registrant organization, name servers, and creation/expiry dates.
When / when not. Use WHOIS to link related assets (same org, same name servers) and to spot soon-to-expire or recently-registered domains. Do not rely on contact details — since GDPR and registrar privacy services, most personal fields are redacted or replaced with a proxy.
Pitfall. WHOIS output format varies by registry and is not machine-standard; a field present for one TLD may be absent for another. Never assume redacted means "no owner" — it usually just means privacy protection.
Definition. Systematically querying the main DNS record types for a domain to inventory its services.
Plain explanation. DNS is not just name-to-IP. Different record types describe different services, and reading them tells you what the domain does.
How it works. You ask a resolver for each record type. The important ones:
| Record | Meaning | What it reveals |
|---|---|---|
A / AAAA |
Hostname to IPv4 / IPv6 address | Where a host actually lives |
MX |
Mail exchangers | Email provider / on-prem mail servers |
NS |
Name servers | Who runs the domain's DNS (ties to WHOIS) |
TXT |
Free-text records | SPF, DKIM, domain-verification tokens, tech hints |
CNAME |
Alias to another name | Third-party services, cloud fronting |
When / when not. Always sweep these early; they are cheap and high-signal. Note that querying a public resolver (like 1.1.1.1 or 8.8.8.8) for cached records is effectively passive, while querying the target's own authoritative name server is active.
Pitfall. TXT records often leak which SaaS products an org uses (verification tokens for various vendors). That is intel, but do not treat a verification token as a secret to exploit — it is just a hint.
Definition. Certificate Transparency (CT) is a public, append-only logging system for TLS certificates. Every certificate a trusted Certificate Authority issues is recorded in public logs.
Plain explanation. To be trusted by browsers, a certificate must be logged. Each log entry lists the certificate's hostnames, including every Subject Alternative Name (SAN — the extra hostnames one certificate covers). Search those logs and you get a list of hostnames the organization has requested certificates for — a rich subdomain source, gathered without touching the target.
How it works. You query a CT search front-end (a common one is crt.sh) for a domain and read back the certificates and their SANs. Because the data lives in third-party logs, the target sees nothing.
When / when not. This is the first place to look for subdomains — it is free, fast, and passive. It will not find hosts that never got a publicly trusted certificate (internal-only names, or hosts using self-signed or private-CA certs).
Pitfall. CT shows names a cert was issued for; some of those hosts may no longer resolve or may be decommissioned. Always confirm a name resolves before treating it as live — and remember confirming it resolves is an active DNS query.
Definition. Guessing subdomain names from a wordlist and querying each to see which resolve.
Plain explanation. You take a list of common prefixes (dev, vpn, admin, staging, mail, ...), prepend each to the domain, and ask DNS whether it exists.
How it works. Each guess is a real DNS query. Names that return an answer exist; names that return NXDOMAIN do not. Because you are sending real queries — often thousands — this is active and can appear in the target's DNS logs.
When / when not. Use it in an authorized engagement to find hosts CT missed. Do not run it against systems you are not authorized to test; a large brute-force sweep is noisy and, against infrastructure you do not own, may be unwelcome or unlawful.
Pitfall. Wildcard DNS (where *.example.com resolves to one IP) makes every guess "succeed" and floods you with false positives. Detect a wildcard first by querying a random, definitely-nonexistent name.
Definition. Scope is the explicit set of assets your authorization covers.
Plain explanation. Recon will surface assets that belong to the target but are not in your rules of engagement — a partner's domain, a cloud tenant, a subsidiary. Mapping them is fine; testing them is not.
Pitfall. It is easy to follow a CNAME or a WHOIS link straight out of scope without noticing. Keep an explicit in-scope list and check every discovered host against it before any active testing.
THREAT MODEL — external footprint mapping
PUBLIC / THIRD-PARTY DATA TARGET-OWNED INFRA
(passive: target sees nothing) (active: target CAN log queries)
+-----------------------------+ +----------------------------+
| WHOIS registry servers | | Target authoritative NS |
| Certificate Transparency | | Target-facing resolvers |
| logs (e.g. crt.sh) | | Web / mail / VPN hosts |
| Public resolver caches | | |
+--------------+--------------+ +-------------+--------------+
| |
read public records DNS brute force / direct
(no packets to target) queries = real packets
| |
v v
=================== TRUST BOUNDARY ==============================
Passive side leaves no trace on target.
Active side crosses the boundary: queries can appear in target logs.
ASSET PROTECTED : the org's external attack surface (every exposed host)
ENTRY POINTS : public logs (passive) + target DNS/services (active)
INSECURE ASSUMPTION an org makes: "if we never linked it, nobody knows."
CT logs and WHOIS break that assumption.
Knowledge check
example.com, versus running a 5,000-word subdomain brute force against example.com's name server? Which one can the target detect in its logs?staging.example.com sit exposed for months, and which passive source most reliably exposes it anyway?The core tools are whois, dig, and host. All are read-only lookups; the only active one against a target is a direct/brute-force DNS query. Everything below is lab-safe — use example.com (an IANA-reserved documentation domain) or a domain you own.
# WHOIS: registration record for a domain
whois example.com
# -> registrar, name servers (NS), creation/expiry dates
# dig: query a specific DNS record type
dig +short example.com A # IPv4 address(es)
dig +short example.com MX # mail servers
dig +short example.com NS # authoritative name servers
dig +short example.com TXT # SPF / verification / hints
# Choose which resolver answers you:
dig @1.1.1.1 +short example.com A # a PUBLIC resolver's cache = passive-ish
# (no @ => your system's default resolver)
# host: a terser front-end for the same queries
host -t MX example.com
# Detect wildcard DNS BEFORE any brute force:
dig +short definitely-not-a-real-host-9f3z.example.com A
# an answer here = wildcard; brute-force results will be false positives
Annotations: +short trims dig's verbose output to just the answer. -t <TYPE> on host selects the record type. @<resolver> picks which DNS server answers — a public resolver reads from its shared cache (low target visibility), while omitting @ or aiming at the target's own name servers sends queries the target can see.
DNS and registration data are the richest sources of passive recon. They map an organization's footprint without touching its servers.
WHOIS returns the registration record for a domain or IP block. It can include:
This tells you who owns what, and often points at related assets.
Enumerate the main record types:
A / AAAA — hosts (IPv4 / IPv6 addresses)MX — mail serversNS — name serversTXT — SPF records, domain verifications, and other technology hintsCNAME — aliases that point one name at anotherUseful tools: dig, nslookup, host.
Most attack surface hides in subdomains — for example dev., vpn., admin., staging..
Ways to find them:
Discovering a subdomain does not put it in scope. Map everything, but only test what your authorization covers.
This example shows the INSECURE → SECURE → VERIFY shape from a defender's seat. The "insecure" artifact is not attack code — it is a naive subdomain-discovery script that an org might run against itself but that behaves badly (no wildcard check, no scope check), producing false intel and hammering a resolver. We then harden it and verify it rejects bad input.
#!/usr/bin/env bash
# INSECURE naive subdomain check. Problems:
# - no wildcard detection => every guess looks "found"
# - no scope allow-list => will happily probe anything
# - no rate limiting / no logging of what it did
DOMAIN="$1"
for sub in dev vpn admin staging mail; do
if dig +short "$sub.$DOMAIN" A | grep -q .; then
echo "FOUND: $sub.$DOMAIN"
fi
done
Run against a wildcard domain and it prints all five "FOUND" — useless, and it queried a name server with no record of why.
#!/usr/bin/env bash
set -euo pipefail
DOMAIN="${1:-}"
SCOPE_FILE="${2:-scope.txt}" # newline-separated list of IN-SCOPE domains
LOG="recon.log"
[ -n "$DOMAIN" ] || { echo "usage: $0 <domain> <scope-file>" >&2; exit 2; }
# --- Scope gate: refuse anything not explicitly authorized ---
if ! grep -qxF "$DOMAIN" "$SCOPE_FILE"; then
echo "REFUSED: $DOMAIN is not in $SCOPE_FILE (found != in scope)" >&2
exit 3
fi
# --- Wildcard detection: query a random name that cannot exist ---
RAND="zzz-$RANDOM$RANDOM-nope"
WILDCARD_IP="$(dig +short "$RAND.$DOMAIN" A | head -n1 || true)"
if [ -n "$WILDCARD_IP" ]; then
echo "NOTE: wildcard DNS detected ($WILDCARD_IP); filtering it out" >&2
fi
log() { printf '%s\tsrc=%s\tresource=%s\tresult=%s\n' \
"$(date -u +%FT%TZ)" "$(id -un)" "$1" "$2" >> "$LOG"; }
for sub in dev vpn admin staging mail; do
host="$sub.$DOMAIN"
ip="$(dig +short "$host" A | head -n1 || true)"
if [ -n "$ip" ] && [ "$ip" != "$WILDCARD_IP" ]; then
echo "FOUND: $host -> $ip"
log "$host" "found:$ip"
else
log "$host" "none"
fi
sleep 0.5 # gentle rate limit
done
# Setup a scope file with ONLY a domain you own or the reserved example.com
printf 'example.com\n' > scope.txt
# ACCEPTS good input: in-scope domain runs and logs
./recon.sh example.com scope.txt
tail recon.log # every host queried is recorded with a UTC timestamp
# REJECTS bad input: out-of-scope domain is refused, exit code 3
./recon.sh not-my-domain.test scope.txt; echo "exit=$?"
# expected: 'REFUSED ...' on stderr, exit=3, and recon.log unchanged
# REJECTS wildcard false positives: point it at a wildcard test domain
# (use a lab domain you control with *.lab configured); the NOTE line
# appears and wildcard-matching hosts are filtered from FOUND output
Expected behavior. The secure script refuses any domain not listed in scope.txt (exit 3, nothing logged), announces and filters wildcard DNS so it stops printing phantom subdomains, records every query in recon.log with a UTC timestamp and the resource/result, and paces itself with a short sleep. The insecure script does none of this.
Walking through the SECURE script:
| Step | Line(s) | What happens | Why it matters |
|---|---|---|---|
| Fail-fast shell | set -euo pipefail |
Abort on any error, unset variable, or failed pipe stage | Stops a half-broken run from producing misleading "results" |
| Read arguments | DOMAIN=..., SCOPE_FILE=... |
Target and the authorized-scope file are inputs, not hard-coded | Forces the operator to name what they are allowed to test |
| Usage guard | [ -n "$DOMAIN" ] || { ...; exit 2; } |
Empty domain -> print usage, exit 2 | Prevents accidental empty/* queries |
| Scope gate | grep -qxF "$DOMAIN" "$SCOPE_FILE" |
Exact, whole-line, fixed-string match against the allow-list; refuse (exit 3) if absent | Enforces found ≠ in scope in code, not just in the tester's head |
| Wildcard probe | RAND=...; dig +short "$RAND.$DOMAIN" A |
Query a name that cannot legitimately exist | If it resolves, the domain has wildcard DNS |
| Capture wildcard IP | WILDCARD_IP=... |
Store whatever the wildcard returns | Used later to filter phantom "hits" |
| Logging helper | log() { printf ... >> "$LOG"; } |
Append UTC timestamp, source user, resource, result | Creates an audit trail of exactly what was queried and when |
| Enumeration loop | for sub in ...; do |
For each candidate prefix, query the A record | The actual (active) discovery step |
| Filter + report | if [ -n "$ip" ] && [ "$ip" != "$WILDCARD_IP" ] |
Report only real, non-wildcard answers | Removes the false positives the insecure version printed |
| Rate limit | sleep 0.5 |
Pause between queries | Reduces load and log-flooding on the resolver |
How the values change on a wildcard domain: WILDCARD_IP becomes, say, 203.0.113.9. When the loop queries admin.example.com, dig returns that same 203.0.113.9. The condition [ "$ip" != "$WILDCARD_IP" ] is false, so the host is not reported — exactly the false positive the insecure script wrongly announced. On a non-wildcard domain, WILDCARD_IP is empty, the second condition is always true, and only genuinely resolving hosts print.
Real mistakes and how to fix them:
1. Treating WHOIS contact fields as reliable.
2. Brute forcing without checking for wildcard DNS.
3. Confusing passive and active — and getting noisy against a target.
4. Testing what you found instead of what is in scope.
partner-portal.example-vendor.com via a CNAME and probing it.5. Thinking decoding is the same as verifying.
Common failures and how to work through them:
dig returns nothing / empty output. Check the record type actually exists (dig example.com ANY is often filtered; query specific types). Confirm your resolver works: dig @1.1.1.1 +short example.com A. An empty answer for MX may simply mean no mail is configured, not an error.whois output looks truncated or wrong. Different TLDs use different WHOIS servers; some registrars rate-limit or return thin records. Try again after a pause, or query the registry's WHOIS server directly. Redacted fields are expected, not a bug.dig +short zzz-nope-$RANDOM.example.com A); if it answers, filter that IP out.NXDOMAIN for a name CT swears exists. The certificate was issued but the host may be decommissioned or internal-only. This is normal — CT proves issuance, not current liveness.set -euo pipefail, an unset variable or failed command aborts early. Run with bash -x ./recon.sh ... to trace which line exited.Questions to ask when it fails: Which resolver answered — a public cache or the target's authoritative NS? Is there a wildcard? Is the record type right? Is the name actually in scope? Am I being rate-limited?
Security & safety — detection and logging.
This lesson is concept-track, so the safety focus is the evidence trail, not memory.
What to log (as the secure script does):
date -u +%FT%TZ).What to NEVER log: any secret you happen to encounter — API keys or verification secrets seen in TXT records, session cookies, tokens, private keys, passwords, or unneeded personal data from WHOIS. Recon logs are working notes and often get shared; keep them free of anything sensitive. Use placeholders like API_KEY=<development-placeholder> in examples.
Which events signal abuse (from the defender's side): a spike of NXDOMAIN responses from one source is the classic signature of subdomain brute force; sudden WHOIS or CT-monitoring interest in a domain can precede an engagement (authorized) or an attack (not). Defenders watch authoritative-DNS query logs for these patterns.
How false positives arise: legitimate tools, uptime monitors, and search-engine crawlers also generate DNS queries, so not every NXDOMAIN burst is hostile. Wildcard DNS produces false "discoveries" on the attacker side; shared CDNs and load balancers make many distinct names share one IP, which can look like duplication.
Why lab-only. Run active DNS queries and any brute force only against domains you own or are explicitly authorized to test (localhost, a lab domain, an intentionally-vulnerable VM, or a CTF). Passive CT/WHOIS lookups of a domain are generally low-risk, but active queries against someone else's infrastructure without authorization can be unlawful and is out of bounds.
Authorized real-world use case. An attack-surface-management (ASM) program at a mid-size company runs continuous, passive recon on its own domains: it monitors Certificate Transparency logs for newly issued certs, sweeps DNS records nightly, and diffs the results. When a team spins up beta-checkout.company.com and requests a TLS cert, the CT monitor flags the new host within minutes, and security confirms it is patched and in inventory before it is ever attacked. This is the same technique an attacker would use — turned inward for defense.
Professional best-practice habits
Beginner vs advanced
| Beginner | Advanced | |
|---|---|---|
| Sources | whois, dig, crt.sh by hand |
Automated CT feeds, passive-DNS datasets, DNS diffing over time |
| Subdomains | small wordlist in a lab | wildcard-aware, permutation-aware discovery with careful scoping |
| Output | a list of hosts | a validated, in-scope, deduplicated attack-surface inventory with provenance |
| Mindset | "what exists?" | "what is exposed, changing, and unowned — and is it authorized?" |
All tasks are lab-only. Use example.com (IANA-reserved for documentation), a domain you personally own, or a lab you control. Each security task ends by remediating and verifying, not exploiting.
Beginner 1 — Read a WHOIS record.
whois example.com; identify the name servers, the registrar, and the creation/expiry dates.Name Server, Registrar, Creation Date.Beginner 2 — DNS record sweep.
dig +short, collect the A, MX, NS, and TXT records for a domain you own or example.com.@1.1.1.1 to keep it low-impact.MX answer means no mail is configured, not an error.Intermediate 1 — Passive subdomain harvest from Certificate Transparency.
issued (from CT) and, once you check, resolves or no-resolve.Intermediate 2 — Wildcard-safe verification.
*.lab -> one IP), run a small subdomain check and show it correctly filters the wildcard.Challenge — Scope-gated recon tool with an audit trail (defensive).
scope.txt allow-list, (b) detects and filters wildcard DNS, (c) logs every query with a UTC timestamp and result, and (d) redacts anything that looks like a secret before writing the log.scope.txt? Am I on my own lab/localhost? Have I set a gentle rate limit?recon.log, remove any wildcard test records you created, and clear scope.txt so the tool defaults to refusing everything.Main concepts. WHOIS reveals ownership, name servers, and key dates. A DNS record sweep (A/AAAA, MX, NS, TXT, CNAME) inventories a domain's services. Certificate Transparency is a passive goldmine of subdomains because every publicly trusted cert is logged with all its hostnames. DNS brute force finds more subdomains but is active — it sends real, loggable queries. Subdomains hold most of the real attack surface (staging, admin, VPN).
Key syntax/commands. whois <domain>; dig +short <domain> <TYPE>; dig @<resolver> ... to choose passive-ish vs active; host -t <TYPE> <domain>; probe a random impossible name to detect wildcard DNS.
Common mistakes. Trusting redacted WHOIS contacts; brute forcing without a wildcard check; assuming all DNS recon is passive; testing assets you found but are not in scope; confusing "a cert was issued" (or "I decoded a value") with "the host is live and verified."
What to remember. Passive first (CT, WHOIS), active only within authorized scope. Default to refuse. Log what you query — never log secrets. Found ≠ in scope, and issued ≠ live. Nothing here proves a system is "secure"; recon just maps what is exposed so you can reduce it.