A phantom domain attack targets recursive DNS resolvers by forcing them to query domains that have been configured to never respond, or to respond extremely slowly. Each query ties up resolver resources (sockets, memory, query slots) as it waits for a response that never comes. When the attacker triggers enough of these phantom queries, the resolver's resources are exhausted, and legitimate DNS resolution degrades or fails entirely.
This is an elegant resource exhaustion attack. Unlike brute-force DDoS where the attacker overwhelms bandwidth, phantom domains consume the resolver's internal state by exploiting its obligation to wait for upstream responses.
How the Attack Works
-
The attacker configures phantom domains. They register domains and set up authoritative nameservers that either:
- Never respond (drop all incoming queries silently)
- Respond very slowly (delay the answer until just before the resolver gives up). Over UDP there is no connection for the attacker to hold open: the server simply sits on the datagram while the resolver keeps local query state alive waiting for it. Over TCP an actual connection can be held open, which ties up a socket on the resolver as well.
-
The attacker triggers queries. Through a botnet, malicious web pages, or email with embedded resources, the attacker causes victim machines to look up hostnames under the phantom domains.
-
The resolver waits. When the resolver queries the phantom domain's authoritative server, it receives no response. The resolver retries according to its configuration (typically 2-4 retries with increasing timeouts).
-
Resources accumulate. Each outstanding query consumes:
- A pending query slot
- A UDP or TCP socket
- Memory for the query state
- CPU time for timeout management
-
Exhaustion. When enough queries are waiting simultaneously, the resolver reaches its resource limits. New legitimate queries are delayed or dropped.
Client → Resolver: "What is a.phantom-domain.com?"
Resolver → Phantom NS: query... (no response)
Resolver → Phantom NS: retry 1... (no response)
Resolver → Phantom NS: retry 2... (no response)
Resolver → Phantom NS: retry 3... (no response)
[30+ seconds of resource consumption per query]
× 10,000 simultaneous queries = resolver exhaustion
Why It Is Effective
The phantom domain attack is effective because it exploits the resolver's designed behavior:
Resolvers are built to be patient. DNS was designed for a world where network latency varies and servers may be temporarily slow. Resolvers give upstream servers multiple chances to respond, with generous timeouts.
Each phantom query is cheap for the attacker. The attacker's nameserver does nothing. It simply drops packets. The work is entirely on the resolver side.
The attack is hard to distinguish from legitimate slowness. Any domain's nameserver might genuinely be slow or temporarily down. The resolver cannot know in advance whether a query will receive a response.
Retries multiply the damage. A resolver typically retries 2-4 times before giving up, with timeouts of 2-10 seconds per attempt. A single phantom query can consume 10-30 seconds of resolver state.
How It Differs from Other DNS DDoS Attacks
| Attack | Target | Mechanism |
|---|---|---|
| Water Torture | Authoritative server | Floods with random subdomain queries |
| NXDOMAIN Attack | Resolver | Floods with queries for nonexistent domains |
| Phantom Domain | Resolver | Ties up resources with queries that never complete |
| DNS Amplification | Victim (via reflection) | Uses open resolvers to amplify traffic |
The phantom domain attack is distinct because it does not require high query volume. A relatively small number of queries can be effective if each one ties up resources for an extended period. You can use the DNS lookup tool to check whether a suspicious domain's nameservers are responding at all.
How Attackers Set Up Phantom Domains
The setup is straightforward:
- Register a domain (e.g.,
phantom-example.com) - Configure nameservers that accept connections but never send responses
# Conceptual: a nameserver that accepts but never responds
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 53))
while True:
data, addr = sock.recvfrom(512)
# Intentionally do nothing — drop the query
pass
- Register NS records pointing to these phantom nameservers
- Trigger resolution of hostnames under the phantom domain
The attacker can use multiple phantom domains to make the attack harder to filter by domain name.
How to Defend Against It
Configure Aggressive Timeouts
Reduce the time your resolver waits for upstream responses. Most resolvers default to generous timeouts that assume well-behaved nameservers:
Unbound:
server:
# How long to wait on a server Unbound has no timing history for,
# in milliseconds. Lowering this gives up on silent servers sooner.
unknown-server-time-limit: 376
# Drop the client-facing recursion request after this long (msec) so
# pending replies do not accumulate. The recursion itself continues.
discard-timeout: 1900
BIND:
options {
// Reduce recursion timeout
resolver-query-timeout 10;
// Limit the number of queries per fetch
max-recursion-queries 50;
};
Shorter timeouts mean the resolver gives up on phantom domains faster, freeing resources for legitimate queries.
Bound the Request List So Slow Queries Get Evicted
Unbound has no per-domain or per-nameserver concurrency limit, so do not expect to cap phantom domains specifically. What it does have is overload behaviour on the global request list, which is the mechanism that actually protects you: when more queries arrive than a thread can service, Unbound lets half the in-flight queries run to completion and displaces the other half if they have already used more than their allotted time. Slow queries are exactly the ones that lose, which is the property you want under this attack.
# Unbound
server:
# Simultaneous queries serviced per thread. Beyond this, queries are
# jostled out or dropped, forcing the client to retry.
num-queries-per-thread: 2048
# Timeout (msec) used when busy: in-flight queries older than this
# can be replaced by new arrivals. Aim for one round trip.
jostle-timeout: 200
wait-limit (default 1000) is a related lever, capping how many replies can be waiting on recursion for any one client IP address. Note that unwanted-reply-threshold is not part of this: it counts unsolicited replies and, on reaching the threshold, flushes the rrset and message caches as an anti-poisoning measure. That is a cache-poisoning defence, and flushing caches is the opposite of what you want mid-attack.
Enable Serve-Stale (RFC 8767)
Serve-stale allows the resolver to return expired cached records when it cannot reach the authoritative server. This provides graceful degradation during attacks:
# Unbound
server:
serve-expired: yes
# How long past expiry stale answers stay usable, in SECONDS
serve-expired-ttl: 86400
# How long the client waits for a fresh answer before Unbound falls
# back to stale data, in MILLISECONDS. 1800 means 1.8 seconds, not
# 30 minutes. A non-zero value here is what enables RFC 8767 order
# of operations: try to resolve first, serve stale only on failure.
serve-expired-client-timeout: 1800
Watch the units in that block: serve-expired-ttl is in seconds and serve-expired-client-timeout is in milliseconds, which is easy to misread when they sit next to each other.
Even if the resolver cannot complete new queries for phantom domains, it can continue serving cached answers for legitimate domains.
Monitor Resource Utilization
Watch these metrics on your resolver:
- Outstanding query count: a spike indicates potential phantom domain activity
- Query timeout rate: increasing timeouts suggest unresponsive upstream servers
- Socket utilization: approaching socket limits means resources are being exhausted
- Response latency: increasing latency for legitimate queries is the user-facing symptom
Deploy Resolver Redundancy
Run multiple resolver instances behind a load balancer. If one instance's resources are exhausted, others can continue serving legitimate queries.
Mitigation Checklist
- Resolver query timeout reduced to reasonable values (5-10 seconds max)
- Maximum outstanding queries per domain/nameserver limited
- Serve-stale (RFC 8767) enabled for graceful degradation
- Resolver resource monitoring in place (sockets, memory, query slots)
- Query timeout rate monitoring and alerting configured
- Multiple resolver instances deployed for redundancy
- QNAME minimization enabled to reduce upstream query volume
- Resolver software is current and patched
Common Misconfigurations
- Default timeout values left unchanged: many resolvers ship with 30+ second total timeout per query, which is too generous under attack
- No limit on outstanding queries per domain: the resolver accepts unlimited queries for an unresponsive domain, rapidly exhausting resources
- Serve-stale not enabled: legitimate queries fail as soon as resources are exhausted, even for domains that were recently cached
- Single resolver instance: no redundancy means one exhausted resolver takes down DNS for all users
- Not monitoring timeout rates: the attack goes undetected until users complain
Ethical Note
Phantom domain testing should only be conducted in a lab environment where you control the entire DNS resolution path, your own resolver, your own authoritative server configured as a phantom, and your own test clients. Do not configure phantom domains on the public internet unless they are used only in isolated testing.
This article is part of the Complete Guide to DNS Attacks and DNS Security. See also: DNS Water Torture Attack, NXDOMAIN Attack.

