5 =head1 NAME $RCSfile: bice.pl,v $
7 Report breakin attempts to this domain
15 Andrew DeFaria <Andrew@ClearSCM.com>
23 Fri Mar 18 01:14:38 PST 2005
27 $Date: 2013/05/30 15:35:27 $
33 Usage: bice [-u|sage] [-v|erbose] [-d|ebug] [-nou|pdate] [-nom|ail]
34 [-f|ilename <filename> ]
37 -u|sage Print this usage
38 -v|erbose: Verbose mode (Default: -verbose)
39 -nou|pdate: Don't update security logfile file (Default: -update)
40 -nom|ail: Don't send emails (Default: -mail)
41 -f|ilename: Open alternate messages file (Default: /var/log/auth.log)
45 This script will look at the security logfile for attempted breakins and then
46 use whois to report them to the upstream provider.
56 use lib "$FindBin::Bin/../lib";
62 use Fcntl ':flock'; # import LOCK_* constants
64 my $security_logfile = '/var/log/auth.log';
66 # Customize these variables
67 my $domain = 'DeFaria.com';
68 my $contact = 'Andrew@DeFaria.com';
69 my $location = 'Phoenix, Arizona, USA';
71 my $mailhost = $domain;
72 # End customize these variables
77 my $hostname = `hostname`;
80 if ($hostname =~ /(\w*)\./) {
84 sub AddToIPTables (@) {
87 # We shouldn't need to weed out duplicate but ya never know
88 my $ipfilename = '/etc/ipblock';
90 my $result = open my $ipfile, '<', $ipfilename;
97 close $ipfile if $ipfile;
102 map { $ips{$_} = 1 } @oldips;
103 map { $ips{$_} = 1 } <@ips>;
105 open $ipfile, '>', "$ipfilename"
106 or error "Unable to open $ipfilename - $!", 1;
108 foreach (sort keys %ips) {
109 print $ipfile "$_\n";
114 # Recreate the BICE chain
115 `/sbin/iptables -F BICE`;
116 `/sbin/iptables -X BICE`;
117 `/sbin/iptables -N BICE`;
119 # Add all new @ips to iptables
120 `/sbin/iptables -A BICE -s $_ -p tcp -j DROP` foreach (sort keys %ips);
125 # Use whois(1) to get the email addresses of the responsible parties for an IP
126 # address. Note that a hash is used to eliminate duplicates.
127 sub GetEmailAddresses ($) {
130 # List of whois servers to try
131 # Apparently whois.opensrs.net no longer offers whois service?
135 'whois.nsiregistry.net',
136 #'whois.opensrs.net',
137 'whois.networksolutions.com',
142 foreach (@whois_list) {
146 @lines = grep { /.*\@.*/ } `whois $ip`;
148 @lines = grep {/.*\@.*/ } `whois -h $_ $ip`;
152 my @fields = split /:/, $_;
154 $_ = $fields [@fields - 1];
156 if (/(\S+\@\S[\.\S]+)/) {
157 $email_addresses{$1} = "";
161 # Break out of loop if we found email addresses
162 last unless keys %email_addresses;
165 return keys %email_addresses;
166 } # GetEmailAddresses
168 # Send email to the responsible parties.
169 sub SendEmail ($$$$$) {
170 my ($to, $subject, $message, $ip, $violations) = @_;
173 verbose "Reporting $ip ($violations violations) to $to";
175 verbose "Would have reported $ip ($violations violations) to $to";
180 from => "BICE\@$domain",
189 sub processLogfile () {
192 # Note: Normally you must be root to open up $security_logfile
193 open my $readlog, '<', $security_logfile
194 or error "Unable to open $security_logfile - $!", 1;
196 flock $readlog, LOCK_EX
197 or error "Unable to flock $security_logfile", 1;
204 if (/^(\S+\s+\S+\s+\S+)\s+.*Invalid user (\w+) from (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) {
205 my %violation = $violations{$3} ? %{$violations{$3}} : %_;
207 push @{$violation{$2}}, $1;
209 $violations{$3} = \%violation;
211 $newline =~ s/Invalid user/INVALID USER/;
212 } elsif (/^(\S+\s+\S+\s+\S+)\s+.*authentication failure.*ruser=(\S+).*rhost=(\S+)/) {
213 my %violation = $violations{$3} ? %{$violations{$3}} : %_;
215 push @{$violation{$2}}, $1;
217 $violations{$3} = \%violation;
219 $newline =~ s/authentication failure/AUTHENTICATION FAILURE/;
220 } elsif (/^(\S+\s+\S+\s+\S+)\s+.*Failed password for (\w+) from (\d{1,3}\.\d{1,3}\.d{1,3}\.d{1,3})/) {
221 my %violation = $violations{$3} ? %{$violations{$3}} : %_;
223 push @{$violation{$2}}, $1;
225 $violations{$3} = \%violation;
227 $newline =~ s/Failed password/FAILED PASSWORD/;
230 push @lines, $newline;
233 return %violations unless $update;
235 flock $readlog, LOCK_UN
236 or error "Unable to unlock $security_logfile", 1;
240 open my $writelog, '>', $security_logfile
241 or error "Unable to open $security_logfile for writing - $!", 1;
243 flock $writelog, LOCK_EX
244 or error "Unable to flock $security_logfile", 1;
246 print $writelog $_ foreach @lines;
248 flock $writelog, LOCK_UN
249 or error "Unable to unlock $security_logfile", 1;
256 # Report breakins to the authorities.
257 sub ReportBreakins () {
258 my %violations = processLogfile;
260 my $nbrViolations = keys %violations;
262 if ($nbrViolations == 0) {
263 verbose 'No violations found';
264 } elsif ($nbrViolations == 1) {
265 verbose '1 site attempting to violate our perimeter';
267 verbose "$nbrViolations sites attempting to violate our perimeter";
270 foreach (sort keys %violations) {
275 $attempts += @{$violations{$ip}{$_}} foreach (keys %{$violations{$ip}});
277 my @emails = GetEmailAddresses $ip;
280 verbose 'Unable to find any responsible parties for detected breakin '
281 . "attempts from IP $ip ($attempts breakin attempts)";
285 my $to = join ',', @emails;
286 my $subject = "Illegal attempts to break into $domain from your domain";
287 my $message = <<"END";
288 <p>Somebody from your domain with an IP Address of <b>$ip</b> has been
289 attempting to break into my domain, <b>$domain</b>. <u>Breaking into somebody
290 else's computer is illegal and criminal prosecution can result!</u> As a
291 responsible ISP it is in your best interests to investigate such activity and to
292 shutdown any such illegal activity as it is a violation of law and most likely a
293 violation of your user level agreement. It is expected that you will investigate
294 this and send the result and/or disposition of your investigation back to
295 $contact. <font color=red><b>If you fail to do so then criminal prosecution may
296 result!</b></font></p>
298 <p>Please be aware that <b>none</b> of these attempts to breakin have been
299 successful - this system is configured such that only trusted users are allowed
300 to log in as they must provide authenticated keys in advance. So your attempts
301 have been wholly unsuccessful. Still, this does not diminish the illegality nor
302 the ability of us to pursue this matter in a court of law.</p>
304 <p>There were a total of $attempts attempts to break into $domain. The following
305 is a report of the breakin attempts from IP Address $ip along with the usernames
306 attempted and the time of the attempt:</p>
308 <p>Note: $domain is located in $location. All times are $UTC:</p>
313 foreach my $user (sort keys %{$violations{$ip}}) {
314 if (@{$violations{$ip}{$user}} == 1) {
315 $message .= "<li>The user <b>$user</b> attempted access on $violations{$ip}{$user}[0]</li>";
317 $message .= "<li>The user <b>$user</b> attemped access on the following date/times:</li>";
319 $message .= "<li>$_</li>" foreach (@{$violations{$ip}{$user}});
324 $message .= '</ol><p>Your prompt attention to this matter is expected '
325 . 'and will be appreciated.</p>';
326 SendEmail $to, $subject, $message, $ip, $attempts;
329 AddToIPTables keys %violations;
336 'verbose', sub { set_verbose },
337 'debug', sub { set_debug },
338 'usage', sub { Usage },
341 'file=s', \$security_logfile,
344 Usage 'Must specify filename'
345 unless $security_logfile;
351 =head1 CONFIGURATION AND ENVIRONMENT
353 DEBUG: If set then $debug is set to this level.
355 VERBOSE: If set then $verbose is set to this level.
357 TRACE: If set then $trace is set to this level.
365 L<Getopt::Long|Getopt::Long>
369 =head2 ClearSCM Perl Modules
382 <<a href="http://clearscm.com/php/scm_man.php?file=lib/Display.pm">Display</a><br>
383 <a href="http://clearscm.com/php/scm_man.php?file=lib/Mail.pm">Mail</a><br>
384 a href="http://clearscm.com/php/scm_man.php?file=lib/Utils.pm">Utils</a><br>
389 =head1 BUGS AND LIMITATIONS
391 There are no known bugs in this script
393 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
395 =head1 LICENSE AND COPYRIGHT
397 Copyright (c) 2010, ClearSCM, Inc. All rights reserved.