From: Willy TARREAU 
Subject: Simple TCP service can hang a system

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).


-------------------- 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 netinet/in.h
#include netinet/ip.h
#include netinet/udp.h
#include netdb.h
#include stdlib.h
#include string.h
#include stdio.h
#include ctype.h
#include errno.h

[snip...]

    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);

[snip...]


-------------------- 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)