X-Git-Url: https://defaria.com/gitweb/?a=blobdiff_plain;f=bin%2Fbice.pl;h=cd25b1bf015b5ab474ae908c236291b33400aa37;hb=75f06ef1cd56d531eb9ae086618bce3ff6aaa510;hp=04ddb8fb7ad3ece39ae36a52189ca19bdc023a56;hpb=2c6c91a7c5b064230a5908456963a93b37a19c00;p=clearscm.git diff --git a/bin/bice.pl b/bin/bice.pl index 04ddb8f..cd25b1b 100755 --- a/bin/bice.pl +++ b/bin/bice.pl @@ -66,12 +66,23 @@ my $security_logfile = '/var/log/auth.log'; # Customize these variables my $domain = 'DeFaria.com'; my $contact = 'Andrew@DeFaria.com'; -my $location = 'Santa Clara, California, USA'; -my $UTC = 'UTC-8'; +my $location = 'Phoenix, Arizona, USA'; +my $UTC = 'UTC-7'; my $mailhost = $domain; # End customize these variables -my $verbose; +# Current IPset. This is the name of an IP match set (See +# https://kirkkosinski.com/2013/11/mass-blocking-evil-ip-addresses-iptables-ip-sets/) +# Each set can hold up to 65535 entries. We are currently on set 2. +# +# TODO: This code should handle the case where the set fills and we need to go +# to the next set. Something like "ipset list | wc - " and +# if it's > than say 60000, start a new set. +# +# Also, when a new set comes around we need to do: +# $ iptables -A FORWARD -m set --mach-set src -j DROP +my $currIPSet = 'BICE2'; + my $update = 1; my $email = 1; my $hostname = `hostname`; @@ -81,46 +92,19 @@ if ($hostname =~ /(\w*)\./) { $hostname = $1; } # if -sub AddToIPTables (@) { - my (@ips) = @_; - - # We shouldn't need to weed out duplicate but ya never know - my $ipfilename = '/etc/ipblock'; +sub AddToIPSet($) { + my ($ip) = @_; - my $result = open my $ipfile, '<', $ipfilename; + my ($status, @output) = Execute "/sbin/ipset add $currIPSet $ip 2>&1"; - my (%ips, @oldips); - - if ($result) { - @oldips = <$ipfile>; - - close $ipfile if $ipfile; + if ($status) { + return if $output[0] =~ /already added/; - chomp @oldips; + error "Unable to add $ip to ipset $currIPSet" . join ("\n", @output), 1; + } else { + return; } # if - - map { $ips{$_} = 1 } @oldips; - map { $ips{$_} = 1 } <@ips>; - - open $ipfile, '>', "$ipfilename" - or error "Unable to open $ipfilename - $!", 1; - - foreach (sort keys %ips) { - print $ipfile "$_\n"; - } # foreach - - close $ipfile; - - # Recreate the BICE chain - `/sbin/iptables -F BICE`; - `/sbin/iptables -X BICE`; - `/sbin/iptables -N BICE`; - - # Add all new @ips to iptables - `/sbin/iptables -A BICE -s $_ -p tcp -j DROP` foreach (sort keys %ips); - - return; -} # AddToIPTables +} # AddToIPSet # Use whois(1) to get the email addresses of the responsible parties for an IP # address. Note that a hash is used to eliminate duplicates. @@ -128,17 +112,18 @@ sub GetEmailAddresses ($) { my ($ip) = @_; # List of whois servers to try + # Apparently whois.opensrs.net no longer offers whois service? my @whois_list = ( '', 'whois.arin.net', 'whois.nsiregistry.net', - 'whois.opensrs.net', + #'whois.opensrs.net', 'whois.networksolutions.com', ); my %email_addresses; - foreach (@whois_list) { + for (@whois_list) { my @lines; if ($_ eq "") { @@ -147,108 +132,108 @@ sub GetEmailAddresses ($) { @lines = grep {/.*\@.*/ } `whois -h $_ $ip`; } # if - foreach (@lines) { + for (@lines) { my @fields = split /:/, $_; - + $_ = $fields [@fields - 1]; - + if (/(\S+\@\S[\.\S]+)/) { $email_addresses{$1} = ""; } # if - } # foreach + } # for # Break out of loop if we found email addresses last unless keys %email_addresses; - } # foreach + } # for return keys %email_addresses; } # GetEmailAddresses # Send email to the responsible parties. -sub SendEmail ($$$$$) { - my ($to, $subject, $message, $ip, $violations) = @_; +sub SendEmail ($$$$$$) { + my ($to, $subject, $message, $ip, $attempts, $violationNbr) = @_; if ($email) { - verbose "Reporting $ip ($violations violations) to $to"; + verbose "$violationNbr: Reporting $ip ($attempts violations) to $to"; } else { - verbose "Would have reported $ip ($violations violations) to $to"; + verbose "$violationNbr: Would have reported $ip ($attempts violations) to $to"; return; } # if mail ( - from => "BICE\@$domain", - to => $to, - cc => $contact, - subject => $subject, - mode => 'html', - data => $message, + from => "BICE\@$domain", + to => $to, + #cc => $contact, + subject => $subject, + mode => 'html', + data => $message, ); } # SendEmail sub processLogfile () { my %violations; - + # Note: Normally you must be root to open up $security_logfile open my $readlog, '<', $security_logfile or error "Unable to open $security_logfile - $!", 1; - + flock $readlog, LOCK_EX or error "Unable to flock $security_logfile", 1; - + my @lines; - + while (<$readlog>) { my $newline = $_; - + if (/^(\S+\s+\S+\s+\S+)\s+.*Invalid user (\w+) from (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) { my %violation = $violations{$3} ? %{$violations{$3}} : %_; - + push @{$violation{$2}}, $1; $violations{$3} = \%violation; - + $newline =~ s/Invalid user/INVALID USER/; } elsif (/^(\S+\s+\S+\s+\S+)\s+.*authentication failure.*ruser=(\S+).*rhost=(\S+)/) { my %violation = $violations{$3} ? %{$violations{$3}} : %_; - + push @{$violation{$2}}, $1; $violations{$3} = \%violation; - + $newline =~ s/authentication failure/AUTHENTICATION FAILURE/; } elsif (/^(\S+\s+\S+\s+\S+)\s+.*Failed password for (\w+) from (\d{1,3}\.\d{1,3}\.d{1,3}\.d{1,3})/) { my %violation = $violations{$3} ? %{$violations{$3}} : %_; - + push @{$violation{$2}}, $1; $violations{$3} = \%violation; - + $newline =~ s/Failed password/FAILED PASSWORD/; } # if push @lines, $newline; } # while - + return %violations unless $update; - + flock $readlog, LOCK_UN or error "Unable to unlock $security_logfile", 1; - + close $readlog; - + open my $writelog, '>', $security_logfile or error "Unable to open $security_logfile for writing - $!", 1; - + flock $writelog, LOCK_EX or error "Unable to flock $security_logfile", 1; - - print $writelog $_ foreach @lines; - + + print $writelog $_ for @lines; + flock $writelog, LOCK_UN or error "Unable to unlock $security_logfile", 1; close $writelog; - + return %violations; } # processLogfile @@ -257,7 +242,7 @@ sub ReportBreakins () { my %violations = processLogfile; my $nbrViolations = keys %violations; - + if ($nbrViolations == 0) { verbose 'No violations found'; } elsif ($nbrViolations == 1) { @@ -265,22 +250,23 @@ sub ReportBreakins () { } else { verbose "$nbrViolations sites attempting to violate our perimeter"; } # if - - foreach (sort keys %violations) { - my $ip = $_; + my $violations; + + for my $ip (sort keys %violations) { my $attempts; - - $attempts += @{$violations{$ip}{$_}} foreach (keys %{$violations{$ip}}); - - my @emails = GetEmailAddresses $ip; + + $violations++; + $attempts += @{$violations{$ip}{$_}} for (keys %{$violations{$ip}}); + + my @emails = GetEmailAddresses $ip; unless (@emails) { verbose 'Unable to find any responsible parties for detected breakin ' . "attempts from IP $ip ($attempts breakin attempts)"; next; } # unless - + my $to = join ',', @emails; my $subject = "Illegal attempts to break into $domain from your domain"; my $message = <<"END"; @@ -309,28 +295,27 @@ attempted and the time of the attempt:

    END # Report users - foreach my $user (sort keys %{$violations{$ip}}) { + for my $user (sort keys %{$violations{$ip}}) { if (@{$violations{$ip}{$user}} == 1) { - $message .= "
  1. The user $user attempted access on $violations{$ip}{$user}[0]
  2. "; + $message .= "
  3. The user $user attempted access on $violations{$ip}{$user}[0]
  4. "; } else { $message .= "
  5. The user $user attemped access on the following date/times:
  6. "; $message .= "
      "; - $message .= "
    1. $_
    2. " foreach (@{$violations{$ip}{$user}}); + $message .= "
    3. $_
    4. " for (@{$violations{$ip}{$user}}); $message .= "
    "; - } # if - } # foreach + } # if + } # for $message .= '

Your prompt attention to this matter is expected ' . 'and will be appreciated.

'; - SendEmail $to, $subject, $message, $ip, $attempts; - } # foreach - - AddToIPTables keys %violations; + SendEmail $to, $subject, $message, $ip, $attempts, $violations; + AddToIPSet $ip; + } # for + + return; } # ReportBreakins ## Main - -# Get options GetOptions ( 'verbose', sub { set_verbose }, 'debug', sub { set_debug }, @@ -340,8 +325,7 @@ GetOptions ( 'file=s', \$security_logfile, ) || Usage; -Usage 'Must specify filename' - unless $security_logfile; +Usage 'Must specify filename' unless $security_logfile; ReportBreakins; @@ -378,9 +362,9 @@ L =begin html
-<Display
-Mail
-a href="http://clearscm.com/php/cvs_man.php?file=lib/Utils.pm">Utils
+<Display
+Mail
+a href="http://clearscm.com/php/scm_man.php?file=lib/Utils.pm">Utils
=end html