#!/usr/bin/perl
-# V 1.7
+# based on V 1.7 guardian enhanced for IPFire and snort 2.8
# Read the readme file for changes
#
# Enhanced for IPFire by IPFire Team
&Getopts ('hc:d');
if (defined($opt_h)) {
- print "Guardian v1.7 \n";
- print "guardian.pl [-hd] <-c config>\n";
- print " -h shows help\n";
- print " -d run in debug mode (doesn't fork, output goes to STDOUT)\n";
- print " -c specifiy a configuration file other than the default (/etc/guardian.conf)\n";
- exit;
+ print "Guardian v1.7 \n";
+ print "guardian.pl [-hd] <-c config>\n";
+ print " -h shows help\n";
+ print " -d run in debug mode (doesn't fork, output goes to STDOUT)\n";
+ print " -c specifiy a configuration file other than the default (/etc/guardian.conf)\n";
+ exit;
}
&load_conf;
&sig_handler_setup;
print "My ip address and interface are: $hostipaddr $interface\n";
if ($hostipaddr !~ /\d+\.\d+\.\d+\.\d+/) {
- print "This ip address is bad : $hostipaddr\n";
- die "I need a good host ipaddress\n";
+ print "This ip address is bad : $hostipaddr\n";
+ die "I need a good host ipaddress\n";
}
$networkaddr = $hostipaddr;
# This is the target hash. If a packet was destened to any of these, then the
# sender of that packet will get denied, unless it is on the ignore list..
-%targethash = ( "$networkaddr" => 1,
- "$broadcastaddr" => 1,
- "0" => 1, # This is what gets sent to &checkem if no
- # destination was found.
- "$hostipaddr" => 1);
+%targethash = ( "$networkaddr" => 1,
+ "$broadcastaddr" => 1,
+ "0" => 1, # This is what gets sent to &checkem if no
+ # destination was found.
+ "$hostipaddr" => 1);
%sshhash = ();
if ( -e $targetfile ) {
- &load_targetfile;
+ &load_targetfile;
}
if (!defined($opt_d)) {
- print "Becoming a daemon..\n";
- &daemonize;
+ print "Becoming a daemon..\n";
+ &daemonize;
} else { print "Running in debug mode..\n"; }
open (ALERT, $alert_file) or die "can't open alert file: $alert_file: $!\n";
-seek (ALERT, 0, 2); # set the position to EOF.
+seek (ALERT, 0, 2); # set the position to EOF.
# this is the same as a tail -f :)
$counter=0;
open (ALERT2, "/var/log/messages" ) or die "can't open /var/log/messages: $!\n";
-seek (ALERT2, 0, 2); # set the position to EOF.
+seek (ALERT2, 0, 2); # set the position to EOF.
# this is the same as a tail -f :)
-for (;;) {
- sleep 1;
- if (seek(ALERT,0,1)){
- while (<ALERT>) {
- chop;
- if (defined($opt_d)) {print "$_\n";}
- if (/\[\*\*\]\s+(.*)\s+\[\*\*\]/){
- $type=$1;
- }
- if (/(\d+\.\d+\.\d+\.\d+):\d+ -\> (\d+\.\d+\.\d+\.\d+):\d+/) {
- &checkem ($1, $2, $type);
- }
- if ($_=~/Portscan/) {
- my @array=split(/ /,$_);&checkem ($array[5], $hostipaddr, "Portscan was detected.");}
- }
- }
-
- sleep 1;
- if (seek(ALERT2,0,1)){
- while (<ALERT2>) {
- chop;
- if ($_=~/.*sshd.*Failed password for root from.*/) {
- my @array=split(/ /,$_);&checkssh ($array[10], "possible SSH-Bruteforce Attack");}
- }
- }
- # Run this stuff every 30 seconds..
- if ($counter == 30) {
- &remove_blocks; # This might get moved elsewhere, depending on how much load
- # it puts on the system..
- &check_log_name;
- $counter=0;
- } else { $counter=$counter+1; }
+for (;;) {
+ sleep 1;
+ if (seek(ALERT,0,1)){
+ while (<ALERT>) {
+ chop;
+ if (defined($opt_d)) {
+ print "$_\n";
+ }
+ if (/\[\*\*\]\s+(.*)\s+\[\*\*\]/){
+ $type=$1;
+ }
+ if (/(\d+\.\d+\.\d+\.\d+):\d+ -\> (\d+\.\d+\.\d+\.\d+):\d+/) {
+ &checkem ($1, $2, $type);
+ }
+ if (/(\d+\.\d+\.\d+\.\d+)+ -\> (\d+\.\d+\.\d+\.\d+)+/) {
+ &checkem ($1, $2, $type);
+ }
+ }
+ }
+
+ sleep 1;
+ if (seek(ALERT2,0,1)){
+ while (<ALERT2>) {
+ chop;
+ if ($_=~/.*sshd.*Failed password for root from.*/) {
+ my @array=split(/ /,$_);&checkssh ($array[10], "possible SSH-Bruteforce Attack");}
+ }
+ }
+
+# Run this stuff every 30 seconds..
+ if ($counter == 30) {
+ &remove_blocks; # This might get moved elsewhere, depending on how much load
+ # it puts on the system..
+ &check_log_name;
+ $counter=0;
+ } else {
+ $counter=$counter+1;
+ }
}
sub check_log_name {
- my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
- $atime,$mtime,$ctime,$blksize,$blocks) = stat($alert_file);
- if ($size < $previous_size) { # The filesize is smaller than last
- close (ALERT); # we checked, so we need to reopen it
- open (ALERT, "$alert_file"); # This should still work in our main while
- $previous_size=$size; # loop (I hope)
- write_log ("Log filename changed. Reopening $alert_file\n");
- } else {
- $previous_size=$size;
- }
+ my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks) = stat($alert_file);
+ if ($size < $previous_size) { # The filesize is smaller than last
+ close (ALERT); # we checked, so we need to reopen it
+ open (ALERT, "$alert_file"); # This should still work in our main while
+ $previous_size=$size; # loop (I hope)
+ write_log ("Log filename changed. Reopening $alert_file\n");
+ } else {
+ $previous_size=$size;
+ }
}
-
+
sub checkem {
- my ($source, $dest,$type) = @_;
- my $flag=0;
- return 1 if ($source eq $hostipaddr); # this should prevent is from nuking
- # ourselves
- return 1 if ($source eq $gatewayaddr); # or our gateway
- if ($ignore{$source} == 1) { # check our ignore list..
- &write_log("$source\t$type\n");
- &write_log("Ignoring attack because $source is in my ignore list\n");
- return 1;
- }
- # if the offending packet was sent to us, the network, or the broadcast, then
- if ($targethash{$dest} == 1) {
- &ipchain ($source, $dest, $type);
- }
- # you will see this if the destination was not in the $targethash, and the
- # packet was not ignored before the target check..
- else {
- &write_log ("Odd.. source = $source, dest = $dest - No action done.\n");
- if (defined ($opt_d)) {
- foreach $key (keys %targethash) {
- &write_log ("targethash{$key} = $targethash{$key}\n");
- }
- }
- }
+ my ($source, $dest,$type) = @_;
+ my $flag=0;
+
+ return 1 if ($source eq $hostipaddr);
+ # this should prevent is from nuking ourselves
+
+ return 1 if ($source eq $gatewayaddr); # or our gateway
+ if ($ignore{$source} == 1) { # check our ignore list..
+ &write_log("$source\t$type\n");
+ &write_log("Ignoring attack because $source is in my ignore list\n");
+ return 1;
+ }
+
+# if the offending packet was sent to us, the network, or the broadcast, then
+ if ($targethash{$dest} == 1) {
+ &ipchain ($source, $dest, $type);
+ }
+# you will see this if the destination was not in the $targethash, and the
+# packet was not ignored before the target check..
+ else {
+ &write_log ("Odd.. source = $source, dest = $dest - No action done.\n");
+ if (defined ($opt_d)) {
+ foreach $key (keys %targethash) {
+ &write_log ("targethash{$key} = $targethash{$key}\n");
+ }
+ }
+ }
}
sub checkssh {
- my ($source,$type) = @_;
- my $flag=0;
- return 1 if ($source eq $hostipaddr); # this should prevent is from nuking
- # ourselves
- return 1 if ($source eq $gatewayaddr); # or our gateway
- if ($sshhash{$dest} eq "" ){ $sshhash{$dest} = 1; }
- if ($sshhash{$dest} >= 3 ) {
- &write_log ("source = $source, count $sshhash{$dest} - blocking for ssh attack.\n");
- &ipchain ($source, "", $type);
- }
- # you will see this if the destination was not in the $sshhash, and the
- # packet was not ignored before the target check..
- else {
- &write_log ("Odd.. source = $source, ssh count only $sshhash{$dest} - No action done.\n");
- if (defined ($opt_d)) {
- foreach $key (keys %sshhash) {
- &write_log ("sshhash{$key} = %sshhash{$key}\n");
- }
- }
- $sshhash{$key} = $sshhash{$key}+1;
- }
+ my ($source,$type) = @_;
+ my $flag=0;
+
+ return 1 if ($source eq $hostipaddr);
+ # this should prevent is from nuking ourselves
+
+ return 1 if ($source eq $gatewayaddr); # or our gateway
+
+ if ($sshhash{$dest} eq "" ){
+ $sshhash{$dest} = 1;
+ }
+ if ($sshhash{$dest} >= 3 ) {
+ &write_log ("source = $source, count $sshhash{$dest} - blocking for ssh attack.\n");
+ &ipchain ($source, "", $type);
+ }
+# you will see this if the destination was not in the $sshhash, and the
+# packet was not ignored before the target check..
+ else {
+ &write_log ("Odd.. source = $source, ssh count only $sshhash{$dest} - No action done.\n");
+ if (defined ($opt_d)) {
+ foreach $key (keys %sshhash) {
+ &write_log ("sshhash{$key} = %sshhash{$key}\n");
+ }
+ }
+ $sshhash{$key} = $sshhash{$key}+1;
+ }
}
-sub ipchain {
- my ($source, $dest, $type) = @_;
- &write_log ("$source\t$type\n");
- if ($hash{$source} eq "") {
- &write_log ("Running '$blockpath $source'\n");
- system ("$blockpath $source");
- $hash{$source} = time() + $TimeLimit;
- } else {
- # We have already blocked this one, but snort detected another attack. So
- # we should update the time blocked..
- $hash{$source} = time() + $TimeLimit;
- }
+sub ipchain {
+ my ($source, $dest, $type) = @_;
+ &write_log ("$source\t$type\n");
+ if ($hash{$source} eq "") {
+ &write_log ("Running '$blockpath $source'\n");
+ system ("$blockpath $source");
+ $hash{$source} = time() + $TimeLimit;
+ } else {
+# We have already blocked this one, but snort detected another attack. So
+# we should update the time blocked..
+ $hash{$source} = time() + $TimeLimit;
+ }
}
-
+
sub build_ignore_hash {
# This would cause is to ignore all broadcasts if it
# got set.. However if unset, then the attacker could spoof the packet to make
# it look like it came from the network, and a reply to the spoofed packet
-# could be seen if the attacker were on the local network.
-# $ignore{$networkaddr}=1;
+# could be seen if the attacker were on the local network.
+# $ignore{$networkaddr}=1;
# same thing as above, just with the broadcast instead of the network.
# $ignore{$broadcastaddr}=1;
- my $count =0;
- $ignore{$gatewayaddr}=1;
- $ignore{$hostipaddr}=1;
- if ($ignorefile ne "") {
- open (IGNORE, $ignorefile);
- while (<IGNORE>) {
- chop;
- next if (/\#/); #skip comments
- next if (/^\s*$/); # and blank lines
- $ignore{$_}=1;
- $count++;
- }
- close (IGNORE);
- print "Loaded $count addresses from $ignorefile\n";
- } else {
- print "No ignore file was loaded!\n";
- }
+ my $count =0;
+ $ignore{$gatewayaddr}=1;
+ $ignore{$hostipaddr}=1;
+ if ($ignorefile ne "") {
+ open (IGNORE, $ignorefile);
+ while (<IGNORE>) {
+ chop;
+ next if (/\#/); #skip comments
+ next if (/^\s*$/); # and blank lines
+ $ignore{$_}=1;
+ $count++;
+ }
+ close (IGNORE);
+ print "Loaded $count addresses from $ignorefile\n";
+ } else {
+ print "No ignore file was loaded!\n";
+ }
}
sub load_conf {
- if ($opt_c eq "") {
- $opt_c = "/etc/guardian.conf";
- }
- if (! -e $opt_c) {
- die "Need a configuration file.. please use to the -c option to name a
-configuration file\n";
- }
- open (CONF, $opt_c) or die "Cannot read the config file $opt_c, $!\n";
- while (<CONF>) {
- chop;
- next if (/^\s*$/); #skip blank lines
- next if (/^#/); # skip comment lines
- if (/LogFile\s+(.*)/) {
- $logfile = $1;
- }
- if (/Interface\s+(.*)/) {
- $interface = $1;
- }
- if (/AlertFile\s+(.*)/) {
- $alert_file = $1;
- }
- if (/IgnoreFile\s+(.*)/) {
- $ignorefile = $1;
- }
- if (/TargetFile\s+(.*)/) {
- $targetfile = $1;
- }
- if (/TimeLimit\s+(.*)/) {
- $TimeLimit = $1;
- }
- if (/HostIpAddr\s+(.*)/) {
- $hostipaddr = $1;
- }
- if (/HostGatewayByte\s+(.*)/) {
- $hostgatewaybyte = $1;
- }
-# if (/ipchainsPath\s+(.*)/) {
-# $ipchains_path = $1;
-# }
- }
- if ($interface eq "") {
- die "Fatal! Interface is undefined.. Please define it in $opt_o with keyword Interface\n";
- }
- if ($alert_file eq "") {
- print "Warning! AlertFile is undefined.. Assuming /var/log/snort.alert\n";
- $alert_file="/var/log/snort.alert";
- }
- if ($hostipaddr eq "") {
- print "Warning! HostIpAddr is undefined! Attempting to guess..\n";
- $hostipaddr = &get_ip($interface);
- print "Got it.. your HostIpAddr is $hostipaddr\n";
- }
- if ($ignorefile eq "") {
- print "Warning! IgnoreFile is undefined.. going with default ignore list (hostname and gateway)!\n";
- }
- if ($hostgatewaybyte eq "") {
- print "Warning! HostGatewayByte is undefined.. gateway will not be in ignore list!\n";
- }
- if ($logfile eq "") {
- print "Warning! LogFile is undefined.. Assuming debug mode, output to STDOUT\n";
- $opt_d = 1;
- }
- if (! -w $logfile) {
- print "Warning! Logfile is not writeable! Engaging debug mode, output to STDOUT\n";
- $opt_d = 1;
- }
- foreach $mypath (split (/:/, $ENV{PATH})) {
- if (-x "$mypath/guardian_block.sh") {
- $blockpath = "$mypath/guardian_block.sh";
- }
- if (-x "$mypath/guardian_unblock.sh") {
- $unblockpath = "$mypath/guardian_unblock.sh";
- }
- }
- if ($blockpath eq "") {
- print "Error! Could not find guardian_block.sh. Please consult the README. \n";
- exit;
- }
- if ($unblockpath eq "") {
- print "Warning! Could not find guardian_unblock.sh. Guardian will not be\n";
- print "able to remove blocked ip addresses. Please consult the README file\n";
- }
- if ($TimeLimit eq "") {
- print "Warning! Time limit not defined. Defaulting to absurdly long time limit\n";
- $TimeLimit = 999999999;
- }
+ if ($opt_c eq "") {
+ $opt_c = "/etc/guardian.conf";
+ }
+
+ if (! -e $opt_c) {
+ die "Need a configuration file.. please use to the -c option to name a configuration file\n";
+ }
+
+ open (CONF, $opt_c) or die "Cannot read the config file $opt_c, $!\n";
+ while (<CONF>) {
+ chop;
+ next if (/^\s*$/); #skip blank lines
+ next if (/^#/); # skip comment lines
+ if (/LogFile\s+(.*)/) {
+ $logfile = $1;
+ }
+ if (/Interface\s+(.*)/) {
+ $interface = $1;
+ }
+ if (/AlertFile\s+(.*)/) {
+ $alert_file = $1;
+ }
+ if (/IgnoreFile\s+(.*)/) {
+ $ignorefile = $1;
+ }
+ if (/TargetFile\s+(.*)/) {
+ $targetfile = $1;
+ }
+ if (/TimeLimit\s+(.*)/) {
+ $TimeLimit = $1;
+ }
+ if (/HostIpAddr\s+(.*)/) {
+ $hostipaddr = $1;
+ }
+ if (/HostGatewayByte\s+(.*)/) {
+ $hostgatewaybyte = $1;
+ }
+ }
+
+ if ($interface eq "") {
+ die "Fatal! Interface is undefined.. Please define it in $opt_o with keyword Interface\n";
+ }
+ if ($alert_file eq "") {
+ print "Warning! AlertFile is undefined.. Assuming /var/log/snort.alert\n";
+ $alert_file="/var/log/snort.alert";
+ }
+ if ($hostipaddr eq "") {
+ print "Warning! HostIpAddr is undefined! Attempting to guess..\n";
+ $hostipaddr = &get_ip($interface);
+ print "Got it.. your HostIpAddr is $hostipaddr\n";
+ }
+ if ($ignorefile eq "") {
+ print "Warning! IgnoreFile is undefined.. going with default ignore list (hostname and gateway)!\n";
+ }
+ if ($hostgatewaybyte eq "") {
+ print "Warning! HostGatewayByte is undefined.. gateway will not be in ignore list!\n";
+ }
+ if ($logfile eq "") {
+ print "Warning! LogFile is undefined.. Assuming debug mode, output to STDOUT\n";
+ $opt_d = 1;
+ }
+ if (! -w $logfile) {
+ print "Warning! Logfile is not writeable! Engaging debug mode, output to STDOUT\n";
+ $opt_d = 1;
+ }
+
+ foreach $mypath (split (/:/, $ENV{PATH})) {
+ if (-x "$mypath/guardian_block.sh") {
+ $blockpath = "$mypath/guardian_block.sh";
+ }
+ if (-x "$mypath/guardian_unblock.sh") {
+ $unblockpath = "$mypath/guardian_unblock.sh";
+ }
+ }
+
+ if ($blockpath eq "") {
+ print "Error! Could not find guardian_block.sh. Please consult the README. \n";
+ exit;
+ }
+ if ($unblockpath eq "") {
+ print "Warning! Could not find guardian_unblock.sh. Guardian will not be\n";
+ print "able to remove blocked ip addresses. Please consult the README file\n";
+ }
+ if ($TimeLimit eq "") {
+ print "Warning! Time limit not defined. Defaulting to absurdly long time limit\n";
+ $TimeLimit = 999999999;
+ }
}
sub write_log {
- my $message = $_[0];
- my $date = localtime();
- if (defined($opt_d)) { # we are in debug mode, and not daemonized
- print STDOUT $message;
- } else {
- open (LOG, ">>$logfile");
- print LOG $date.": ".$message;
- close (LOG);
- }
+ my $message = $_[0];
+ my $date = localtime();
+ if (defined($opt_d)) { # we are in debug mode, and not daemonized
+ print STDOUT $message;
+ } else {
+ open (LOG, ">>$logfile");
+ print LOG $date.": ".$message;
+ close (LOG);
+ }
}
sub daemonize {
- my ($home);
- if (fork()) {
- # parent
- exit(0);
- } else {
- # child
- &write_log ("Guardian process id $$\n");
- $home = (getpwuid($>))[7] || die "No home directory!\n";
- chdir($home); # go to my homedir
- setpgrp(0,0); # become process leader
- close(STDOUT);
- close(STDIN);
- close(STDERR);
- print "Testing...\n";
- }
-}
+ my ($home);
+ if (fork()) {
+# parent
+ exit(0);
+ } else {
+# child
+ &write_log ("Guardian process id $$\n");
+ $home = (getpwuid($>))[7] || die "No home directory!\n";
+ chdir($home); # go to my homedir
+ setpgrp(0,0); # become process leader
+ close(STDOUT);
+ close(STDIN);
+ close(STDERR);
+ print "Testing...\n";
+ }
+}
sub get_ip {
- my ($interface) = $_[0];
- my $ip;
- open (IFCONFIG, "/bin/netstat -iee |grep $interface -A7 |");
- while (<IFCONFIG>) {
- if ($OS eq "FreeBSD") {
- if (/inet (\d+\.\d+\.\d+\.\d+)/) {
- $ip = $1;
- }
- }
- if ($OS eq "Linux") {
- if (/inet addr:(\d+\.\d+\.\d+\.\d+)/) {
- $ip = $1;
- }
- }
- }
- close (IFCONFIG);
- if ($ip eq "") { die "Couldn't figure out the ip address\n"; }
- $ip;
-}
+ my ($interface) = $_[0];
+ my $ip;
+ open (IFCONFIG, "/bin/netstat -iee |grep $interface -A7 |");
+ while (<IFCONFIG>) {
+ if ($OS eq "FreeBSD") {
+ if (/inet (\d+\.\d+\.\d+\.\d+)/) {
+ $ip = $1;
+ }
+ }
+ if ($OS eq "Linux") {
+ if (/inet addr:(\d+\.\d+\.\d+\.\d+)/) {
+ $ip = $1;
+ }
+ }
+ }
+ close (IFCONFIG);
+
+ if ($ip eq "") { die "Couldn't figure out the ip address\n"; }
+ $ip;
+ }
sub sig_handler_setup {
- $SIG{TERM} = \&clean_up_and_exit; # kill
- $SIG{QUIT} = \&clean_up_and_exit; # kill -3
+ $SIG{TERM} = \&clean_up_and_exit; # kill
+ $SIG{QUIT} = \&clean_up_and_exit; # kill -3
# $SIG{HUP} = \&flush_and_reload; # kill -1
}
sub remove_blocks {
- my $source;
- my $time = time();
- foreach $source (keys %hash) {
- if ($hash{$source} < $time) {
- &call_unblock ($source, "expiring block of $source\n");
- delete ($hash{$source});
- }
- }
+ my $source;
+ my $time = time();
+ foreach $source (keys %hash) {
+ if ($hash{$source} < $time) {
+ &call_unblock ($source, "expiring block of $source\n");
+ delete ($hash{$source});
+ }
+ }
}
sub call_unblock {
- my ($source, $message) = @_;
- &write_log ("$message");
- system ("$unblockpath $source");
+ my ($source, $message) = @_;
+ &write_log ("$message");
+ system ("$unblockpath $source");
}
sub clean_up_and_exit {
- my $source;
- &write_log ("received kill sig.. shutting down\n");
- foreach $source (keys %hash) {
- &call_unblock ($source, "removing $source for shutdown\n");
- }
- exit;
+ my $source;
+ &write_log ("received kill sig.. shutting down\n");
+ foreach $source (keys %hash) {
+ &call_unblock ($source, "removing $source for shutdown\n");
+ }
+ exit;
}
sub load_targetfile {
- my $count = 0;
- open (TARG, "$targetfile") or die "Cannot open $targetfile\n";
- while (<TARG>) {
- chop;
- next if (/\#/); #skip comments
- next if (/^\s*$/); # and blank lines
- $targethash{$_}=1;
- $count++;
- }
- close (TARG);
- print "Loaded $count addresses from $targetfile\n";
+ my $count = 0;
+ open (TARG, "$targetfile") or die "Cannot open $targetfile\n";
+ while (<TARG>) {
+ chop;
+ next if (/\#/); #skip comments
+ next if (/^\s*$/); # and blank lines
+ $targethash{$_}=1;
+ $count++;
+ }
+ close (TARG);
+ print "Loaded $count addresses from $targetfile\n";
}