Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
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.