#!/usr/bin/perl ### # Parse text-based log files of Snort alerts, and save them # to a file in Berkley DB format. ### # Load necessary libraries. require "init.pl"; ### # Initialize output alert database. if (-e $ALERTDB) { die "Output alert database $ALERTDB already exists. Exiting.\n"; } if (! tie(%ALERTDB, "DB_File", $ALERTDB)) { die "Could not initialize output alert database $ALERTDB:\n$!\n"; } ### # Process every line on STDIN or in files passed on command line. $counter = 0; $dbdelim = "*"; while (<>) { # Display a message every time a new file is being processed. if ($VERBOSE) { if ($ARGV eq "-") { $infile = "STDIN"; } else { $infile = $ARGV; } if (! $PROCESSED_FILES{$infile}) { warn "Processing $infile...\n"; $PROCESSED_FILES{$infile} = 1; } } # Skip empty lines, lines with nothing but stars, and title lines. # Also skip lines that don't start with a date, but warn about that. next if ((/^\s*\**\s*$/) || (/^\s*Snort Alert Report/)); if (! /^\d\d\/\d\d\-/) { warn "No leading date: $_"; next; } # Separate the line into meaningful fields. chop; ($timestamp, $name, $details) = split(/\s*\[\*\*\]\s*/); if ($timestamp =~ /^\s*$/) { warn "Timestamp empty ([**] $name [**] $details)\n"; next; } if ($name =~ /^\s*$/) { warn "Alert name empty ($timestamp .. $details)\n"; next; } if ($details =~ /^\s*$/) { # In some alerts these are empty. ($src, $dst, $srchost, $srcport, $dsthost, $dstport) = (); } else { ($src, $dst) = split(/ \-> /, $details); ($srchost, $srcport) = split(/:/, $src); ($dsthost, $dstport) = split(/:/, $dst); if (($srchost =~ /^\s*$/) || ($dsthost =~ /^\s*$/)) { # Hosts cannot be empty, but ports are in some alerts. warn "Details corrupted ($timestamp)\n"; next; } } # Write alert to the database. $ALERTDB{$counter++} = $timestamp . $dbdelim . $name . $dbdelim . $srchost . $dbdelim . $srcport . $dbdelim . $dsthost . $dbdelim . $dstport; } ### # Clean up and exit. untie(%ALERTDB);