Bug 208392 - CVE-2006-4572 IPv6/IP6Tables Vulnerabilities
Summary: CVE-2006-4572 IPv6/IP6Tables Vulnerabilities
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 2.1
Classification: Red Hat
Component: kernel
Version: 2.1
Hardware: i386
OS: Linux
high
high
Target Milestone: ---
Assignee: Don Howard
QA Contact: Brian Brock
URL:
Whiteboard: impact=important,source=kernelsec,rep...
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2006-09-28 11:02 UTC by Marcel Holtmann
Modified: 2007-11-30 22:06 UTC (History)
1 user (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2006-10-02 12:50:09 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)

Description Marcel Holtmann 2006-09-28 11:02:56 UTC
Reported by Mark Dowd from McAfee:


1. Upper Layer Protocol Mismatch

A problem exists within the netfilter code that is responsible for matching
upper layer protocols with rules that are installed by ip6tables (using the
protocol "-p" switch) on the system. When a packet is fragmented, the following
code in ip6_packet_match() is executed to evaluate whether the incoming packet
is a match or not:

----

    /* look for the desired protocol header */
    if((ip6info->flags & IP6T_F_PROTO)) {
        int protohdr;
        unsigned short _frag_off;

        protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
        if (protohdr < 0)
            return 0;

        *fragoff = _frag_off;

        dprintf("Packet protocol %hi ?= %s%hi.\n",
                protohdr,
                ip6info->invflags & IP6T_INV_PROTO ? "!":"",
                ip6info->proto);

        if (ip6info->proto == protohdr) {
            if(ip6info->invflags & IP6T_INV_PROTO) {
                return 0;
            }
            return 1;
        }

        /* We need match for the '-p all', too! */

----

This code uses ipv6_find_header() to encapsulate the following logic for
fragmented packets:

a. If the fragment is a 0-offset fragment, cycle through extension headers to
find the upper layer protocol for this packet. If one is not found, return -1.
b. If the fragment is not a 0-offset fragment and the fragment header's nexthdr
value is not an extension header, return it as the upper layer protocol.
c. If the fragment is not a 0-offset fragment and the fragment header's nexthdr
value is an extension header, return -1.

Using these rules, it is possible to create a fragmented packet that incorrectly
evades a match. To illustrate this, consider a scenario where the following rule
is installed:

ip6tables -A INPUT -p udp -j DROP

This rule should drop all UDP packets. This rule can be evaded by sending the
following pair of packets:

[ IP Header (nxthdr=fraghdr) ] [ fraghdr (offset=0, nxthdr=destopts)  ] [
destopts (nxthdr=routeopts) ]
[ IP Header (nxthdr=fraghdr) ] [ fraghdr (offset=X, nxthdr=routeopts) ] [
routeopts (nexthdr=UDP)     ] [ UDP Data ]

The first fragment will not match the DROP udp rule because it doesn't contain a
UDP header, and the second one will not match the rule either because the
fragment offset is non-zero and the nexthdr in the fragment extension is not UDP.

Kernel Versions tested:
    2.6.18
    2.6.16
    2.6.15
    (Others supporting IPv6/IPTables are also suspected to be vulnerable)


2. Extension Header match bypass

The attack described in the previous scenario can also be used to evade rules
that are attempting to block certain extension headers from appearing in the
input packets. This is also due to the way ipv6_find_header() is invoked and the
same rules are essentially followed, except that when a non-zero offset fragment
is encountered the target match will always fail. Consider the following rule:

ip6tables -A INPUT -m rt -j DROP

The following packet pair will evade this rule:

[ IP Header (nxthdr=fraghdr) ] [ fraghdr (offset=0, nxthdr=destopts) ] [
destopts (nxthdr=destopts) ]
[ IP Header (nxthdr=fraghdr) ] [ fraghdr (offset=X, nxthdr=destopts) ] [
destopts (nxthdr=routeopts)] [ routeopts ] ...

Because the option appears in a non 0-offset fragment, the rule fails to match
this packet and it will be successfully delivered

(Same Kernel Versions Tested)

Comment 1 Marcel Holtmann 2006-09-28 12:54:09 UTC
The function ipv6_find_hdr() was first introduced with 2.6.14-rc2 and later
updated with 2.6.16-rc1. The code in question before 2.6.14 and so also in the
RHEL2.1 kernel looks like this:

        /* look for the desired protocol header */
        if((ip6info->flags & IP6T_F_PROTO)) {
                u_int8_t currenthdr = ipv6->nexthdr;
                u_int8_t *hdrptr;
                hdrptr = (u_int8_t *)(ipv6 + 1);
                do {
                        if (ip6info->proto == currenthdr) {
                                if(ip6info->invflags & IP6T_INV_PROTO)
                                        return 0;
                                return 1;
                        }
                        currenthdr = ip6_nexthdr(currenthdr, hdrptr);
                } while(currenthdr);
                if (!(ip6info->invflags & IP6T_INV_PROTO))
                        return 0;
        }


Comment 2 Marcel Holtmann 2006-10-02 12:50:09 UTC
The attack talks about circumventing the possibly installed DROP rule and make
the function return a non-match. RHEL2.1 doesn't seem to be affected to the
fragment rule workaround.



Note You need to log in before you can comment on or make changes to this bug.