Skip to content

We use analytics cookies to understand how the site is used and to improve it. Privacy policy

SubAnalyzer

Subdomain enumeration: 12 ways to find a domain's subdomains

Certificate logs, passive DNS, zone transfers, wordlists and more: 12 ways to find a domain's subdomains, with a command to try each one yourself

Updated (17 min read)

Subdomain enumeration is the work of listing the names that exist under a domain, such as mail.example.com or staging.example.com. Security teams do it to see what they expose, and attackers do it to find what was forgotten. No single method finds every name: some names are published, and others answer only when someone asks for them by name.

This guide covers 12 methods. Each section explains what a method finds, how to try it yourself with free tools, and how SubAnalyzer's subdomain finder uses it. The commands use example.com, so replace it with the domain you are checking.

MethodWhat it findsTry it with
1. Certificate Transparency logsNames on publicly trusted certificates, old ones includedTry it with crt.sh
2. Passive DNS datasetsNames seen in DNS answers over timeTry it with HackerTarget
3. Search enginesHosts with indexed public pagesTry it with site: searches
4. Web archivesHosts of archived pages, including gone onesTry it with Wayback Machine
5. The website itselfHosts its links, sitemaps and headers nameTry it with curl
6. DNS recordsNameservers, mail servers and service hostsTry it with dig
7. Zone transfersA copy of the zone, if a nameserver allows itTry it with dig AXFR
8. Zone walkingA zone's names, if its NSEC chain can be walkedTry it with ldns-walk
9. Wordlist brute forceCommon names that resolveTry it with puredns
10. Name variationsVariants of names already foundTry it with alterx
11. Certificates on live serversOther names a server's certificate coversTry it with openssl
12. Reverse DNSNames on nearby addressesTry it with dig -x

The methods differ in what they contact. Certificate logs, passive DNS, search engines and web archives are third-party sources, so the domain itself sees nothing. Reading the website makes a few ordinary web requests to it. The DNS methods send queries of their own, most through a recursive resolver and some straight to the domain's nameservers, and following live hosts means connecting to them. The rules differ by country, so use those on domains you own or have permission to test.

A recommended workflow

  1. Collect candidates from third-party sources: certificate logs, passive DNS, search engines and web archives.
  2. Read the website and the DNS records that name other hosts.
  3. Where you have permission, try a zone transfer and a zone walk, then a wordlist and name variations.
  4. Clean up the list: lowercase every name, strip any *. prefix, keep only names under the domain and remove duplicates. Then resolve each name and check for wildcards.
  5. Look at what the live hosts expose, and follow their certificates and reverse DNS to more names.
  6. Run it all again later and compare, since names come and go.

The commands run in a Unix shell, and most need only curl, jq, dig or openssl. The sections that need other tools link to them. The curl commands use -f, so a service that fails prints an error instead of an empty list. An empty answer can still be genuine: a small domain may have nothing in a source.

Passive enumeration: third-party sources

These sources have already collected names, so you ask them rather than the domain. In SubAnalyzer, certificate logs and passive DNS are part of the light scan.

Certificate Transparency logs

Certificate Transparency (CT) logs are public, append-only records of the TLS certificates that certificate authorities issue. Chrome rejects a publicly trusted certificate that was not logged, so nearly every certificate a public website uses ends up in them. Each certificate lists the names it was issued for, so a certificate for staging-admin.example.com reveals that name even if no page ever links to it.

To try it, search crt.sh, a public CT search run by Sectigo that needs no account. Searching for example.com lists the certificates of its subdomains too. This command keeps only names under the domain, lowercased and without a *. prefix, so a name such as notexample.com cannot slip in:

curl -sSf 'https://crt.sh/?q=example.com&output=json' | jq -r --arg d example.com '.[].name_value | split("\n")[] | ascii_downcase | ltrimstr("*.") | select(. == $d or endswith("." + $d))' | sort -u

The list includes expired certificates and names that no longer exist, so every name still needs checking. crt.sh often times out or answers with an error on domains with many certificates, and it can lag days behind the logs themselves.

SubAnalyzer reads CT logs itself and keeps its own index of the names in them, expired certificates included, along with archives of older logs that have since shut down.

CT has two gaps. A wildcard certificate such as *.example.com shows the pattern, not the hosts it covers. Certificates from a private certificate authority, such as one a company runs for internal hosts, are generally absent from the public logs. Those names need to be found another way.

A certificate lists the names it was issued for, and a publicly trusted one is published in CT logs. The day staging-admin.example.com gets a certificate, anyone reading the logs can see the name, and so can the light scan. A wildcard entry such as *.example.com would show only the pattern, not the hosts it covers.

Passive DNS datasets

Passive DNS services record the answers DNS resolvers see across the internet and keep them as a history of names and addresses. They know hosts that never had a certificate.

HackerTarget offers a free lookup with a limited quota. Each line of its answer is a hostname and its address. Past the quota, it answers with a line starting API count exceeded instead:

curl -sSf 'https://api.hackertarget.com/hostsearch/?q=example.com'

Larger commercial datasets need an account and an API key. SubAnalyzer's light scan asks passive DNS datasets as well. They also remember names that are long gone, so their names go through the same checks as the rest.

Search engines

Search engines list hosts that serve public pages. A search like this one shows hosts other than the main website, and excluding each new host in the next search brings up more:

site:example.com -site:www.example.com

The results are a sample, not an inventory: Google says a site: search does not necessarily return every page it has indexed. SubAnalyzer doesn't query search engines.

Web archives

The Wayback Machine's index lists the address of every page it has archived, including pages on hosts that no longer exist. This command lists the hosts it holds under the domain:

curl -sSf 'https://web.archive.org/cdx/search/cdx?url=*.example.com&fl=original&collapse=urlkey' | sed -E 's#^[a-zA-Z]+://([^/:?]+).*#\1#' | tr '[:upper:]' '[:lower:]' | sort -u

The index can take a while to answer, and archived hosts are often long gone. SubAnalyzer doesn't query web archives.

Third-party sources only know names that were published or observed. The methods below look for the names they missed.

Active enumeration: the website and DNS

These methods contact the domain or ask DNS about it. In SubAnalyzer, reading the website is part of the light scan, and the DNS methods make up the deep scan, which starts alongside it.

The domain's own website

A website names other hosts in its links, its robots.txt file, its sitemaps and its security headers. A Content Security Policy header, for example, lists the hosts a page may load scripts and data from:

curl -sSf https://www.example.com/robots.txtcurl -sSI https://www.example.com | grep -i content-security-policy

SubAnalyzer reads your homepage, robots.txt and your sitemaps, looking for links to hosts under your domain. These are a handful of ordinary requests identified as SubAnalyzer. A linked host counts only if it resolves, since sites often link to hosts that are gone.

DNS records that name other hosts

Some records point to hosts by name: NS records to nameservers, MX records to mail servers, SPF rules in TXT records to the servers allowed to send mail, and SRV records to the hosts behind services such as SIP and Microsoft's Autodiscover. To list them:

dig +short NS example.comdig +short MX example.comdig +short TXT example.comdig +short SRV _autodiscover._tcp.example.com

SubAnalyzer queries 169 common SRV records, including _autodiscover._tcp and _sip._tcp, and reads your NS, MX and SPF records. Only names under your domain are included. A mail server belonging to your email provider is left out.

Zone transfers

A zone transfer (AXFR) asks a nameserver for a full copy of the zone. Most nameservers refuse. When one allows it, every name in that zone is listed at once. To try it, list the nameservers, then ask each one in turn. A refusal shows as Transfer failed in dig's output:

dig +short NS example.comdig AXFR example.com @ns1.example.com

A transfer covers one zone. A subdomain delegated to other nameservers is a zone of its own, and its names need a transfer from those servers.

SubAnalyzer asks each of your nameservers. When one allows the transfer, it collects the zone's names directly, and it asks each delegated subdomain the transfer names for its nameservers.

Zone walking

DNSSEC can offer another route. In a zone signed with NSEC records, the record that proves a name does not exist also names the next name in the zone. Following that chain is called zone walking.

Not every signed zone can be walked. NSEC3 hashes the names. A server that signs its answers on the fly can return records that cover only the name asked for, which leaves no chain to follow, as RFC 4470 describes. For a first clue, ask for the zone's keys and NSEC3 settings. A DNSKEY answer means the zone is signed, and an NSEC3PARAM answer means it uses NSEC3. An empty answer is a hint, not proof.

ldns-walk, from the ldns tools, follows an NSEC chain. Point it at one of the zone's own nameservers, since its manual warns that a caching resolver can trip it up:

dig +short DNSKEY example.comdig +short NSEC3PARAM example.comldns-walk @ns1.example.com example.com

Like a transfer, a walk lists one zone and stops at its delegations. Tools such as nsec3map can collect NSEC3 hashes and test guesses against them offline, which recovers only the names that are guessed.

SubAnalyzer tries a walk when no zone transfer succeeded. One query tells a real NSEC chain from NSEC3 and from records made on the fly, and the scanner walks only a real chain.

In a zone signed with a plain NSEC chain, each record points to the next name in the zone, so following the chain from the start lists the zone's names, up to any subdomain delegated to another zone. NSEC3 hashes the names, so the same walk turns up only hashes, and a server that signs its answers on the fly leaves no chain to follow. The scan walks only a plain NSEC chain.

Wordlist brute force

Brute forcing tries common names, such as www, mail, vpn, staging and grafana, and keeps those that resolve. It can find names that never appeared in public sources. SubAnalyzer's free subdomain wordlist, ranked from Certificate Transparency, is one place to start, and any file with one label a line works.

puredns runs a wordlist through massdns, which must be installed first, and filters out wildcard answers. It also needs a file of public resolvers, one address a line. Trickest publishes one, and puredns reads it from resolvers.txt in the current directory or from the file you pass with -r:

curl -fO https://subanalyzer.com/wordlists/subdomains-top-20000.txtcurl -fO https://raw.githubusercontent.com/trickest/resolvers/main/resolvers.txtpuredns bruteforce subdomains-top-20000.txt example.com -r resolvers.txt

Public resolvers drop queries when they get too many, and some give wrong answers, so puredns checks its results again through a few trusted resolvers, Google's by default.

SubAnalyzer's scan tests 20,659 common labels. It skips them when a zone transfer or walk has read the whole zone, since nothing is left to guess, and when a wildcard answers for every name directly under your domain, since every guess would then resolve.

Name variations

Organizations reuse naming patterns, so names already found suggest others: api-dev next to api, or eu2 next to eu1. Permutation tools such as alterx generate the variants, and a resolver such as dnsx keeps those that resolve. Here found.txt holds the names you have so far, one hostname a line, such as the output of the commands above:

alterx -l found.txt | dnsx -silent

Variants multiply quickly, so this works best on a short list. Under a wildcard every variant resolves, so check for one first. SubAnalyzer doesn't generate variants.

Following live hosts to more names

Hosts that answer can lead to names no source listed. In SubAnalyzer, these checks run during the service scan, described below.

Certificates on live servers

A server's certificate often covers more names than the one you connected to, and a certificate from a private certificate authority is generally absent from the public CT logs. To read the names:

openssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null | openssl x509 -noout -text | grep -o 'DNS:[^,]*'

Each TLS handshake in SubAnalyzer's service scan reads the server's certificate, which may list additional hostnames.

Reverse DNS

A PTR record names the host behind an address. Looking up the addresses around a known host can turn up neighbors such as mail or backup servers:

dig +short -x 203.0.113.10for i in $(seq 0 255); do dig +short -x 203.0.113.$i; done

A neighbor is a lead, not proof of common ownership. On shared hosting and in clouds, the next address often belongs to another customer, so keep only the names under the domain you are checking.

SubAnalyzer's reverse DNS sweep looks up every address in the block of 256 around each IPv4 address it finds, and keeps only names under your domain.

New names from certificates and reverse DNS go through the same checks as the rest, and those that pass get a service scan of their own. If a wildcard answers for every name under your domain, the certificate names are set aside, since every one of them would resolve.

Checking which names are real

Discovery produces candidates, not a finished list. Each one needs evidence that it exists in DNS today. On the scan page, these checks are part of Deep scan.

SubAnalyzer resolves candidates through a pool of 12 public resolvers, asking for IPv4 addresses first and then IPv6. A timeout is treated differently from an answer saying the name does not exist. A name qualifies if it has an address, is a CNAME alias or has TXT records of its own. A CNAME still counts when its target has disappeared, because that dangling record may indicate takeover risk.

Names supported by certificates or your own DNS records can remain in the results even when they do not resolve today. They appear without an address and are hidden in the Live view. Names found only by guessing must resolve to count.

Wildcard DNS

A wildcard record such as *.example.com answers for names the zone does not hold. It does not apply to a name that exists, to the names below one, or past a delegation to another zone (RFC 4592). Without checking for wildcards, a scanner can report thousands of invented subdomains. To check for one, look up a random name:

dig +short "$(openssl rand -hex 8).example.com"

An answer suggests a wildcard covers that level, so a guessed name there may resolve without the zone holding it. Repeat it with dev.example.com or another known name in place of example.com, since a wildcard can start below the domain itself. Compare answers with care: the puredns documentation notes that a load-balanced wildcard can return different addresses to each query.

SubAnalyzer tests for wildcards at every level of your domain. For each resolving candidate, it queries a random 16-character name at the same level. If that random name also resolves, the scanner moves up one level at a time to find where the wildcard begins.

A candidate beneath a wildcard needs more evidence that the zone holds it: a complete zone listing that includes it, a DNSSEC signature made for that exact name, an answer whose CNAME differs from the wildcard's, or a random name below it that gets no answer, since a name the zone holds blocks the wildcard above it. Some servers break that last rule, so the scanner first tests it on names it already knows.

If DNS cannot settle the question, SubAnalyzer compares the candidate's web page with the pages served for two random names at the same address. A different page, or a valid certificate for the name where the random names have none, keeps it. A page that matches the random names' is taken as the wildcard's answer, and the name is dropped. That is strong evidence, not proof: two real hosts can serve the same page, and a fallback page can change between requests, which the comparison tries to allow for.

Names beneath a wildcard that point only to private addresses cannot undergo that page comparison. They are kept only when a certificate or your website names them.

When DNS cannot tell whether the zone holds a name under a wildcard, two random names show what the server sends for names it does not know. test.example.com gets the same page, so the scan takes it for the wildcard's answer and drops it. shop.example.com gets a page of its own and is kept. Matching pages are strong evidence, not proof: two real hosts can serve the same page.

Confirming removals

A failed lookup should not erase a real subdomain. When a previously discovered name appears to be gone, SubAnalyzer asks your own nameservers directly. It reports the name as removed only when all of them agree that it no longer exists. If the answers are inconclusive, the name keeps its last known result.

Tools that combine these methods

Running each method by hand is slow, so tools bundle them. Subfinder, a command-line tool, queries many passive sources at once, and many of them work only with an API key. Amass adds active reconnaissance.

subfinder -d example.com

Online subdomain finders run the methods on their own servers, with nothing to install. SubAnalyzer runs nine of the 12 methods above, checks every name and adds addresses, open services, takeover checks and screenshots.

How SubAnalyzer runs these steps

A SubAnalyzer scan runs through five steps: Light scan, Deep scan, IP scan, Service scan and Verify. Some run side by side, and names discovered later go back through the same checks. Most scans finish in under two minutes, and a large domain takes longer.

Illustrative counts from an invented scan of example.com. Each row counts a different set: 148 of the 212 candidate names exist in DNS, 131 of those have a public address, and 57 answer on a scanned port. A takeover risk can sit on a name with no address at all. Names found late, on certificates and in reverse DNS, go back to be checked like the rest.

Each count describes a different set of names. A name with no public address or no open service can still be a real subdomain: it may point to a private network, hold only a CNAME or TXT record, or run nothing on the ports the scan checks.

IP scan: addresses and hosting

The IP scan records IPv4 and IPv6 addresses and looks up the network behind them in MaxMind's GeoLite2 ASN database. For major clouds and CDNs, such as AWS, Azure, Google Cloud, Cloudflare and Akamai, it names the provider in the Hosting column.

Service scan: confirming open services

SubAnalyzer checks 58 TCP ports on up to 8 public IPv4 addresses a host. IPv6 addresses are recorded but not scanned for services. The full port reference explains which ports are included and why.

A fast pass sends the first packet of a connection, and firewalls and SYN proxies can answer it even when no service is listening. So a port is shown only once a real connection confirms it: the service sends something back, or the connection stays open without being reset. The port reference explains how a port is confirmed. Service names, such as HTTPS for port 443, come from the port number, and the scan does not check software versions.

Both hosts answer the first packet, so the fast pass alone would call both ports open. The confirmation tells them apart: the web server completes a TLS handshake and presents its certificate, while the SYN proxy resets the connection as soon as data arrives.

Verify: takeover checks and screenshots

A takeover can happen when a DNS record points to a cloud or SaaS resource that no longer exists and someone else can claim it. Read more about how subdomain takeover happens and how to prevent it.

SubAnalyzer checks each CNAME it finds against 36 supported services, including 15 Azure services, AWS S3 and Elastic Beanstalk, WordPress.com and Ghost. It also reports a nameserver whose domain nobody has registered, checked through DNS and the registry's own records, since whoever registers that domain controls every zone delegated to it. Every reported risk gets a red marker: free scans label it Takeover risk, and paid plans name the service in its place.

A headless browser takes a screenshot of each host with an open web port, from a list of 14 common HTTP and HTTPS ports. The first page of screenshots is free; paid plans show every screenshot and its page type.

After the first scan: changes and monitoring

Each re-scan checks every subdomain found before, even one that has dropped out of public sources. The Changes tab lists what moved since the previous scan, from new and removed subdomains to changed CNAME records, services and takeover risks.

Monitoring, part of the paid plans, runs these re-scans daily, weekly or monthly. When something changes, SubAnalyzer sends one email with takeover risks first.

Each re-scan is compared with the scan before it, and the Changes tab lists what moved. Monitoring sends one email with the changes since its last one, takeover risks first. Quiet rounds send nothing.

What a scan never does

SubAnalyzer examines your domain from the internet using DNS queries, connections to common ports and web page requests. It never logs in, attempts an exploit or changes a setting.

Scan your domain

Start a free scan to see the subdomains, services, hosting providers and takeover risks SubAnalyzer finds.

Sources

← All articles