xorl %eax, %eax

dns2tcp Remote Integer Underflows (2008)

with one comment

dns2tcp is a really useful utility for quickly implementing DNS tunnels. You can use it to pass DNS traffic and convert it to DNS on the server side of the application. This way you can easily pass through many restrictions that do not apply on DNS protocol on your local network. Anyway, the code was taken from dns2tcp 0.4.0 release. The first bug can be found at common/dns.c:

115  void            dns_simple_decode(char *input, char *output, int max_len)
116  {
117    int         len;
118    char          *ptr;
119    int           total_len =0;
120
121    ptr = input;
122    *output = 0;
123    while (*ptr)
124      {
125        len = (int) *ptr;
126        total_len +=len;
127        if (total_len > max_len)
128          break;
129        strncat(output, ptr + 1, len);
130        output[total_len] = 0;
131        ptr += (len + 1);
132      }
133  }

This function is used directly on the data client received. If integer at line 117 can contain a value larger than 0x7ffffff which means that it will wrap around zero and result in a negative number, it’ll truncate the total_len at line 126 to contain a negative number too, this way it’ll pass the check at line 127 and continue overflowing that output buffer at lines 129-131. This was simply fixed by replacing the signed integer with an unsigned like this:

@@ -114,7 +114,7 @@
 void           dns_simple_decode(char *input, char *output, int max_len)
 {
-  int          len;
+  uint8_t      len;
   char         *ptr;
   int          total_len =0;
  
@@ -122,7 +122,7 @@
   *output = 0;
   while (*ptr)
     {
-      len = (int) *ptr;
+      len = (uint8_t) *ptr;
       total_len +=len;

The next overflow, was at server/dns_decode.c which is an implementation for decoding DNS packets for the server side of the application. Here is the bug:

77  int             dns_decode(char *data, char *input, char *output, t_conf *conf,
78                             struct sockaddr_in *sa)
79  {
80    int           max_compress_depth = MAX_COMPRESS_DEPTH;
81    int           total_len = 0;
82    int           len;
83    char          *ptr;
84
85    ptr = input;
86    *output = 0;
87
88    while ((max_compress_depth) && (*ptr))
89      {
90        len = (int) *ptr;
91        total_len += len;
     ...
107        strncat(output, ptr + 1, len);
108        output[total_len] = 0;
     ...
119    return (dns_strip_subdomain(output, conf, sa));
120  }

It’s the same signedness issue at lines 82 and 91. Consequently, this was patched like this:

@@ -79,7 +79,7 @@
 {
   int          max_compress_depth = MAX_COMPRESS_DEPTH;
   int          total_len = 0;
-  int          len;
+  uint8_t      len;
   char         *ptr;
   ptr = input;
@@ -87,7 +87,8 @@

   while ((max_compress_depth) && (*ptr))
     {
-      len = (int) *ptr;
+      // Oups ...
+      len = (uint8_t) *ptr;
       total_len += len;

This bug was disclosed on 4 September 2008 but since I could recall this from heart I decided to write down this little post.

Written by xorl

March 9, 2009 at 16:48

Posted in bugs

One Response

Subscribe to comments with RSS.

  1. CVE-2008-3910

    Jericho

    April 3, 2009 at 09:52


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s