#!/usr/bin/perl -dw

#NAME
#  WormScan - Scan apache log for CodeRed worm signature and send email

#SYNOPSIS
#  WormScan [infile] [outfile]

#DESCRIPTION
#  The  apache log file is scanned for evidence of the CodeRed worm, and when
#  it is found, email is sent to the owner of  the  address  block  informing
#  them of the situation.

#REQUIRES
	unshift(@INC, '.', ($ENV{'HOME'} . '/sh'));
	require "AttackMsg.pm";

#OPTIONS
#  We need to know what syntax to use for the whois command:
	$systype = 'linux';

#  Limit the number of messages sent:
	$msglimit = 10;

#EXAMPLES

#FILES
#  Here's the default log file:
	$webdflfile = '/usr/local/apache/logs/access_log';

#  We  write  a record of the successful email addresses, so we won't harrass
#  them too much.  Here is where we write it:
	$ourdflfile = '/usr/local/apache/logs/WormScan_log';

#BUGS

#SEE ALSO

#AUTHOR
#  John Chambers <jc@trillian.mit.edu>

($me = $0) =~ s".*/"";
$V = $ENV{"V_$me"} || 2;
$! = 1;
$" = "\n";
$exitstat = 0;

($ss,$mm,$hh,$DD,$MM,$CY) = gmtime(time);
$CY += 1900;
#$cymd = sprintf('%02d' x 3,$CY,1+$MM,$DD);
$cymdhms = sprintf('%02d' x 6,$CY,1+$MM,$DD,$hh,$mm,$ss);

$weblogfile = shift || $webdflfile;
$ourlogfile = shift || $ourdflfile;

if (open(OLF,$ourlogfile)) {
	for $line (<OLF>) {
		$line =~ s/[\s\r]+$//;
		if ($line =~ m"^\s*$") {
		} elsif ($line =~ m"^\s*#") {
		} elsif ($line =~ m"^([\d.]+)\t([-_.@\w]*)\t([-:/\d\s]+)") {
			print "Done $1 $2 $3\n" if $V>2;
			$Done{"$1\t$3"} = $2 || '-';	# Note this one done.
		}
	}
	close OLF;
} elsif (open(OLF, ">$ourlogfile")) {
	print OLF "# Log of CodeRed messages sent.\n\n";
	close OLF;
}

die "$me: Can't read \"$weblogfile\"\n"
	unless open(WLF, $weblogfile);

die "$me: Can't write \"$ourlogfile\"\n"
	unless open(OLF, ">>$ourlogfile");

print OLF "\n#Scan $weblogfile at $cymdhms\n";

for (<WLF>) {
	if (/"GET \/default.ida\?/) {
		print "Found default.ida =======================================\n";
	}
	if (/^([.\d]+) - - \[(\d\d)\/(\w\w\w)\/(\d\d\d\d):(\d\d:\d\d:\d\d) ([-+]\d\d\d\d)\] "GET \/default.ida\?([NX]+)%u/) {
		print "IP=$1 D=$2 M=$3 Y=$4 hms=$5 tz=$6\n" if $V>2;
		$ipad = $1;		# IP address of perp
		$isod = &ISOdate($4,$3,$2);	# Put date into ISO form
		$time = $5;		# Time of day
		$zone = $6;		# Time zone
		$disc = $7;		# Discriminator between versions
		$idtz = "$isod $time $zone";
		if ($Done{"$ipad\t$idtz"}) {
			print "Sent $ipad\t$idtz message.\n" if $V>1;
			next;
		}
		print "Perp: $ipad $idtz\n" if $V>1;
		&Whois($ipad,$idtz);

		if ($msgs >= $msglimit) {
			print "Message limit exceeded.\n";
			exit 0;
		}
	}
}

close OLF;
exit $exitstat;

sub Whois {
	local(
		$ipad,	# IP address of attacker.
		$idtz)	# Date of attack.
		= @_;
	local($line,$Coord,$Disc,$Eaddr);
	$cmd = ($systype eq 'linux') ? "whois $ipad\@rs.arin.net"
								 : "whois -h rs.arin.net $ipad";
	print "Cmd: $cmd\n" if $V>1;
	for $line (`$cmd`) {
		print "Rsp: $line" if $V>2;
		if ($line =~ /Coordinator:/) {
			$Coord ++;
			print "++++ Coordinator\n" if $V>1;
		} elsif ($line =~ /\)\s+([-._\w\d]+\@[-._\w\d]+)\s*$/) {
			$Eaddr = $1 if $Coord;
			print "++++ Email $Eaddr\n" if $V>1;
		}
	}
	if ($Coord && $Eaddr) {
		print "Send to \"$Eaddr\" (Coord=$Coord)\n" if $V>1;
		if    ($disc =~ /NNNNNNNN/) {$Disc = 'Code Red I'}
		elsif ($disc =~ /XXXXXXXX/) {$Disc = 'Code Red II'}
		else                        {$Disc = 'Code Red'}
		&AttackMsg($ipad,$idtz,$Disc,$Eaddr);
		++$msgs;		# Count the messages sent
	} else {
		print "No address found for $ipad.\n" if $V>1;
		$Eaddr = '-';
	}
	print OLF "$ipad\t$Eaddr\t$idtz\n";
}

sub ISOdate {
	local($y,$m,$d) = @_;
	local(%M) = (
		'Jan' => '01', 'Feb' => '02', 'Mar' => '03',
		'Apr' => '04', 'May' => '05', 'Jun' => '06', 
		'Jul' => '07', 'Aug' => '08', 'Sep' => '09',
		'Oct' => '10', 'Nov' => '11', 'Dec' => '12');
	$m = $M{$m};
	return "$y/$m/$d";
}
