djbdns misformats some long response packets; patch and example attack

The DNS packet format allows names to be compressed by replacing the
suffix of a name with an encoded offset to another location in the
packet where the suffix already exists. Because of the encoding
scheme, valid offsets are limited to < 16384.

In djbdns 1.05, response.c handles name compression. Line 12 has a
comment "each < 16384" on the name_ptr array, but response_addname()
from the same file does not enforce this limitation. The result is
that when encoding names with a suffix that first appears >= 16384
bytes into the packet, response_addname() incorrectly tries to encode
an offset to that name and produces a misformatted response packet.
(At the bottom of this email, there is a patch for this.)

You can reproduce an exploit of this bug as follows:

# Download and build ucspi-tcp-0.88.
$ curl -O
$ tar -zxf ucspi-tcp-0.88.tar.gz
$ echo 'gcc -include /usr/include/errno.h -O' > ucspi-tcp-0.88/conf-cc
$ make -C ucspi-tcp-0.88

# Download and build djbdns-1.05.
$ curl -O
$ tar -zxf djbdns-1.05.tar.gz
$ echo 'gcc -include /usr/include/errno.h -O' > djbdns-1.05/conf-cc
$ make -C djbdns-1.05

# Use tcpclient and axfr-get to do a zone transfer for
# from
$ ./ucspi-tcp-0.88/tcpclient 53 \
./djbdns-1.05/axfr-get data data.tmp

# Use tinydns-data to compile data into data.cdb.
$ ./djbdns-1.05/tinydns-data

# Simulate an A query for using the data
# from the zone transfer.
$ ./djbdns-1.05/tinydns-get a

The last command will include these two lines in the output:

additional: foo 8388608 NS
additional: foo 8388608 NS

i.e., poisonous NS records for foo, delegating the domain to
and; with my patch applied, only records within are output. Also, there's significant freedom in
what poisonous records the attacker can produce.

The security hole here is that an administrator that uses djbdns 1.05
to serve DNS content does not expect that configuring his name server
as above will cause it to send records for names outside of I.e., an attacker can trick the administrator's
name servers to include arbitrary DNS records in response to queries
for names within domains he controls. Note that axfr-get is doing the
right thing here: it already strips out names from outside of the
specified zone; it's just that tinydns-get (and so tinydns and
axfrdns) misformat the response packet. A direct NS query for foo
would not generate these poisonous records.

As a real life example, I registered as a secondary
domain with EveryDNS pulling data from my server. I was able to trick
their name servers into serving the above poisonous NS records.
EveryDNS's name servers have no authority over the hypothetical foo
TLD, but I could have included poisonous NS records for
instead. The DNS cache from djbdns 1.05, dnscache, would have
rejected these records as poison, but it's possible other DNS caches
might accept them. (Either way, EveryDNS installed my patch earlier
today, so this is no longer a risk.)

As another example, I registered as a secondary
domain with FreeDNS ( They don't use djbdns, but
if they had, this would have allowed me to include poisonous NS
records for that DNS caches like dnscache and BIND would
have accepted.

Some caveats: this bug only affects domains that serve DNS content
using tinydns and axfrdns (only for DNS queries over TCP; clients do
not need AXFR permissions) from djbdns 1.05 and allow untrusted users
to include arbitrary records (at least about 100 records, totalling
about 30KB of space) within some zone.

In summary: if you use tinydns/axfrdns from djbdns 1.05 to serve
authoritative DNS content and give untrusted users control over
records you serve, I strongly suggest you install this patch. I don't
believe other users are at risk, but they are encouraged to install
this patch as well to be safe.

Finally, here's the promised patch:

--- response.c.orig 2009-02-24 21:04:06.000000000 -0800
+++ response.c 2009-02-24 21:04:25.000000000 -0800
@@ -34,7 +34,7 @@
uint16_pack_big(buf,49152 + name_ptr[i]);
return response_addbytes(buf,2);
- if (dlen <= 128)
+ if ((dlen <= 128) && (response_len < 16384))
if (name_num < NAMES) {
name_ptr[name_num] = response_len;

Relevant Pages

  • Re: We have lots of users with SonicWalls for VPN connectivity in to FW-1, possible major security h
    ... A faster processor in the current Sonicwall firewalls has helped ... DNS name resolution on the fly was enabled for Logging. ... >to pass from the LAN to the WAN. ... >why is my internal server responding to this packet as a "Destination ...
  • Re: Bad packets and invalid domain names Please help
    ... At any rate, it isn't clear whether these errors, or DNS at all, has anything to do with your issues. ... > Source DNS ... > The DNS server has encountered numerous run-time events. ... > The DNS server encountered a bad packet from X.X.X.X. ...
  • Re: Neotrace program snoops on me
    ... >> DNS servers. ... A client starts a traceroute to some computer. ... the TTL field in the IP packet by one. ... > those hops from McAfee's database. ...
  • Re: Cant Resolve Certain internet DNS names
    ... >> Why are some websites using non-RFC compliant packets for DNS? ... > It is not websites it is your DNS server and it is RFC compliant. ... > queries do not fit into one UDP packet, it has always been that way. ... > into one UDP packet and will be trucated if even a few bytes of a DNS ...
  • Re: Cant Resolve Certain internet DNS names
    ... It is not websites it is your DNS server and it is RFC compliant. ... queries do not fit into one UDP packet, it has always been that way. ... > "SmartDefense is able to recognize an illegal DNS packet. ...