xorl %eax, %eax

CVE-2009-0692: ISC DHCP Client Stack Based Buffer Overflow

leave a comment »

This issue was reported by Mandriva Linux Engineering Team as CERT states. dhclient is a DHCP client application which is used in numerous major distributions including Debian, Gentoo, Ubuntu etc. According to ISC this vulnerability affects all versions of 4.1, 4.0, 3.1, 3.0 and 2.0 releases. Here is the buggy code as seen in 4.1.0 release of ISC’s DHCP implementation.

void script_write_params (client, prefix, lease)
        struct client_state *client;
        const char *prefix;
        struct client_lease *lease;
{
        int i;
        struct data_string data;
        struct option_cache *oc;
        struct envadd_state es;

        es.client = client;
        es.prefix = prefix;
        ...
        memset (&data, 0, sizeof data);
        oc = lookup_option (&dhcp_universe, lease -> options, DHO_SUBNET_MASK);
        if (oc && evaluate_option_cache (&data, (struct packet *)0,
                                         (struct lease *)0, client,
                                         (struct option_state *)0,
                                         lease -> options,
                                         &global_scope, oc, MDL)) {
                if (data.len > 3) {
                        struct iaddr netmask, subnet, broadcast;

                        memcpy (netmask.iabuf, data.data, data.len);
                        netmask.len = data.len;
                        data_string_forget (&data, MDL);
        ...
        client_envadd (client, prefix, "expiry", "%d", (int)(lease -> expiry));
}

The above routine can be found at client/dhclient.c. As you can see, if lookup_option() returns a non-NULL value, meaning that there is some DHO_SUBNET_MASK option cache, and the user controlled data length (which was retrieved using evaluate_option_cache()) is more than three, it will initialize three iaddr structures and it will attempt to copy data.len bytes from data.data to netmask.iabuf. Of course, since both data.len and data.data are user controlled variables, the user could create an overflow situation by copying more bytes than netmask can contain. For completeness, from includes/dhcpd.h we can see that the option cache structure is defined like:

struct option_cache {
        int refcnt;
        struct option_cache *next;
        struct expression *expression;
        struct option *option;
        struct data_string data;

        #define OPTION_HAD_NULLS        0x00000001
        u_int32_t flags;
};

The user controlled, data_string structure from includes/tree.h:

/* A string of data bytes, possibly accompanied by a larger buffer. */
struct data_string {
        struct buffer *buffer;
        const unsigned char *data;
        unsigned len;   /* Does not include NUL terminator, if any. */
        int terminated;
};

And finally, from includes/inet.h the structure that we can overflow is:

struct iaddr {
        unsigned len;
        unsigned char iabuf [16];
};

This was fixed by applying the following patch.

                if (data.len > 3) {
                        struct iaddr netmask, subnet, broadcast;

-                       memcpy (netmask.iabuf, data.data, data.len);
-                       netmask.len = data.len;
+                       /*
+                        * No matter the length of the subnet-mask option,
+                        * use only the first four octets.  Note that
+                        * subnet-mask options longer than 4 octets are not
+                        * in conformance with RFC 2132, but servers with this
+                        * flaw do exist.
+                        */
+                       memcpy(netmask.iabuf, data.data, 4);
+                       netmask.len = 4;
                        data_string_forget (&data, MDL);

As you can see, it will *always* copy just 4 bytes regardless of what the data.len contains. Of course, this vulnerability requires server-side control in order to trigger it since it is located in the client’s code.

Written by xorl

July 15, 2009 at 21:07

Posted in bugs

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