You are hereForums / Computers / CentOS server setup and maintenance notes / Preventing DNS cache poisoning attacks with iptables
Preventing DNS cache poisoning attacks with iptables
About a week ago I started noticing several odd entries in the DNS log digest. The entries either looked like:
client 208.76.253.253 query (cache) './NS/IN' denied: 19406 Time(s)
or something like:
client 70.86.80.98 query (cache) 'acihldaaaafwx0000dgaaabaaafbjmok/NS/IN' denied: 1 Time(s)
with the second form repeated possibly hundreds of times with minor changes in the cache query string. I had read about the theoretical possibility of DNS cache poisoning several months ago and had dully updated my DNS software. It looked like several people were attempting "brute force" cache poisoning attacks with the minimum consequence to me being the huge number of rejected queries making my logs difficult to use for diagnosing other problems and possibly much more serious consequences if the cache poisoning attcks succeeded.
On the plus side, brute force, cache poisoning attacks are about as subtle as an artillery barrage. Not only was it easy to see that I was being attacked but I could get immediate feedback as to how well my various attempts the thwart the attacks were working. For the first few attackers I simply added a firewall rule to block DNS queries from the source IP address. Obviously, this approach doesn't scale and, even worse, leaves me either constantly monitoring my logs for new attacks or only responding to a new attack the day after the attack started.
The typical defense against a brute force attack is to find a mechanism to throttle the attack thus decreasing the possibility that the attack will succeed in any sort of a reasonable time frame. Unfortunately, my DNS software, Linux named, doesn't appear to have any internal mechanism for rate limiting queries such as the cache poisoning attacks. At this point I turned to iptables to see if there was a way to rate limit such attacks at my firewall.
I had previous run across, implemented and wrote up on this blog a method for rate limiting ssh password guessing using iptables. A little study of those firewall rules plus the iptables man page led me to try the following:
# Block cache poisoning attacks
# Drop repeated DNS requests
-A RH-Firewall-1-INPUT -p udp -m udp -m recent -i eth0 --dport 53 \
--update --seconds 660 --hitcount 7 --name DNSTHROTTLE --rsource -j DROP
-A RH-Firewall-1-INPUT -p udp -m udp -m recent -i eth0 --dport 53 \
-j ACCEPT --set --name DNSTHROTTLE --rsource
These two rules work together the rate limit DNS queries. The upper rule does not affect an initial DNS query (legitimate or otherwise). The second rule fires on an initial DNS query and results in an entry in an in memory file at /proc/net/ipt_recent/DNSTHROTTLE for the querying IP address. Subsequent queries from the same IP address result in updates to the entry for the IP address. An IP address that is responsible for a cache poisoning attack ends up looking like:
...
src=76.9.16.171 ttl: 51 last_seen: 3885028762 oldest_pkt: 6 3884715602, 3884778257, 3884840874, 3884903511, 3884966150, 3885028762, 3883776150, 3883838769, 3883901394, 3883964056, 3884026668, 3884089307, 3884151949, 3884214569, 3884277203, 3884339845, 3884402452, 3884465129, 3884590331, 3884652970
...
The key to this rule set working is that multiple queries from the same IP address must be received within a fairly short amount of time. In my case, I came up with seven queries within eleven minutes. I originally started with ten queries within ten minutes but then found someone attempting a cache poisoning attack with the attack queries coming a little over a minute apart and thus not being caught.
I should also point out that I specified "-i eth0" which is the "external" NIC on my DNS server. Internal queries never hit these rules so lots of DNS requests from an internal box aren't a problem (and if an internal IP address is responsible for a cache poisoning attck, I'd suggest dealing with the problem by simply shutting down the offending system).
Somewhat humorously, this defense against cache poisoning relies on DNS caching at some level to ensure that legitimate queries aren't prevented along with cache poisoning attacks. Given a legitimate DNS query, the results of the query end up being cached at a minimum at the querier's nameserver. Susequent requests from a valid user are answered using the cached entry and don't result in another query to my nameserver.
This approach works well for small operations such as mine that only provide name services for a single or small number of domains. Unfortunately, it doesn't scale to the ISP or hosting provider level since multiple, legitimate requests for different domain names by a peer ISP or hosting provider are indistinguishable at the firewall from a cache poisoning attack. That is the nameserver at the one hosting provider may need to fire off multiple requests for different domains hosted at the peer provider within a short enough period of time that the requests trigger the multiple requests rule.
Unfortunately, I don't have a solution to this problem although more sophisticated logic may be an answer. Again, brute force attacks are as subtle as an artillery barrage. It should be possible to detect the ongoing queries and build up a block list of offending IP addresses. I'll leave that an an exercise to someone who is also in a position to test the rules they come up with.
Cheers,
Dave
![DaveAtFraud on Technorati [Technorati Profile]](http://davenjudy.org/me.jpg)

![Validate my RSS feed [Valid RSS]](http://davenjudy.org/valid-rss.png)