Ethereal-dev: Re: [ethereal-dev] DNS exploits

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Tue, 11 Apr 2000 22:57:25 -0700
On Tue, Apr 11, 2000 at 04:48:09PM -0500, Gilbert Ramirez wrote:
> On Tue, Apr 11, 2000 at 03:16:34PM -0500, Gilbert Ramirez wrote:
> > 
> > 
> > On Tue, Apr 11, 2000 at 12:35:41PM -0500, Gilbert Ramirez wrote:
> > >
> > >
> > > At packetstorm.securify.com, I searched for "ethereal" and found
> > > "zlip.tar.gz", which contains 3 exploits of DNS resolution:
> > >
> > > 
> > http://209.143.242.119/cgi-bin/search/search.cgi?searchvalue=ethereal&type=archives&search.x=25&search.y=23
> > >
> > 
> > Attached is a very quick patch which keeps Ethereal from hanging on the
> > 3 sample traces of this exploit. This is just a quick fix; I haven't looked
> > in detail to see if this is the best (or even proper!) fix.
> > 
> > --gilbert
> > 
> >  - zlip-fix.diff
> 
> FYI, here is a more in-depth discussion of the zlip exploit:
> 
> http://www.securiteam.com/exploits/Weaknesses_in_DNS_label_decoding_can_cause_a_Denial_of_Service.html
> 
> and
> 
> http://www.oamk.fi/~jukkao/bugtraq/9906/0005.html

The latter one might be based on older Ethereal code, as we don't do DNS
name uncompression recursively any more, and, whilst the buffer into
which we uncompress is fixed-length, we bounds-check it.

His third exploit just claimed to be multiple decompressions of a long
label; however, as I read RFC 1035, you can have only *one* pointer in a
domain name:

	4.1.4. Message compression
      
	In order to reduce the size of messages, the domain system utilizes a  
	compression scheme which eliminates the repetition of domain names in a 
	message.  In this scheme, an entire domain name or a list of labels at 
	the end of a domain name is replaced with a pointer to a prior occurance
	of the same name.

	The pointer takes the form of a two octet sequence:
      
	    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
	    | 1  1|                OFFSET                   |
	    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      
	The first two bits are ones.  This allows a pointer to be distinguished
	from a label, since the label must begin with two zero bits because
	labels are restricted to 63 octets or less.  (The 10 and 01 combinations
	are reserved for future use.)  The OFFSET field specifies an offset from
	the start of the message (i.e., the first octet of the ID field in the
	domain header).  A zero offset specifies the first byte of the ID field,
	etc. 

	The compression scheme allows a domain name in a message to be
	represented as either:
     
	   - a sequence of labels ending in a zero octet

	   - a pointer

	   - a sequence of labels ending with a pointer

I have a version of "packet-dns.c" that uses checks similar to those
used by the BSD resolver and by BIND, where it counts the total number
of characters at which it's looked when expanding a name, and if, when
it sees a pointer, it's already looked at all of the characters in the
message, it concludes that there must be a loop.

However, it looks as if the BIND/BSD resolver code does *not* quit after
processing a pointer, so that it would treat the packet from his third
exploit as a loop.  I guess it's assuming that a pointer has to point to
a valid domain name, so that, as there must be a pointerless domain name
at the bottom of the pile, and as a pointerless domain name must have a
zero-length label at the end:

	3. DOMAIN NAME SPACE AND RR DEFINITIONS

	3.1. Name space definitions

	Domain names in messages are expressed in terms of a sequence of labels.
	Each label is represented as a one octet length field followed by that
	number of octets.  Since every domain name ends with the null label of 
	the root, a domain name is terminated by a length byte of zero.  The   
	high order two bits of every length octet must be zero, and the   
	remaining six bits of the length field limit the label to 63 octets or
	less.

unless there's a loop (in which case its loop detection will stop it),
it'll eventually stop.

This may be done in order to allow a pointer to point to "a sequence of
labels ending with a pointer" without complicating the code.  I'll look
into asking Paul Vixie about this.

Our current code works similarly, so it also treats it as a loop.

It looks as if the third exploit program may also be based on a
misreading of RFC 1035, as 1035 doesn't seem to support multiple
pointers in a name as I read the above, unless a pointer is considered
to be a label (which I don't read 1035 as saying it is), but he seems to
be assuming it does.

I'll run a bunch of regression tests on the code I currently have
(Tethereal comes in handy here...), and check it in.