Concepts / Denial of service

Denial of service

DNS amplification

Also called DNS reflection, amplification attack, open resolver, reflection attack

Bouncing small spoofed queries off open resolvers so large answers flood a victim.

UDP has no handshake, so a resolver answers whatever source address a query claims. An attacker sends tiny queries with the victim's address as the source to open resolvers; each sends a much larger answer to the victim — a reflection that hides the attacker and an amplification that multiplies the traffic (a 60-byte ANY query for a signed zone can draw a reply ten times its size). The fix is to not run an open resolver: answer only your own users, and let authoritative servers rate-limit responses, so the resolver cannot be turned into a weapon.

How a DNS amplification attack works, step by step

In the DNS amplification lab an open resolver, openResolver (10.0.1.10), validates DNSSEC and answers anyone. The attacker (10.0.2.12) and the victim (10.0.2.13) sit on the internet side, and the signed zone lab is served by labServer (10.0.2.11).

  1. The attacker builds a small query. 32 bytes of DNS: id 0xabcd (43981), recursion desired, one question (lab, type ANY), and an EDNS0 OPT record offering a 4096-byte buffer with the DO bit set, so the reply may be large and must include the DNSSEC records.
  2. It forges the source. The UDP packet goes to 10.0.1.10 port 53 with source 10.0.2.13, the victim. Nothing in IP or UDP checks a source address (IP spoofing), and UDP has no handshake that would expose the lie.
  3. The resolver answers the address it sees. It resolves lab (or answers from its cache) and sends the reply to 10.0.2.13: the SOA, NS, NSEC and both DNSKEYs, each with its RRSIG. Several hundred bytes (about 780) for a 32-byte question, a factor of about 24. That is amplification.
  4. The victim receives answers it never asked for, from a server it never contacted. That is reflection: the attacker's address appears nowhere in what the victim sees.
  5. Multiply. Real attacks spread queries over thousands of open resolvers, each sending modest traffic, so no single source looks like a flood. The victim's link fills with UDP from port 53. Attacks of this kind have passed 300 Gbit/s.

Three things must all be true: a forged source can leave the attacker's network, a resolver answers strangers, and a small question has a big answer. Each defence removes one.

What it looks like on a Linux machine

First the flaw: the resolver answers a host on the internet as readily as one on its own network:

$ dig +short www.lab @10.0.1.10        # from the attacker, 10.0.2.12
10.0.2.20

The size of the answer is in dig's last line, ;; MSG SIZE rcvd:. dig 9.18 asks ANY over TCP unless given +notcp, and a forged query can only travel over UDP, so the lab asks over UDP and turns the size into a factor:

$ sz=$(dig +notcp +dnssec ANY lab @10.0.1.10 | awk '/MSG SIZE/{print $NF}')
$ echo "response: $sz bytes, query: ~32 bytes, factor: ~$((sz/32))x"; [ "$sz" -gt 400 ] && echo AMPLIFIED
response: 780 bytes, query: ~32 bytes, factor: ~24x
AMPLIFIED

Then nping sends 30 forged queries with -S 10.0.2.13, and a capture on the victim shows what lands. The reply's id is the attacker's 43981, $ means the answer was validated (the ad bit), and 10/0/1 counts answer, authority and additional records:

$ tcpdump -ni eth0 udp and host 10.0.1.10
IP 10.0.1.10.53 > 10.0.2.13.7777: 43981$ 10/0/1 SOA, RRSIG, NS ns.lab., RRSIG, NSEC, RRSIG, DNSKEY, DNSKEY, RRSIG, RRSIG (780)

The fix in the lab is one rule on homeRouter, which drops DNS from outside before it reaches the resolver:

$ iptables -A NETLAB-FORWARD -d 10.0.1.10 -p udp --dport 53 -j DROP

The same burst then leaves no trace on the victim, and legitClient (10.0.1.11), which never crosses the router, still resolves www.lab. On the resolver itself, unbound's access-control: 10.0.1.0/24 allow (refuse the rest) closes it, whatever the network does.

What goes wrong, and how you see it

Your resolver is the weapon. Outbound traffic from port 53 jumps while inbound queries come from a few addresses asking the same name over and over, often ANY. tcpdump -ni eth0 udp port 53 shows it; the answer is to restrict recursion to your own networks.

You are the victim. Inbound UDP from source port 53 floods the link, from many resolvers, with answers to questions nobody on your network asked. Filtering on your own router is too late, because the link is already full; the upstream provider or a scrubbing service has to drop it.

An authoritative server is abused. It cannot refuse strangers, since answering them is its job. Response rate limiting (BIND's rate-limit) caps identical answers to one address and sends some back truncated, so a real client retries over TCP and a forged one gets nothing more.

Forged packets leave your network. If a host inside can send packets with a source that is not yours, your network can launch the attack. BCP 38 ingress filtering, or reverse path filtering (rp_filter on Linux routers), drops them at the edge.

Questions people ask

What is an open resolver? A recursive resolver that answers queries from anyone on the internet. Run one only on purpose, with rate limits; a home or office resolver should answer only its own clients.

Why ANY and DNSSEC? ANY asks for every record type at once, and DNSSEC adds keys and signatures, so both make the answer bigger. Many servers now give ANY a minimal answer (RFC 8482), and attackers pick large TXT or DNSKEY records instead.

How is this different from a SYN flood? Both rely on forged sources. A SYN flood exhausts a server's half-open connections; amplification exhausts the victim's bandwidth with someone else's answers.

See it on real machines

Learn it on real machines.

Every lab is a small network of real Linux machines in your browser. Start with a free account: Google or email, no card.

Open this lab