Exploit-DB #17097
Description: IPComp - encapsulation Kernel Memory Corruption
Type: dos
Platform: bsd
Date: 2011-04-01
Author: Tavis Ormandy

Exploit:
// source: http://lists.grok.org.uk/pipermail/full-disclosure/2011-April/080031.html

BSD derived RFC3173 IPComp encapsulation will expand arbitrarily nested payload
-------------------------------------------------------------------------------

Gruezi, this document describes CVE-2011-1547.

RFC3173 ip payload compression, henceforth ipcomp, is a protocol intended to
provide compression of ip datagrams, and is commonly used alongside IPSec
(although there is no requirement to do so).

An ipcomp datagram consists of an ip header with ip->ip_p set to 108, followed
by a 32 bit ipcomp header, described in C syntax below.

struct ipcomp {
    uint8_t     comp_nxt;       // Next Header
    uint8_t     comp_flags;     // Reserved
    uint16_t    comp_cpi;       // Compression Parameter Index
};

The Compression Parameter Index indicates which compression algorithm was used
to compress the ipcomp payload, which is expanded and then routed as requested.
Although the CPI field is 16 bits wide, in reality only 1 algorithm is widely
implemented, RFC1951 DEFLATE (cpi=2).

It's well documented that ipcomp can be used to traverse perimeter filtering,
however this document discusses potential implementation flaws observed in
popular stacks.

The IPComp implementation originating from NetBSD/KAME implements injection of
unpacked payloads like so:

    algo = ipcomp_algorithm_lookup(cpi);

    /* ... */

    error = (*algo->decompress)(m, m->m_next, &newlen);

    /* ... */

    if (nxt != IPPROTO_DONE) {
        if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
            ipsec4_in_reject(m, NULL)) {
            IPSEC_STATINC(IPSEC_STAT_IN_POLVIO);
            goto fail;
        }
        (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
    } else
        m_freem(m);

    /* ... */

Where inetsw[] contains definitions for supported protocols, and nxt is a
protocol number, usually associated with ip->ip_p (see
http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml), but in
this case from ipcomp->comp_nxt. m is the mbuf structure adjusted to point to
the unpacked payload.

The unpacked packet is dispatched to the appropriate protocol handler
directly from the ipcomp protocol handler. This recursive implementation fails
to check for stack overflow, and is therefore vulnerable to a remote
pre-authentication kernel memory corruption vulnerability.

The NetBSD/KAME network stack is used as basis for various other
operating systems, such as Xnu, FTOS, various embedded devices and
network appliances, and earlier versions of FreeBSD/OpenBSD (the code
has since been refactored, but see the NOTES section regarding IPComp
quines, which still permit remote, pre-authentication, single-packet,
spoofed-source DoS in the latest versions).

The Xnu port of this code is close to the original, where the decompressed
payload is recursively injected back into the toplevel ip dispatcher. The
implementation is otherwise similar, and some alterations to the testcase
provided for NetBSD should make it work. This is left as an exercise for the
interested reader.

--------------------
Affected Software
------------------------

Any NetBSD derived IPComp/IPSec stack may be vulnerable (Xnu, FTOS, etc.).

NetBSD is not distributed with IPSec support enabled by default, however Apple
OSX and various other derivatives are. There are so many NetBSD derived network
stacks that it is infeasible to check them all, concerned administrators are
advised to check with their vendor if there is any doubt.

Major vendors known to use network stacks derived from NetBSD were pre-notified
about this vulnerability. If I missed you, it is either not well known that you
use the BSD stack, you did not respond to security@ mail, or could not use pgp
properly.

Additionally, administrators of critical or major deployments of NetBSD (e.g.
dns root servers) were given advance notice in order to deploy appropriate
filter rules.

Exploitability of kernel stack overflows will vary by platform (n.b. a stack
overflow is not a stack buffer overflow, for a concise definition see
TAOCP3,V1,S2.2.2). Also note that a kernel stack overflow is very different
from a userland stack overflow.

For further discussion, including attacks on other operating systems,
see the notes section on ipcomp quines below.

--------------------
Consequences
-----------------------

While exploitation of kernel stack overflows is a somewhat under researched
topic, the author feels a skilled attacker would be able to leverage this for
remote code execution. However, this is not a trivial task, and is highly
platform dependent.

I have verified kernel stack overflows on NetBSD are exploitable, I have looked
at the source code for xnu and do not see any obvious obstacles to prevent
exploitation (kernel stack segment limits, guard pages, etc. which would cause
the worst impact to be limited to remote denial of service), so have no reason
to believe it is different.

Thoughts on this topic from fellow researchers would be welcome.

Source code for a sample Linux program to reproduce this flaw on NetBSD is
listed below. Please note, check if your system requires an IPv4 header in the
compressed payload before attempting to adapt it to your needs.

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <zlib.h>
#include <alloca.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

//
// BSD IPComp Kernel Stack Overflow Testcase
//  -- Tavis Ormandy <taviso at cmpxchg8b.com>, March 2011
//

#define MAX_PACKET_SIZE (1024 * 1024 * 32)
#define MAX_ENCAP_DEPTH 1024

enum {
    IPCOMP_OUI          = 1,
    IPCOMP_DEFLATE      = 2,
    IPCOMP_LZS          = 3,
    IPCOMP_MAX,
};

struct ipcomp {
    uint8_t     comp_nxt;       //