#!/usr/bin/perl # # NOTE: the path to perl must match its path on your system # Most perl installations are either in /usr/bin/perl or in # /usr/local/bin/perl. This script won't run with the wrong path # # This script runs on Perl 5.0.6.1 on OpenBSD. It should run on # any "modern" version of Perl, but it has not been tested on # other platforms or other versions. Please let me know if you # have problems running it - pauls@utdallas.edu. # ######################################################################### # # # This script was written by Paul Schmehl, U of Texas at Dallas, # # however the sigs for the various worms are a result of a cooperative # # effort in AVIEN and the smb_lure was conceived and designed entirely # # by John Morris of Nortel Networks. http://www.avien.org/ # # # # This script is freely available and may be used without first # # requesting my permission and is made available in the hope that it # # will be beneficial in the never-ending fight against worms and other # # infestations of the Internet. This script is a rework of my previous # # shell script - checklogs.sh - and includes a new pager feature # # # ######################################################################### use strict; # first we create some variables. Change these to fit your config and OS # These *should* be the only changes that you need to make my $sambalogs = '/usr/local/samba/logs'; my $backups = '/usr/local/samba/logs/backup'; my $alertlog = '/home/alert.log'; my $mailto = 'abuse.smblure@utdallas.edu,pauls@utdallas.edu'; my $pager = 'paul.schmehl@my2way.com'; my $mailapp = '/usr/bin/mail'; my $cat = '/bin/cat'; my $rm = '/bin/rm'; my $touch = '/usr/bin/touch'; # set this to the level you want 0,1 or more # (sends a page if you get 1 or more consecutive alerts) # requires a text-capable pager - otherwise set to 0 # setting this to 0 disables the pager alerts my $alert_level= '3'; # set this to the frequency that you want the pager level reset # the value is in minutes. If you set it to 60, for example, # after 60 minutes, the alert level is reset to 0. So, if you # get three alerts in a 60 minute period, and then 1 alert 3 hours # later, the "timer" would start all over again. my $alert_frequency = '60'; # the wormlist is a text file with the following format: # string_valueworm_name (see the comments in the file) # where string_value is the string we look for in the # samba logs ( such as "can't locate c$") and worm_name # is the name of the worm, such as Bugbear or Klez my $wormlist = '/home/wormlist.txt'; # You should not need to change anything below this line #******************************************************* # first we load the wormlist into a hash open (WORMLIST, $wormlist) or die "Can't find worm list file $wormlist: $!\n"; while () { next if /\#/; (my $worm_str, $::worm_name) = split /\t/; $worm_str =~ s/(\W)/\\$1/g; $::worms{$worm_str} = $::worm_name; } close (WORMLIST); # next we get a directory list, open each file, check it against # the hash for any matches, and increment a counter if we get any opendir (DIR, $sambalogs) or die "Can't open the directory $sambalogs: $!\n"; while (defined($::log = readdir(DIR))) { next if $::log =~ /^\.\.?$/; if ( -T "/$sambalogs/$::log" ) { $::count = 0; my $IP = ''; my $machinename = ''; my $user = ''; $::worm_name = ''; open (LOG,"/$sambalogs/$::log") or die "Can't open logfile $::log: $!\n";; while () { foreach $::key(keys(%::worms)) { if ( /$::key/i ) { # We have a match $::count++; $::worm_name = $::worms{$::key}; } } chomp $::worm_name; if ( ?name=\[(\w+)]? ) { $user = $1; } if ( ?(\w+)\s*\((\d+\.\d+\.\d+\.\d+)\)\s*closed connection? ) { $machinename = $1; # get the NetBIOS name $IP = $2; # get the IP address } } close(LOG); reset; open (ALERT, ">$alertlog") or die "Can't open alert log $alertlog for writing: $1\n"; if ( $::count > 0 ) { print ALERT "$::count hits of $::worm_name\n"; print ALERT "The IP is $IP\n"; print ALERT "The NetBIOS name is $machinename\n"; print ALERT "The last logged in user was $user\n"; print ALERT "The name of the log file is $::log\n"; } close(ALERT); if ( $::count > 0 ){ system("$mailapp -s \"$::worm_name ALERT!!\" $mailto < $alertlog"); # always send me email alerts } # This next section sends a page based on your choice of alert levels (0, 1 or more) # 0 disables the pager alerts, 1 or more determine the number of email alerts you have # to get before you get a pager alert. The count is reset to 1 after the number that # you choose have occurred. In order for the pager alert to be sent, the timer also # has to be set. If it's set to 0, no page will be sent, even if you've gotten three email alerts. # if you set this script to run through cron every 15 minutes, you might want to get a # page if three alerts are sent in a one hour period. If that's the case, set the values # like this: $alert_level = '3'; $alert_frequency = '60'; This will page you after three # alerts have occurred in a 60 minute time frame, and then it will reset the pager alert. # count. The timer resets based on the interval you have chosen. In order to get a page, # the alert_level has to match your choice *and* the timer must have been set. my $cookie_file = "/tmp/cookie"; unless ( -f $cookie_file ) { system("$touch $cookie_file"); } my $time = time; my $alert_secs = $alert_frequency*60; open (COOKIE, "<$cookie_file") or die "Can't open cookie file for reading: $!\n"; while () { push @::cookies, $_; } close(COOKIE); $::line1 = $::cookies[0]; $::line2 = $::cookies[1]; if ( ($::line1 eq '') || ($::line1 == $alert_level) ) { $::line1 = 1; }else{ $::line1++; } if ( ($::line2 eq '') || ($::line2 == 0) ) { $::line2 = $time; }elsif ( $alert_secs <= ($time - $::line2) ) { $::line2 = 0; # reset the timer $::line1 = 1; # reset the pager alert level } open (COOKIE, ">$cookie_file") or die "Can't open cookie file for writing: $!\n"; print COOKIE "$::line1\n"; print COOKIE "$::line2"; close(COOKIE); unless ($alert_level == 0) { # 0 disables pager alerts if ( ($alert_level == $::line1) && ($::line2 != 0) && ($::count > 0) ) { # if all conditions are met # system("$mailapp -s \"$::worm_name ALERT!!\" $pager < $alertlog") # send me a page. Otherwise } # leave me alone. I'm busy. } } } closedir(DIR); # Now we have one thing left to do. We have to remove all the logfiles in the log # directory. Otherwise we'll keep getting alerts for the same events - not good chdir $sambalogs or die "Can't change directories to $sambalogs: $!\n"; opendir (DIR, $sambalogs) or die "Can't open the directory $sambalogs: $!\n"; while (defined($::log = readdir(DIR))) { next if $::log =~ /^\.\.?$/; next if $::log =~ /cookie/; # don't touch the cookie file, if it's in the same directory next if $::log =~ /backup/; if ( -T $::log ) { $::log = qq{$::log}; system("$cat $::log >> $backups/$::log"); system("$rm -f $::log"); } } closedir(DIR);