Back to Articles

dnscan: Why Zone Transfer Attacks Still Matter in 2024

[ View on GitHub ]

dnscan: Why Zone Transfer Attacks Still Matter in 2024

Hook

In an era of passive DNS databases and AI-powered reconnaissance, one Python script still starts every scan the old-fashioned way: by politely asking DNS servers to hand over their entire zone file. Surprisingly, it works more often than you’d think.

Context

Subdomain enumeration is the bread and butter of security reconnaissance. Before you can test a web application, identify exposed services, or map an organization’s attack surface, you need to know what domains actually exist. The problem is that DNS wasn’t designed with discovery in mind—it’s a lookup service, not a directory listing. You can query for specific records if you know the hostname, but there’s no universal “show me everything” command.

Historically, security researchers relied on two approaches: zone transfers (AXFR requests) that replicate entire DNS databases, or brute-force dictionary attacks that try thousands of common subdomain names. Zone transfers were supposed to be restricted to authorized secondary nameservers, but misconfigurations were rampant in the 2000s and early 2010s. As sysadmins tightened security, the industry shifted toward passive DNS databases, search engine scraping, and certificate transparency logs. Yet the fundamentals haven’t changed—you still need a reliable, scriptable way to enumerate subdomains when passive sources come up empty. That’s where dnscan carved its niche: a straightforward Python tool that tries the old tricks first, then falls back to intelligent brute-forcing with wordlists built from actual reconnaissance data.

Technical Insight

AXFR Success

AXFR Fails

Valid Response

NXDOMAIN/Timeout

Yes

No

Target Domain Input

Zone Transfer Attempt

Complete Enumeration

Dictionary-Based Scanning

Load Wordlist

subdomains.txt/10000.txt

Thread Pool

Concurrent Workers

DNS Resolver

dnspython queries

Query A/AAAA/CNAME

Skip Entry

Discovered Subdomains

Recursive

Mode?

Output Results

System architecture — auto-generated

What sets dnscan apart isn’t novel architecture—it’s a single Python script under 1,000 lines—but its pragmatic multi-phase enumeration strategy. The tool starts every scan by attempting zone transfers against all authoritative nameservers for the target domain. This isn’t naïve optimism; misconfigurations still exist, especially in internal networks, staging environments, or legacy infrastructure. If AXFR succeeds, you get instant complete enumeration without triggering rate limits or detection systems.

When zone transfers fail (the common case), dnscan pivots to dictionary-based brute-forcing. Here’s where the research investment pays off. The default wordlists aren’t arbitrary collections of “admin,” “test,” and “staging.” They’re derived from analyzing over 86,000 successful zone transfer datasets, sorted by actual subdomain popularity. The subdomains.txt file contains entries like “www,” “mail,” “remote,” and “blog”—boring, but statistically proven to exist. The subdomains-10000.txt extends coverage to less common patterns observed in real-world infrastructure.

The scanning engine uses Python’s threading module to parallelize DNS queries. Here’s the core lookup logic:

def get_records(domain, qtype='A'):
    try:
        answers = resolver.query(domain, qtype)
        return [rdata.to_text() for rdata in answers]
    except dns.resolver.NXDOMAIN:
        return None
    except dns.resolver.NoAnswer:
        return []
    except dns.exception.Timeout:
        return None

# Threaded worker scanning subdomains
for subdomain in wordlist:
    target = f"{subdomain}.{domain}"
    records = get_records(target)
    if records:
        print(f"[+] {target} - {records}")

The tool’s flexibility comes from custom insertion points using the %% placeholder. Instead of only testing “prefix.example.com” patterns, you can scan patterns like “www-%%.example.com” or ”%%-prod.internal.example.com.” This matters when organizations use consistent naming conventions that deviate from simple subdomain prefixes.

One underappreciated feature is TLD enumeration mode. Given a base domain like “example,” dnscan will test “example.com,” “example.net,” “example.org,” and hundreds of other TLDs from IANA’s public suffix list. This discovers registrations across international TLDs (.co.uk, .com.au) and newer gTLDs (.io, .dev) that manual searches might miss. The alteration mode extends this by generating ~60 permutations per domain—adding common prefixes (“my-,” “get-”), suffixes (“-app,” “-api”), and patterns observed in corporate naming conventions.

Wildcard detection is where dnscan shows its age. The tool queries a random subdomain like “dkadsjfhsdkjfh823982398.example.com” to establish a baseline. If it resolves, the domain uses wildcard DNS, and dnscan filters subsequent results by comparing returned IP addresses. This works but produces false positives when CDNs or load balancers return different IPs for legitimate subdomains. Modern tools use multiple random queries and statistical analysis to reduce noise, but dnscan’s approach is “good enough” for most use cases.

Output handling is refreshingly straightforward—plain text to stdout, with optional CSV export for parsing. No JSON schemas, no database backends, just grep-friendly results you can pipe to other tools. This Unix philosophy design makes dnscan excellent for shell scripts and automation pipelines where you need predictable, parseable output.

Gotcha

The biggest limitation is speed. Python’s Global Interpreter Lock means threading doesn’t deliver true parallelism, and even with 32 threads (the configurable maximum), dnscan processes roughly 100-200 queries per second depending on resolver performance. Compare this to massdns, which can sustain 200,000+ queries per second using async I/O and UDP packet manipulation. For scanning a single domain with a 10,000-word list, dnscan finishes in minutes. For scanning hundreds of domains or using million-word lists, you’ll be waiting hours.

The tool has no rate limiting or jitter capabilities. When you point dnscan at a domain, it hammers the configured resolver with maximum-threaded queries. Public resolvers like Google’s 8.8.8.8 will start dropping packets or temporarily blocking your IP. Corporate DNS servers will generate security alerts. There’s no exponential backoff, no request spacing, no attempt at stealth. You’re trading subtlety for simplicity.

Wildcard handling, while functional, struggles with complex CDN configurations. If a domain uses Cloudflare or AWS CloudFront with geo-distributed IP pools, dnscan’s single-random-query baseline might not capture the full range of wildcard IPs. You’ll get false positives where legitimate subdomains are filtered out because they happened to return a wildcard IP from a different edge location. The recursive scanning mode that automatically enumerates discovered subdomains (finding “dev.internal.example.com” then scanning “*.dev.internal.example.com”) is noted in the documentation as “slow” and lacks depth limiting, so a deep subdomain hierarchy could cause exponential runtime growth.

Verdict

Use if: You need a no-dependencies Python tool for periodic infrastructure audits, you’re working in environments where zone transfers might still succeed (internal networks, red team engagements against legacy systems), or you want research-backed wordlists without assembling custom lists from scratch. It’s perfect for bug bounty reconnaissance when you’re targeting a specific domain and care more about thoroughness than speed, and the simple output format makes it trivial to integrate into existing shell-based workflows. Skip if: You’re scanning large domain lists where speed matters, you need passive reconnaissance from certificate transparency or DNS databases, you require stealth features to avoid detection, or you want modern capabilities like API integrations, JSON output, or distributed scanning. In those scenarios, reach for amass (comprehensive multi-source enumeration), subfinder (passive-first approach), or massdns (raw speed). dnscan is the reliable Honda Civic of subdomain enumeration—not flashy, but it starts every time and gets the job done.

// ADD TO YOUR README
[![Featured on Starlog](https://starlog.is/api/badge/developer-tools/rbsec-dnscan.svg)](https://starlog.is/api/badge-click/developer-tools/rbsec-dnscan)