skip to content

How did the Kaminsky technique make off-path DNS cache poisoning practical without waiting for TTLs, and what did recursive resolvers change in response?

level: seniorimportance: should knowfreq 28%

answer

  1. race for names nobody cached
  2. authority section carries the payload
  3. one race per query, not per TTL
  4. the source port as a second ID
  5. letter case as extra bits

basics

~20 s

The Kaminsky technique queries random uncached names under a target zone, so each query opens a fresh race, and forged replies carry NS records capturing the whole zone. Resolvers answered with unpredictable source ports (RFC 5452) and 0x20 case randomisation.

solid answer

~50 s

Classically an off-path forger raced the genuine answer for one name; after a loss the real record sat in cache for its TTL, so a long TTL rationed attempts (RFC 5452 section 7). The Kaminsky technique removed that brake: make the resolver look up `a1.example.com`, `a2.example.com` and so on - names nobody has cached - so each query is a new race. Each forged reply answers the random name and adds `NS` records for `example.com` pointing at the attacker's server, data a resolver accepts because it comes from a supposed authority for a parent of the queried name. One win captures the zone. Against a fixed source port, RFC 5452 section 8.1 puts a 7000 packets/s attacker at 50% within 7 seconds. The response was RFC 5452's MUST for unpredictable source ports and IDs - about 116 hours with 64000 ports - plus 0x20 case randomisation, an Internet-Draft; DNSSEC validation is the cryptographic fix.

code

dns · 8 lines
dns
;; forged response to the resolver's query for a17.example.com IN A
;; ID guessed; source port guessed
;; ANSWER SECTION:
a17.example.com.        300     IN  A   192.0.2.66
;; AUTHORITY SECTION:
example.com.            86400   IN  NS  ns.attacker.example.net.
;; ADDITIONAL SECTION:
ns.attacker.example.net. 86400  IN  A   198.51.100.53

go deeper

for a junior

Remember that the attack floods a resolver with forged answers for random names, and that random source ports plus random query IDs are what make guessing hard.

for a middle

Explain why querying uncached names removes the TTL wait, and why the forged NS record in the authority section is the real payload.

for a senior

Quantify the defence with RFC 5452's numbers, name what undoes it such as port-rewriting devices, and state that only DNSSEC validation proves origin.

for a principal

Decide where to invest: resolver placement that preserves port entropy, DNSSEC validation, and whether encrypting resolver-to-authoritative traffic is worth its operational cost.

## The race an off-path forger must win A recursive resolver that sends a query over UDP accepts the first datagram that matches it. RFC 5452 section 9.1 lists what must match: both addresses, the destination port against the query's source port, the **query ID**, the query name, and the class and type. An **off-path** attacker - one who cannot see the query - knows the name it made the resolver ask and the authoritative servers' addresses; it must guess the ID and the source port and deliver its guess in the **window of opportunity** before the genuine answer arrives, which RFC 5452 puts at often around 0.1 s. ## Why the TTL used to be the brake In the classic attack the forger races for the very record it wants to plant, say `www.example.com`. If the genuine answer wins, the resolver caches it and sends no new query until its **TTL** expires. RFC 5452 section 7 models this: attempts arrive once per TTL, so a short TTL makes spoofing far more viable. Its worked example against a fixed source port: at 7000 forged packets per second, a record with a 3600-second TTL has a 10% chance of being spoofed in the first 24 hours and 50% after a week. ## The Kaminsky construction The technique, named after the researcher who publicised it, removes the wait: 1. The attacker makes the resolver query names that cannot be cached - `a1.example.com`, `a2.example.com`, and so on - directly if the resolver is open, or indirectly, for instance by making a mail server look them up. 2. Each query opens a **new window**, so there is no TTL to wait out; RFC 5452 section 8.1 says such repeated-query techniques reduce the effective TTL to 0. 3. Into each window the attacker fires forged responses claiming to come from an `example.com` authoritative server, guessing the ID. 4. Each forgery answers the random name and carries, in its **authority section**, `NS` records saying `example.com` is served by `ns.attacker.example.net`, with an address for it. 5. When one guess matches, the resolver stores those records, and every later lookup under `example.com` goes to the attacker. The payload is not the answer but the delegation that rides along with it. ## Why the in-domain check did not stop it RFC 5452 section 6 tells resolvers to accept data only if the originator is authoritative for the query name or a parent of it - the idea older texts call a **bailiwick** check, a term RFC 9499 now calls historic. Here the forged `NS` data is for `example.com`, the parent of the queried name, and it claims to come from `example.com`'s own server. The check passes. RFC 2181 section 5.4.1 ranks authority-section data from an authoritative answer above glue, which is why such data could displace what the cache held. ## The entropy stack that answered it | Layer | Space it adds | Source | Limits | |---|---|---|---| | Query ID | 16 bits, 0-65535 | RFC 1035 header; RFC 5452 requires the full range, unpredictably | Too small alone against fast retries | | Source port | Up to about 64000 ports (ports below 1024 are not always available) | RFC 5452 section 9.2 MUST, from 53 or 1024 and above | A device in front that rewrites ports predictably undoes it | | Source address | Multiple resolver addresses, used unpredictably | RFC 5452 SHOULD | Needs several addresses | | 0x20 letter case | About one bit per letter in the name | An Internet-Draft technique, never an RFC | Short names and digits add little; servers must echo the question's case | The arithmetic from RFC 5452 section 8.1 shows the effect: with repeated queries at 7000 packets per second, one source port gives the attacker a 50% chance within 7 seconds; 64000 ports push the same 50% to around 116 hours. **0x20 randomisation** exploits two rules in RFC 1034: names compare case-insensitively, yet a server that receives a name should preserve its case. A resolver sends `wWw.eXaMpLe.cOm`, the genuine server echoes that question exactly, and a forger who never saw the query must also guess the case pattern. ## What remains after randomisation - Randomisation raises the **cost** of guessing; it proves nothing about where data came from. - The cryptographic fix is **DNSSEC validation**, where a forged `NS` set or address simply fails to verify for a signed zone. - Restricting which authority and additional data a resolver caches, and never promoting it into answers, narrows what a winning forgery can plant, as RFC 2181 section 5.4.1 recommends. - Encrypting the resolver-to-authoritative hop, which RFC 9250 defines for DoQ, replaces the blind-guessing race on that hop with a connection an off-path forger cannot inject into.

  • Why does a long TTL on www.example.com not protect it against the Kaminsky technique?
    The attacker never races for `www.example.com`. It races for random uncached names under the zone, each of which triggers a fresh query, and plants delegation data for the zone itself. RFC 5452 section 8.1 notes such repeated-query techniques reduce the effective TTL to 0, so the target record's TTL no longer rations attempts.
  • A resolver randomises its source ports, but sits behind a device that rewrites them to a sequential range. What happens to the protection?
    Most of it is lost. The authoritative server replies to the rewritten port, so a forger only needs to predict what the device will pick next. RFC 5452 section 9.2.1 warns that a resolver with few upstream-facing endpoints is effectively using constants. The rewriting device must itself randomise, or the resolver must sit where ports survive.

saying these in an interview costs you the question

  • Kaminsky poisoning only works when the target record's TTL has just expired.
  • Bailiwick checks block forged NS records sent for the parent zone.
  • Source-port randomisation makes off-path poisoning cryptographically impossible.
  • 0x20 case randomisation is required by RFC 5452.
  • Randomising the query ID alone gives 32 bits of protection.