#!/usr/bin/perl -w # Nimda Notifyer 1.3 # Copyright (C) 2001 Trevor Peirce # Reporting tool for Code Red-like worm that's taking down networks. # This tool will look up IP addresses and send an email to the administrator # of a machine "gone bad" scanning everybody. # The idea came from an anti-Code Red script I saw once, though I don't know # where and didn't feel like digging. # Any improvements are welcome - trev@digitalcon.ca # Enjoy! ####################################################################### # CHANGES ###################################################################### # Release 1.0 - Wednesday, September 19, 2001 # - Initial Release # # Release 1.1 - Friday, September 21, 2001 # - added a debug mode # - fixed major problem with ARIN sub delegations (they were being # ignored) # - added ability to submit IPs to a Nimda-Registry of infected # hosts, see http://worm.jungnickel.com/ for details # - added timestamp to email letter # - improved documentation in configuration section. # # Release 1.2 - Friday, October 5, 2001 # - corrected syntax for gmtime() to eliminate warnings in error log # - added support for APNIC delegations # - added X-Mailer: Nimda Notifyer to email headers # - fixed omission of netblk owner's name when there was no comma # # Release 1.3 - Saturday, October 6, 2001 # - added option to summerize action taken in server's error log # ###################################################################### use strict; use CGI::Carp qw(fatalsToBrowser); use Net::Whois::Raw; use File::Cache; use LWP::UserAgent; $|++; use vars qw($version $fromaddr $subject $sendmail $bcc $submitip $debug $verbose); ###################################################################### #### Configuration # This is who the email appears to be from. Remember to escape @'s # if you change this address, or to use single quotes. # Default: SERVER_ADMIN from Apache's configuration $fromaddr = "$ENV{SERVER_ADMIN}"; # This is the subject of the email being sent. REMOTE_ADDR = remote ip # Default: Nimda Detected - $ENV{REMOTE_ADDR} $subject = "Nimda Detected - $ENV{REMOTE_ADDR}"; # The path to sendmail. This should work fine for most. # Default: /usr/bin/sendmail -t $sendmail = "/usr/bin/sendmail -t"; # Send a BCC of every email to the From address. 1=on, 0=off # Default: 1 $bcc = 1; # Automatically submit IPs to Nimda-Registry. See # http://worm.jungnickel.com/ for more information about their site. # 1=on, 0=off # Default: 1 $submitip = 1; # Verbose mode. When enabled, a message will be left in your error log # indicating the detected IP, and the results of the lookup. 1=on, 0=off # Default: 1 $verbose = 1; # Debug mode. If debug is on, no emails are actually sent. Instead # the email that would be sent is displayed at the bottom, after # the results. 1=on, 0=off # Default: 0 $debug = 0; #### End Configuration ###################################################################### $version = "Nimda Notifyer 1.3"; my $header = ""; if ($debug) { $header = "

Debug Mode

\n"; $fromaddr =~ s/Debug Mode automatically enabled -- you are not Nimda ;)\n"; $debug++; $fromaddr =~ s/whois $ip@" if $debug; if ($ip =~ /^(61|202|203|210|211|218)\./) { print "whois.apnic.net\n\n" if $debug; $server="APNIC"; $wr = Net::Whois::Raw::_whois($ip,"whois.apnic.net",0,[]); } else { print "whois.arin.net\n\n" if $debug; $server="ARIN"; $wr = Net::Whois::Raw::_whois($ip,"whois.arin.net",0,[]); } print "$wr" if $debug; my @email; if ($server eq "ARIN") { unless ((@email = coordlisted($wr)) > 1) { # Perhaps it's further delegated my ($company, $block) = findhandle($wr); print "
No coordinator found. Looking up info for $company" . "($block)\n" if $debug; print "
whois !$block\n\n" if $debug;
		my $contact = Net::Whois::Raw::_whois("!" . $block, "whois.arin.net",0,[]);

		print "$contact
" if $debug; unless ((@email = coordlisted($contact)) > 1) { # Give up print "Couldn't find coordinator in sub delegation either. Giving up.\n"; warn "Unable to find email address for administrator of $ip using ARIN. Giving up.\n"; exit; } } } elsif ($server eq "APNIC") { # Pick out the contact name from the results if ($wr =~ /person: +(.+)/) { $email[0] = $1; } else { $email[0] = "Whom It May Concern"; } # Pick out the email address from the results if ($wr =~ /e\-mail: +(.+)/) { $email[1] = $1; } else { print "Unable to find email address. Giving up.\n"; warn "Unable to find email address for administrator of $ip using APNIC. Giving up.\n"; exit; } } print "
"; print "Sending report to $email[0] ($email[1])...
\n"; sendletter(@email, $ip); submitnr($ip) if $submitip and not $debug; exit; #### Subs below #### sub checkcache { my $ip = shift; my $cache = new File::Cache( { namespace => 'NimdaWorm', expires_in => 86400, filemode => 0600 } ); my $cr = $cache->get($ip); if ($cr) { return 1; } else { $cache->set($ip, 1); return; } } sub coordlisted { my $wr = shift; # whois results if ($wr =~ /Coordinator:/) { if ($wr =~ /^(.+) \(.+?\) (.+?\@.+)$/m) { return $1, $2; } } return undef; } sub findhandle { my $wr = shift; # whois results my @res; while ($wr =~ /^(.*?) \((.+?)\)/mg) { unshift(@res, $1,$2); #print "

Delegated to: \"$1\" ($2)
"; } print "

Delegated to: $res[0] ($res[1])
"; return $res[0], $res[1]; } sub submitnr { my $ip = shift; my $ua = LWP::UserAgent->new; my $req = HTTP::Request->new(HEAD => 'http://worm.jungnickel.com/?action=submit&type=nimda&ip=' . $ip); my $res = $ua->request($req); if ($res->is_success) { print "Successfully submitted $ip to the Nimda Registry at http://worm.jungnickel.com
\n"; } else { print "There was a problem submitting $ip to the Nimda Registry: " . $res->status_line . "
\n"; } } sub sendletter { my $name = shift; my $addr = shift; my $ip = shift; # Change the name from "Last, First" to "First Last" + kill leading whitespace if ($name =~ /^ *(.+?), *(.+)$/) { $name = "$2 $1"; } # If the email address belongs to RIPE, do not send!! (patches, anyone?) if ($addr eq 'nicdb@RIPE.NET') { print "Nope, looks like you're a lucky one. RIPE support will come soon however.\n"; return; } if ($debug) { *MAIL = *STDOUT; print "
\n";
	}
	else {
		open(MAIL, "|$sendmail") || die "can't open pipe to $sendmail: $!";
	}
	print MAIL "To: $addr\n";
	print MAIL "BCC: $fromaddr\n" if ($bcc);
	print MAIL "From: $fromaddr\n";
	print MAIL "Subject: $subject\n";
	print MAIL "X-Mailer: $version\n\n";
	print MAIL "$name,\n\n";
	print MAIL "    This is an automated email from $ENV{SERVER_NAME}.  It appears\n";
	print MAIL "as though you are listed as the coordinator for the netblock from\n";
	print MAIL "which a Windows NT machine appears to have been infected with the\n";
	print MAIL "Nimda worm.\n\n";
	
	print MAIL "    The IP address of the infected machine is $ip.  This\n";
	print MAIL "was detected on " . gmtime() . " GMT.  Please either remove\n";
	print MAIL "the worm or disconnect the machine from the Internet until you have\n";
	print MAIL "the chance to do so.  It is using up not only your bandwidth but\n";
	print MAIL "everybody else's too.\n\n";
	
	print MAIL "    Here are a few links with information about this worm:\n\n";
	print MAIL 'http://www.sarc.com/avcenter/venc/data/w32.nimda.a@mm.html' . "\n";
	print MAIL "http://www.newsbytes.com/news/01/170225.html\n\n";
	
	print MAIL "Thank you for your attention,\n";
	print MAIL "Administrator of $ENV{SERVER_NAME}";
	close MAIL unless $debug;
	print "

\n" if $debug; warn "Sent report to $name <$addr> regarding $ip.\n"; }