Suspected DNS Cache Poisoning
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://ipfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://ipfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://ipfyi.com/entity//)
Use the native HTML custom element.
Users on the network are being redirected to unexpected IP addresses when visiting known-good domains — the correct domain name resolves but returns a rogue IP that serves a phishing page or drops the connection. The resolver cache contains forged records injected by an attacker who won a source-port or transaction-ID prediction race, and cached records persist until their spoofed TTL expires.
Symptoms
- ⚠ A trusted domain resolves to an IP address that belongs to a foreign ASN or unknown hosting provider
- ⚠ Users report certificate warnings (mismatched CN/SAN) after navigating to a familiar site
- ⚠ whois or IP geolocation of the resolved IP does not match the expected CDN or hosting provider
- ⚠ The anomaly affects all clients on the same resolver but not clients using external resolvers
- ⚠ DNSSEC validation fails or is absent for an affected zone that should have DNSSEC
- ⚠ dig shows an unusually short TTL (e.g., 60 seconds) on a record that normally has a 3600s TTL
Possible Root Causes
- • Kaminsky-style cache poisoning: attacker floods the resolver with forged responses, predicting the transaction ID and source port before the legitimate response arrives — enabled by resolvers that do not randomize source ports
- • The resolver lacks DNSSEC validation, so forged records cannot be detected by signature mismatch
- • An on-path attacker (compromised router, BGP hijack, or ARP spoofing on LAN) intercepts DNS queries and injects forged responses
- • A compromised authoritative nameserver or upstream resolver in the recursive chain serves poisoned records
- • The resolver uses a predictable transaction ID space or a fixed source port (UDP 53 → 53), dramatically narrowing the attacker's brute-force space
Diagnosis Steps
Step 1 — Compare resolver output against authoritative source
# Query your local/corporate resolver
dig A suspicious-domain.com
# Query the authoritative nameserver directly (bypasses resolver cache)
dig NS suspicious-domain.com @8.8.8.8 # Find authoritative NS
dig A suspicious-domain.com @<authoritative-ns> # Query authoritative directly
# Compare the two IPs — any discrepancy is a red flag
Step 2 — Verify the IP with Whois and geolocation
If the IP from your resolver differs from the authoritative source:
# Check IP ownership
whois <suspicious-ip>
# Verify ASN
dig -x <suspicious-ip> # PTR lookup
Compare the registered org and ASN against what you expect (e.g., Fastly, Cloudflare, AWS). An IP in an unexpected country or ASN is strong evidence of a poisoned record.
Step 3 — Check TTL for signs of injected records
Legitimate CDN records often have TTLs of 60–300 seconds, so low TTL alone is not conclusive. However, combined with a mismatched IP:
# Check remaining TTL in resolver cache
dig +ttlunits A suspicious-domain.com @127.0.0.53
# Query the authoritative NS for its authoritative TTL
dig A suspicious-domain.com @<auth-ns> | grep -E "^suspicious-domain"
A poisoned record often has a very high TTL set by the attacker to persist as long as possible; or a low one to evade detection by expiring before forensics.
Step 4 — Verify DNSSEC validation status
# Check DNSSEC validation result
dig +dnssec A suspicious-domain.com @8.8.8.8
# Look for "ad" flag (Authenticated Data) in header
# Use a DNSSEC-validating resolver
dig +dnssec +cd A suspicious-domain.com @1.1.1.1
# +cd disables checking — if result differs, validation is failing
# Online tool: https://dnssec-analyzer.verisignlabs.com
drill -D suspicious-domain.com # drill from ldns package
A SERVFAIL response from a DNSSEC-validating resolver when +cd succeeds is a
clear indicator that the DNSSEC chain of trust is broken — consistent with poisoning
of a signed zone.
Step 5 — Flush the resolver cache and re-query
# systemd-resolved
sudo resolvectl flush-caches
# macOS
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder
# Unbound
sudo unbound-control flush_zone suspicious-domain.com
# Windows
ipconfig /flushdns
# Re-query immediately after flush
dig A suspicious-domain.com
If the result changes after flushing, the previous cached record was different from what the resolver's upstream returns today — supporting the poisoning hypothesis.
Step 6 — Capture DNS traffic for forensic analysis
# tcpdump — capture all DNS traffic to/from your resolver
sudo tcpdump -i eth0 -w dns-capture.pcap port 53
# Analyze transaction IDs and source ports for patterns
# Kaminsky attack: attacker floods with many source ports and transaction IDs
# A burst of UDP packets to port 53 from unknown sources is suspicious
tshark -r dns-capture.pcap -Y dns -T fields \
-e frame.time -e ip.src -e dns.id -e dns.qry.name
Solution
Immediate containment
# 1. Flush the poisoned cache entries
sudo resolvectl flush-caches # systemd-resolved
sudo unbound-control flush_zone example.com # Unbound
# 2. Switch all clients to DNSSEC-validating resolvers
# Cloudflare (validates DNSSEC)
nameserver 1.1.1.1
nameserver 1.0.0.1
# Google (validates DNSSEC)
nameserver 8.8.8.8
nameserver 8.8.4.4
Enable DNSSEC validation on your resolver
# Unbound — /etc/unbound/unbound.conf
server:
module-config: "validator iterator"
auto-trust-anchor-file: "/var/lib/unbound/root.key"
harden-dnssec-stripped: yes
# Fetch the root trust anchor
sudo unbound-anchor -a /var/lib/unbound/root.key
# Restart
sudo systemctl restart unbound
# Verify validation works
dig +dnssec A google.com @127.0.0.1
# "ad" flag in header = validation successful
Enable source-port randomization (Unbound)
# /etc/unbound/unbound.conf
server:
outgoing-port-permit: 1024-65535 # Randomize across full ephemeral range
outgoing-num-tcp: 10
use-caps-for-id: yes # 0x20 encoding (additional entropy)
Sign your own zones with DNSSEC
If you operate authoritative DNS for your domain:
# Example with BIND 9
dnssec-keygen -a ECDSAP256SHA256 -n ZONE example.com
dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) \
-N INCREMENT -o example.com -t db.example.com
After signing, publish the DS record at your registrar to complete the chain of trust.
Prevention
- Enable DNSSEC validation on all recursive resolvers — this makes forged records cryptographically detectable regardless of how they entered the cache
- Use DNS over HTTPS (DoH) or DNS over TLS (DoT) to encrypt resolver traffic, preventing on-path interception
- Deploy a resolver that enforces source-port randomization and query-ID randomization (RFC 5452); Unbound, BIND 9.7+, and PowerDNS Recursor all support this
- Sign all zones you control with DNSSEC and publish DS records at the registrar — even if you cannot validate all upstream zones, signed zones cannot be spoofed
- Monitor resolver cache contents for anomalous records using periodic
dig @<internal-resolver>checks against known-authoritative IPs