[Snort-users] Removing of duplicate rules

lmonin at ...252... lmonin at ...252...
Fri Aug 11 15:27:59 EDT 2000


I wrote a very helpy perl script,
its purpose is to remove duplicate rules in snort alert rules file

Usage:
Rename rules files to something-lib and then

cat *-lib | ./dupl.pl 2>log | sort > newrules 

Please test it, i'm waiting for any comment

Zas
-------------- next part --------------
#!/usr/bin/perl -w
#Usage: cat rules_file | ./dupl.pl 2>log | sort > newrules
#or cat rules_file | ./dupl.pl 2>log | sort > newrules
#Then edit newrules for snort config
use Digest::MD5 qw(md5_hex);
$DEFAULT_NET="HOME_NET";

sub traiter_ligne() {
    chomp;
	s/^\s*//;
    s/\s*$//;
	if ($_) {
		print STDERR "-"x132, "\n";
       	if (/alert\s+(\S+)\s+([^ \t]+)\s+(\S+)\s+([<-]>)\s+([^ \t]+)\s+(\S+)\s+\((.+)\)$/) {
			print STDERR "%% $_\n";
			my %rule;
			$rule{"_pro"}=uc($1);
			my $src=$2;
			$rule{"_sp"}=$3;
			$rule{"_dir"}=$4;
			my $dst=$5;
			$rule{"_dp"}=$6; 
			my $text=$7;
			$src=~s/\$[^\/]+$/\$$DEFAULT_NET/;
			$rule{"_src"}=$src;
			$dst=~s/\$[^\/]+$/\$$DEFAULT_NET/;
			$rule{"_dst"}=$dst;
			my  @param = ();
			push(@param, $+) while $text =~ m/(
								[^\"\:\;]+:\s*"
									(?:	\\[^"][^"]?
									| [^\\;"]?
									| \\[";]
									| \\
									)*
								[^\\]?")\s*;?
								|([^;\"]+)\s*;?
								/gx;
			for (@param) {
				if ($_) {
					chomp;
					s/^\s*(.*?)\s*$/$1/;
					print STDERR ">> $_\n";
					$text=$_;
		            my  @vars = ();
					if (/([^\"\:\;]+):\s*"(
								(?:	\\[^"][^"]?
									| [^\\;"]?
									| \\[";]
									| \\
								)*
								[^\\]?)"\s*;?

						/x) {

						$vars[0]=$1;
						$vars[1]=$2;
					} elsif (/([^:]+):(.+)/) {
						$vars[0]=$1;
						$vars[1]=$2;
					} else {
						$vars[0]=$text;
                		$vars[1]="";
					};
					if ($vars[0]) {
						$vars[0]=~ s/^\s*(.*?)\s*$/$1/;
						print STDERR " 0: $vars[0]\n";
					}
					if ($vars[1]) {
                		print STDERR " 1: $vars[1]\n";
					}
					if ($vars[0]) {
						my $ni=0;
						if (lc($vars[0]) eq "content") { 
							while ($rule{"content".$ni}) {
								$ni++;
							};
						}
						if (lc($vars[0]) eq "nocase" or lc($vars[0]) eq "offset" or lc($vars[0]) eq "depth")  {
				 			my $nbcase=-1;
							while ($rule{"content".$ni}) {
								$ni++;
								$nbcase++;
							};
							$ni=$nbcase;
						}
						print STDERR "ni $ni\n";
						if ($ni!= -1) {
							$vars[0].=$ni;
							if ($vars[1]) { $rule{lc($vars[0])}=$vars[1]; } else { $rule{lc($vars[0])}="1"; };
						}
					}
				}		
			}

			my @keys = sort keys %rule;
			my $s="";
			for (@keys) {
				if ($_ eq "flags0"  ) {
					my @tmp=split //,uc($rule{$_});
					my $t=0;
					for (@tmp) {
						if (/F/) { $t+=1; }
						elsif (/S/) { $t+=2; }
               			elsif (/R/) { $t+=4; }
                		elsif (/P/) { $t+=8; }
                		elsif (/A/) { $t+=16; }
                		elsif (/U/) { $t+=32; }
                		elsif (/2/) { $t+=64; }
                		elsif (/1/) { $t+=128; }
						else { $t+=32768; };
					}
					print STDERR "nn $t\n";	 
					$s.=" $_ = $t"; 
				}  else {
#dont check src and dst
					if ($_ ne "msg0" and $_ ne "_src" and $_ ne "_dst" ) { $s.=" $_ = $rule{$_}"; };
#					if ($_ ne "msg0") { $s="$s $_ = $rule{$_}"; }
				}
			};
			my $sum=md5_hex("$s");
			if ($frules{$sum}) { 
				my $a="";
				my $b="";
				print STDERR "!! Duplicate ***********\n";
				if (/msg:\s*"([^"]+)"/) { $a=$1;}
				if ($frules{$sum} =~ /msg:\s*"([^"]+)"/) { $b=$1;}
				if ( $a and $b ) { 
			 		if ($a ne $b) { 
						print STDERR '!! [',$a,"]\n!! [",$b,"]\n"; 
						if (($a =~/IDS\d+/ and $b!~/IDS\d+/) or (length($a)>length($b))) {
							$frules{$sum}=~s/\Q\"$b\"/\"$a\"/;
							print STDERR "!! Selecting [$a]\n";
						}
					}
				}
				print STDERR "!! ",$frules{$sum},"\n";
				$nbld++;
			} else {
				my $str=qq/alert /.uc($rule{"_pro"}).qq/ $rule{"_src"} $rule{"_sp"} $rule{"_dir"} $rule{"_dst"} $rule{"_dp"} (/;
				if ($rule{"msg0"}) { $str.=qq/msg:"$rule{"msg0"}";/; }
				if ($rule{"logto0"}) { $str.=qq/ logto:"$rule{"logto0"}";/; }

				while (($key, $value) = each %rule) {
					if ($key=~ /^ttl/) { $str.=qq/ ttl:"$value";/; }
					elsif ($key=~ /^id/) { $str.=qq/ id:"$value";/; }
					elsif ($key=~ /^dsize/) { $str.=qq/ dsize:$value;/; }
					elsif ($key=~ /^content(\d+)/) { 
						$str.=qq/ content:"$value";/; 
						if ($rule{"nocase$1"}) { $str.=qq/ nocase;/; }
						if ($rule{"offset$1"}) { $str.=qq/ offset:$rule{"offset$1"};/; }
						if ($rule{"depth$1"}) { $str.=qq/ depth:$rule{"depth$1"};/; }
					}
					elsif ($key=~ /^flags/) { $str.=qq/ flags:$value;/; }
					elsif ($key=~ /^seq/) { $str.=qq/ seq:$value;/; }
					elsif ($key=~ /^ack/) { $str.=qq/ ack:$value;/; }
					elsif ($key=~ /^itype/) { $str.=qq/ itype:$value;/; }
					elsif ($key=~ /^icode/) { $str.=qq/ icode:$value;/; }
					elsif ($key=~ /^session/) { $str.=qq/ session:$value;/; }
					elsif ($key=~ /^icmp_id/) { $str.=qq/ icmp_id:$value;/; }
					elsif ($key=~ /^icmp_seq/) { $str.=qq/ icmp_seq:$value;/; }
					elsif ($key=~ /^ipoption/) { $str.=qq/ ipoption:$value;/; }
					elsif ($key=~ /^rpc/) { $str.=qq/ rpc:$value;/; }
					elsif ($key=~ /^resp/) { $str.=qq/ resp:$value;/; }
				}
				$str.=')';
				$frules{$sum}=qq/$str/;
				print STDERR "%% $_\n";
				print STDERR "** $str\n";
				$nblv++;
			};
		} elsif (/^var/ or /^preprocessor/ or /^output/ or /^log/ or /^pass/ ) {
			$head{$nh++}=$_;
			$nbls++;
		} else { 
			print STDERR '@@ ',$_,"\n";
			$nbli++;
#			print $_,"\n";
		}
	}
	else { $nbli++; }
}
$nh=0;
$nbl=0;
$nblv=0;
$nbld=0;
$nbli=0;
$nbls=0;
while (<>) {
	traiter_ligne;
	$nbl++;
}
print  STDERR "+"x132, "\n\n";
while (($key, $value) = each %head) {
	print "# $value\n";
}
print "\n";
while (($key, $value) = each %frules) {
	print "$value\n";
}
$key="";
print STDERR "Processed lines:\r\t\t\t$nbl\nAlert rules:\r\t\t\t$nblv\nDuplicated rules:\r\t\t\t$nbld\nIgnored lines:\r\t\t\t$nbli\n";
print STDERR "Other lines:\r\t\t\t$nbls\n";
print STDERR "+"x132, "\n\n";



More information about the Snort-users mailing list