Harden BIND9 Against Cache Poisoning

By Charlie Schluting | Apr 8, 2005 | Print this Page

DNS cache poisoning has been around since 1993. The concept behind cache poisoning is to simply inject false information into a DNS server, where it will be cached. Then, when an unsuspecting user connects to, say, their bank's website, they are actually connecting to the IP address of an attacker. With phishing attacks on the rise, the DNS cache poisoning technique has many more uses in today's Internet. In this article we will examine how cache poisoning works, and also how to make sure your DNS servers aren't vulnerable.

How Is This Even Possible?
There are historically three reasons cache poisoning is possible. Back in 1993, ISC's BIND DNS server was allowing extra information to be included with replies. This means that all an attacker had to do was initiate a query, causing the vulnerable DNS server to ask the attacker's server for DNS data, and then in the response could include any malicious information they wanted to. This was, of course, a bug and fixed in a subsequent release of BIND.

The next vulnerability was in BIND 4, circa 1997. CERT advisory CA-1997-22 uncovered the fact that BIND's transaction ID numbers were sequential. Attackers could no longer simply send evil data to a DNS server, but they instead had to guess the next transaction ID, and send the data spoofing the ID. The attacker's only hurdle was to guess the IP source port of a legitimate request from the victim DNS server. This turned out to be trivial, since BIND was in the habit of using the same port over and over again for most DNS transactions. The transaction IDs were randomized to fix this problem.

Today, there still exist problems. BIND 8 and BIND 9 both have problems generating truly random transaction IDs. A transaction ID is a 16 bit number (i.e. 1-65536) that identifies a single DNS transaction. BIND 9 uses the operating system's /dev/random device, so the randomness is much better than existed in version 8. In BIND 8, utilizing the mathematical anomaly known as the "Birthday Attack," an attacker can correctly guess the transaction ID for a DNS request in less than 600 tries. Of course, this would need to be done before the real DNS server had a chance to respond. A simple denial of service attack on the real DNS server will slow it down enough to allow the attacker time to run through 600 transaction IDs. 600 packets is a trivial amount, and anyone with a broadband connection can execute this attack successfully.

All may seem hopeless at this point, but don't worry, it gets even worse: There are statistical methods to guess how likely a random number is to appear from a given random number generator. BIND 8's generator predictably churns out very similar numbers, making the amount of guessing an attacker needs to do extremely small. BIND 9, however, does a much better job. Another DNS server, djbdns, does an even better job because it randomizes the source port as well as the transaction ID.

Continued on page 2: Protecting Yourself

Continued From Page 1

Protecting Yourself
I think we can all agree that upgrading to BIND 9 is a good idea at this point. The remainder of this article shows how to make cache poisoning nearly impossible, and the configuration assumes a BIND 9 installation.

There are two types of DNS lookups: iterative and recursive. Iterative lookups mean that the DNS answer will be "go look here for the answer." Recursive lookups mean that the DNS server queried will find out the answer, and then return it to the person who asked the question. The normal client computer that isn't running a DNS server needs to be able to ask a recursive DNS server, since it won't understand how to "go look elsewhere."

The best method for protecting your site from DNS cache poisoning is to not allow recursive lookups from unknown sources. There will be no chance for malicious people to inject false information if you aren't serving queries on their behalf. This means that your server should not answer authoritatively for zones it doesn't control, unless the query came from an internal computer trying to use the server for all its DNS information. Some people will claim this doesn't help, since the attacker can just spoof an internal IP address; but we have already read about border security and know that our ingress filters will stop that, right?

BIND 9 provides an excellent method for accomplishing this, but unfortunately the default configuration provides no protection.

A quick example in BIND 9.3.x terms shows how to set this up:

  //Put all your "trusted" IPs in here. acl "inside" {  127/8;
10.0.10/24; 192.168.1/24; };

 //zone declarations go here.  view "inside" {  match-clients {
"inside"; };  recursion yes;  };

 //Same zone declarations go here too.  view "outside" {  match-clients
{ any; };  recursion no;  }; 

The important line to note is "recursion no."

BIND 9 will honor the fact that we don't want to do recursive lookups for untrusted clients who match the "outside" view. It is really that simple. There is no more worrying about the mathematical reasoning behind guessing transaction IDs, because it no longer matters when we don't respond to unknown requestors (excluding authoritative responses about our own zones).

ISC's BIND has had many run-ins with security issues, partly because it has been around since the dawn of Internet time. Dr. Bernstein's djbdns is quite secure, and worth considering. He even offers a monetary reward if someone finds a security hole in his software, but guessing a transaction ID after 1 million attempts isn't a "hole." With djbdns, remember, the port numbers used to talk to a client are random too. This simple practice yields a much more secure DNS implementation, with regards to securing transactions and preventing cache poisoning. Look for ISC to follow in djb's footsteps, eventually.