Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 149 lines (136 sloc) 6.109 kb
#!/usr/bin/perl -w
#
###############################################################################
#
# File: snort_compat.pl
#
# Purpose: To assist in the construction of a set of Snort rules that can be
# made compatible with psad.
#
# Methodology: Psad exclusively uses iptables log messages as its source
# of intrusion detection data. This means that psad cannot accurately
# detect most Snort rules because payload data is not available (the
# iptables string match extension can provide string matching capabilities
# against application layer data; see "fwsnort" at
# http://www.cipherdyne.org/fwsnort). However, there are several backdoor
# programs, DDoS tools, and other suspect traffic that can be inferred from
# looking at transport layer data (for tcp and udp) as long as it does not
# involve a commonly used IANA specified port number. For example, consider
# the following three Snort rules, which are designed to detect various
# communication aspects of the Trin00 DDoS tool:
#
# alert tcp $EXTERNAL_NET any -> $HOME_NET 27665 (msg:"DDOS Trin00 Attacker to Master default startup password"; flow:established,to_server; content:"betaalmostdone"; reference:arachnids,197; classtype:attempted-dos; sid:233; rev:3;)
# alert tcp $EXTERNAL_NET any -> $HOME_NET 27665 (msg:"DDOS Trin00 Attacker to Master default password"; flow:established,to_server; content:"gOrave"; classtype:attempted-dos; sid:234; rev:2;)
# alert tcp $EXTERNAL_NET any -> $HOME_NET 27665 (msg:"DDOS Trin00 Attacker to Master default mdie password"; flow:established,to_server; content:"killme"; classtype:bad-unknown; sid:235; rev:2;)
#
# Each of the above rules uses the Snort "content" keyword to detect a
# specific aspect of the Trin00 communication in order to be able to
# distinguish the "default startup password" from the "default password"
# for example. Each of the rules only applies to traffic over an
# established TCP session (see the "established" argument give to the
# "flow" keyword). It is impossible to extract the same level of
# granularity from iptables logs alone. However, if iptables logs a SYN
# packet directed to TCP port 27665, it is a good bet that a Trin00 DDoS
# client is attempting to contact a Trin00 master client. Hence psad will
# generate the alert "DDOS Trin00 Attacker to Master" upon monitoring such
# a packet in the iptables log. Even if the Snort rules above are
# improved by the Snort community to use the more advanced features of the
# Snort rules language, the basic fact that SYN packets to TCP/27665 may
# be associated with the Trin00 DDoS remains. This is the general
# methodology used to write psad signatures that are derived from Snort
# rules. Of course, this type of analysis is not possible for heavily
# utilized services that run over IANA specified ports (such as web, dns,
# and stmp servers for example). Detecting attacks over such services
# requires application data inspection as provided by the Snort rules
# language. The snort_compat.pl script generates a listing of Snort rules
# that may be compatible with psad. The resulting rules are then reviewed
# and altered for inclusion within the psad signatures file.
#
###############################################################################
#
use Data::Dumper;
use strict;
#=========================== config =============================
my $services_file = '/etc/services';
my $rules_dir = 'snort_rules';
### ignore all snort rules in these files
my @ignore_files = (
'deleted.rules',
'exploit.rules', ### really need content inspection for these
'web-misc.rules',
'chat.rules'
);
#========================= end config ===========================
my %services;
my @files;
open S, "< $services_file" or die " ** Could not open $services_file";
my @lines = <S>;
close S;
for my $line (@lines) {
chomp $line;
### sunrpc 111/tcp
if ($line =~ m|^\s*(\S+)\s+(\d+)/(\S+)|) {
my $service = $1;
my $port = $2;
my $proto = $3;
$services{$proto}{$port} = $service;
}
}
$services{'tcp'}{'80'} = '' unless defined $services{'tcp'};
$services{'udp'}{'53'} = '' unless defined $services{'udp'};
if ($ARGV[0]) {
push @files, $ARGV[0];
} else {
opendir D, $rules_dir or die " ** Could not open $rules_dir";
@files = readdir D;
closedir D;
}
FILE: for my $file (@files) {
next unless $file =~ /rules/;
for my $ignore_file (@ignore_files) {
next FILE if $file eq $ignore_file;
}
open R, "< $rules_dir/$file" or die;
my @rules = <R>;
close R;
print "### $file\n";
RULE: for my $rule (@rules) {
chomp $rule;
next RULE unless $rule =~ /^\s*alert/;
if ($rule =~ m|^alert\s+(\S+)\s+(\S+)\s+(\S+)
\s+(\S+)\s+(\S+)\s+(\S+)|x) {
my $proto = $1;
my $src_p = $3;
my $dst_p = $6;
next RULE if $src_p =~ /\$/; ### skip things like $HTTP_PORTS
next RULE if $dst_p =~ /\$/;
next RULE if ($rule =~ /content:/
and $src_p eq 'any' and $dst_p eq 'any');
if (not defined $services{$proto}) {
print $rule, "\n";
} else {
my @src_p_arr;
my @dst_p_arr;
if ($src_p =~ /:/) {
@src_p_arr = split /\s*:\s*/, $src_p;
} else {
push @src_p_arr, $src_p;
}
if ($dst_p =~ /:/) {
@dst_p_arr = split /\s*:\s*/, $dst_p;
} else {
push @dst_p_arr, $dst_p;
}
for my $src_p (@src_p_arr) {
next RULE if defined $services{$proto}{$src_p};
}
for my $dst_p (@dst_p_arr) {
next RULE if defined $services{$proto}{$dst_p};
}
print $rule, "\n";
}
}
}
print "\n";
}
exit 0;
Jump to Line
Something went wrong with that request. Please try again.