05 September, 2008

Modified: Pulling IP addresses from Snort rules

This is a modification of another script I wrote to pull IP addresses from Snort rules. Since the last time I posted it, I added support for multiple rules files and also automatically insert the IP addresses into the database. After that, I can run a query to compare the IP addresses with sancp data to see what systems connected or attempted connections to the suspicious hosts.

I think this version will only work with MySQL 5.x, not 4.x, because of the section that adds the IP addresses to the database. In the older versions, the IP addresses had to be added manually. Note that the table used for the $tablename variable is not part of the Sguil database schema and must be created before running the script. Make sure not to use a table that is part of the Sguil DB schema because this script deletes all data from the table!

The script is fairly slow since it expands CIDR blocks to individual IP addresses and then puts them in the database one by one. If anyone has ideas for a more efficient method, I'd love to hear it, but since I'm using Sguil I need to be able to compare the suspicious IP addresses with individual IP addresses in the Sguil sancp table.

# Script to pull IP address from Snort rules file
# by nr
# 2007-08-30
# 2007-09-14 Added CIDR expansion
# 2007-12-19 Added support for multiple rule files
# 2008-05-22 Added MySQL support to insert and convert IPs

use strict;
use Mysql;

my $dir = "/nsm/rules"; # rules directory
my @rulefile = qw( emerging-compromised.rules emerging-rbn.rules );
my @rule; # unprocessed rules

foreach my $rulefile(@rulefile) {
# Open file to read
die "Can't open rulefile.\n" unless open RULEFILE, "<", "$dir/$rulefile";
chomp(@rule = (@rule,<RULEFILE>)); # put each rules into array
close RULEFILE; # close current rule file

# Open mysql connection
my $host = "localhost";
my $database = "sguildb";
my $tablename = "suspicious_hosts";
my $colname = "dst_ip";
my $user = "sguil";
my $pw = "PASSWORD";

# perl mysql connect()
my $sql_connect = Mysql->connect($host, $database, $user, $pw);

# clear out old IP addresses first
my $sql_delete = "DELETE FROM $tablename";
my $execute = $sql_connect->query($sql_delete) or die "$!";

# For each rule
foreach my $rule (@rule) {
# Match only rules with IP addresses so we don't get comments etc
# This string match does not check for validity of IP addresses
if ( $rule =~ /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/ ) {
$rule =~ s/.*\[//g; # Remove [ character and before
$rule =~ s/\].*//g; # Remove ] character and after
# Split the remaining data using the commas
# and put it into ip_address array
my @ip_address = split /\,/, $rule;

# For each IP address in array
foreach my $ip_address (@ip_address) {

# Match on slash
if ( $ip_address =~ /.*\/.*/ ) {

# Expand CIDR to all IP addresses in range modified from
# http://www.perlmonks.org/?displaytype=print;node_id=190497
use NetAddr::IP;
my $newip = new NetAddr::IP($ip_address);

# While less than broadcast address
while ( $newip < $newip->broadcast) {
# Strip trailing slash and netmask from IP
my $temp_ip = $newip;
$temp_ip =~ s/\/.*//g;
# sql statement to insert IP
my $sql_statement = "INSERT INTO $tablename SET $colname = INET_ATON('$temp_ip')";
# execute statement
my $execute = $sql_connect->query($sql_statement); # Run statement
$newip ++; # Increment to next IP
# For non-CIDR, simply print IP
else {
# sql statement to insert IP
my $sql_statement = "INSERT INTO $tablename SET $colname = INET_ATON('$ip_address')";
# execute statement. maybe make this a function or otherwise clean
# since it is repeated inside the if
my $execute = $sql_connect->query($sql_statement); # Run statement
To search for connections or attempted connections to the suspicious IP addresses, you could use a query like the following. Obviously, the query should change based on criteria like the the ports that interest you, time of activity, protocol, etc.
SELECT sancp.sid,INET_NTOA(sancp.src_ip),sancp.src_port,INET_NTOA(sancp.dst_ip),sancp.dst_port, \
sancp.start_time FROM sancp INNER JOIN suspicious_hosts ON (sancp.dst_ip = suspicious_hosts.dst_ip) WHERE \
sancp.start_time >= DATE_SUB(UTC_DATE(),INTERVAL 24 HOUR) AND sancp.dst_port = '80';

No comments:

Post a Comment