Skip to content

06-03: Exercises

Question

A recursive resolver sends a query out to an authoritative name server:

Query:  Transaction ID = 0x4F2A, Source Port = 51422
        A? secure-bank.com

Shortly after, two responses arrive claiming to answer this query:

Response A:

Transaction ID = 0x4F2A
Source Port    = 53 (from the real authoritative server's IP)
Destination Port = 51422

;; ANSWER SECTION:
secure-bank.com.     300   IN   A    198.51.100.10

;; AUTHORITY SECTION:
secure-bank.com.     300   IN   NS   ns1.secure-bank.com.

Response B:

Transaction ID = 0x7C13
Source Port    = 53 (spoofed to look like the authoritative server's IP)
Destination Port = 51422

;; ANSWER SECTION:
secure-bank.com.     300   IN   A    198.51.100.10

;; AUTHORITY SECTION:
secure-bank.com.     300   IN   NS   ns1.attacker-controlled.com.

;; ADDITIONAL SECTION:
ns1.attacker-controlled.com.   300   IN   A    203.0.113.99

  1. Which response is the legitimate one, and which is the cache-poisoning attempt? What specifically gives it away?
  2. Even though the resolver should be able to detect the fake response, explain why a real-world resolver might still be tricked into accepting it.

Solution

Step 1: Compare the transaction IDs

DNS uses a transaction ID (TXID) — a 16-bit number chosen randomly by the resolver for every outgoing query — specifically so that the resolver can match a response to the query it actually sent, and reject anything that doesn't match.

  • The original query used Transaction ID = 0x4F2A.
  • Response A: Transaction ID = 0x4F2A → matches.
  • Response B: Transaction ID = 0x7C13 → does not match.

This alone is a strong signal that Response B is the forged / cache-poisoning attempt. A correctly-behaving resolver checks the TXID on every incoming response and silently discards any response whose TXID doesn't match an outstanding query. Response B would normally be dropped immediately for this reason.


Step 2: Notice the suspicious Authority section in Response B

Beyond the mismatched TXID, Response B contains a second red flag even if the TXID had matched:

;; AUTHORITY SECTION:
secure-bank.com.     300   IN   NS   ns1.attacker-controlled.com.

;; ADDITIONAL SECTION:
ns1.attacker-controlled.com.   300   IN   A    203.0.113.99
  • This response doesn't just supply an A record for secure-bank.com — it also tries to sneak in a claim that secure-bank.com's authoritative name server is now ns1.attacker-controlled.com, along with a "helpful" glue A record pointing that name at 203.0.113.99 (an attacker-controlled IP).
  • This is a classic cache-poisoning / Kaminsky-style injection technique: by riding along extra NS and glue records in the Authority/Additional sections of a response, an attacker tries to get the resolver to cache the idea that all future queries for secure-bank.com (not just this one A record) should be sent to the attacker's fake name server. If the resolver blindly trusts and caches this, the attacker gains standing control over the domain in that resolver's cache — a much bigger win than poisoning a single A record.
  • A response that suddenly reassigns authority for a well-established domain to an unfamiliar, out-of-bailiwick name server is inherently suspicious and is exactly the pattern a resolver's bailiwick-checking logic should reject.

Step 3: Why might a resolver still be tricked, despite these defenses?

Even though transaction ID checking and bailiwick checking exist, real resolvers have historically still been vulnerable for practical reasons:

  1. The transaction ID space is only 16 bits (65,536 values). An attacker who can send a flood of guessed responses very quickly (e.g., thousands per second) has a realistic chance of guessing the correct TXID before the real authoritative response arrives — especially if they can also predict or narrow down the query timing (e.g., by first triggering the resolver to look up the domain).
  2. Source port used to be predictable/fixed. Historically, many resolvers always sent DNS queries from the same fixed source port (port 53). This cut the attacker's search space down to just the 16-bit TXID, since the destination port for the forged response was already known. The Kaminsky attack (2008) demonstrated exactly this weakness. The fix — source port randomization — combines with TXID randomization to make the effective "guess space" much larger (16 bits of TXID x ~16 bits of port ≈ 32 bits), making brute-force spoofing far less practical.
  3. Timing race condition. DNS over UDP has no handshake — a resolver simply accepts the first response that matches the expected TXID (and, on stricter implementations, the expected source IP/port), no matter who really sent it. If an attacker can spoof a response that lands in the resolver's queue before the legitimate authoritative server's real answer, and it happens to guess the TXID/port correctly, the resolver has no further way to tell it's fake from the packet alone — DNS responses over plain UDP are not cryptographically signed by default.
  4. No source authentication in classic DNS. Without DNSSEC, there's no cryptographic signature tying a response to the genuine authoritative server, so a resolver's only defenses are the TXID, the source port, and matching the query name/type/class — all of which can, with enough attempts or a favorable position on the network path, be spoofed or brute-forced by a motivated attacker.

This is precisely why modern deployments recommend DNSSEC (which adds cryptographic signatures resolvers can verify) on top of TXID and source-port randomization — randomization only raises the cost of the attack, it doesn't make forgery cryptographically impossible.


Final Answer

  • Response A is legitimate: its Transaction ID (0x4F2A) matches the original query.
  • Response B is the cache-poisoning attempt: its Transaction ID (0x7C13) does not match, and it additionally tries to inject a forged NS + glue A record pointing secure-bank.com's authority at an attacker-controlled server — a classic cache-poisoning injection technique.
  • A resolver can still be fooled in practice because: (a) the 16-bit TXID space can be brute-forced with enough forged packets sent quickly, (b) historically-fixed/predictable source ports made guessing easier (mitigated by source port randomization), (c) plain UDP DNS has no signature verification, so the resolver just accepts the first response that matches TXID/port, and (d) without DNSSEC there is no cryptographic proof of authenticity — only randomization raising the guessing difficulty.