Sep 2010

Simple Snort Alert Log Parsing Script

Snort Intrusion Detection Software (IDS) is a great out of the box easy to use system to monitor a network for possible threats. While there are many ways to receive alerts, one very simple approach is to periodically parse the alert log and simply mail alerts to whom it may concern. In this text a simple example of parsing a snort alert log using Perl. Note this alerter could probably be used for other loggers and there exist other tools available like Splunk which might be more suited for larger installations. The thesis of this text is to show how a relatively useful utility can be quickly hacked together to provide an elegant solution.

Since this text has the time to think logically (the author didn't) here is some pseudo code that expresses the idea of how this particular parser will work. For the time being the script is interested in priority 1 and priority 2 alerts:

	Read the alert log into an array
	loop over alert log
		priority 2 alert?
			if yes, start appending lines temp file until \
	          next alert entry
		priority 1 alert?
			if yes, start appending lines temp file until \
	          next alert entry
	end loop alert log

	did we find alerts?
		yes
			stop snort
			backup the alert file
			start snort
			mail tmp file
			delete tmp file
		no
			exit program

Sure seems simple enough. Of course there is more to it. First up the helper subroutines. Only one is needed since the only repeated operation that is being performed is (possibly) appending alert log lines to a temporary file that will be mailed to the administrator:

sub appendfile {
    my ($fp, $msg) = @_;

    if (open(FILE, ">>$fp")) {
        print FILE ("$msg");
        close FILE;
    } else {
		die ("Could not open $fp!");
	}
}

With the one subroutine complete now a look at the variables the script will need:

my $logdir = "/var/log/snort";
my $logfile = "alert";
my $msgfile = "/var/tmp/snort-alerts.$$";

Now setup some more variables and get everything set for the loop:

open(FILE, "$logdir/$logfile");
my @alerts = <FILE>;
close FILE;

if (scalar(@alerts) == 0) { exit (0); } # exit if there are 0 entries

my $do_msg = 0; # if we have not hit another record keep appending lines
my $pri2 = 0;   # A count of pri 2 alerts
my $pri1 = 0;   # A count of pri 1 alerts

Now the script is ready to enter the core algorithm, looking for trouble. This is accomplished using a foreach loop over each line of the alerts array, then pattern matching each line. If a match is found set the do_msg flag to 1. The script will append lines to the message file until it sees the next message. Once the script sees a new message, it resets do_msg to 0. Rinse and repeat as needed:

foreach (@alerts) {
    # if we hit a new record reset the message logger
    if (/\[\*\*/) {
        $do_msg = 0;
    }

    # if we have still not hit a new record keep appending lines to msg file
    if ($do_msg eq 1) {
        appendfile($msgfile, $_);
    }

    # if we hit a Pri2 or 1 increment counter, append the line to msg file
        # and set the flag to keep appending lines until we hit the next 
    # new alert record
    if (/Priority: 2/) {
        appendfile($msgfile, $_);
        $pri2++;
        $do_msg = 1;
    }

    if (/Priority: 1/) {
        appendfile($msgfile, $_);
        $pri1++;
        $do_msg = 1;
    }
}

Now that the decision and data collecting portion is done it is time to decide what to do (if anything) with the results. The pri1 and pri2 variables are added and checked, if the result is anything greater than zero the script:

  • creates a data string
  • stops snortd
  • changes directory to the snort logs
  • back up the alert log
  • Start snort
  • Append to the message file the total pri1 and pri2 alerts
  • Mail the message file

The last step deletes the message file. Note that the reason a system command is used to mail the message is to not rely upon Perl modules. If one were inclined, they could use Perl modules for the mail operation and init script:

# if we have either pri1 or 2 alerts, finish the message file and mail it out
if ($pri1 + $pri2) {
    my $date = `date +%F-%H%M-%S`;
    system("/etc/init.d/snortd stop");
    chdir ($logdir);
    rename($logfile, $logfile.$date);
    system("/etc/init.d/snortd start");
    appendfile($msgfile, "Pri 1 alerts: $pri1\n");
    appendfile($msgfile, "Pri 2 alerts: $pri2\n");
    system("/bin/cat $msgfile | /bin/mail -s Snort-Alerts me\@mail.domain.org");
}

unlink($msgfile); # delete the temp message file

Example Email Message

Following is what an alert that is emailed would look like:

From: snort@somesensor.net
To: cooladmin@roxor.net
Cc: 
Subj: Snort-Alerts

[**] [1:2049:6] SQL ping attempt [**]
[Classification: Misc activity] [Priority: 2]
08/03-12:38:47.049614 192.168.48.68:1575 -> 255.255.255.255:1434
UDP TTL:128 TOS:0x0 ID:27143 IpLen:20 DgmLen:29
Len: 1
[Xref => http://cgi.nessus.org/plugins/dump.php3?id=10674]