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 = 'Santa Clara, California, 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
134 'whois.nsiregistry.net',
136 'whois.networksolutions.com',
141 foreach (@whois_list) {
145 @lines = grep { /.*\@.*/ } `whois $ip`;
147 @lines = grep {/.*\@.*/ } `whois -h $_ $ip`;
151 my @fields = split /:/, $_;
153 $_ = $fields [@fields - 1];
155 if (/(\S+\@\S[\.\S]+)/) {
156 $email_addresses{$1} = "";
160 # Break out of loop if we found email addresses
161 last unless keys %email_addresses;
164 return keys %email_addresses;
165 } # GetEmailAddresses
167 # Send email to the responsible parties.
168 sub SendEmail ($$$$$) {
169 my ($to, $subject, $message, $ip, $violations) = @_;
172 verbose "Reporting $ip ($violations violations) to $to";
174 verbose "Would have reported $ip ($violations violations) to $to";
179 from => "BICE\@$domain",
188 sub processLogfile () {
191 # Note: Normally you must be root to open up $security_logfile
192 open my $readlog, '<', $security_logfile
193 or error "Unable to open $security_logfile - $!", 1;
195 flock $readlog, LOCK_EX
196 or error "Unable to flock $security_logfile", 1;
203 if (/^(\S+\s+\S+\s+\S+)\s+.*Invalid user (\w+) from (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) {
204 my %violation = $violations{$3} ? %{$violations{$3}} : %_;
206 push @{$violation{$2}}, $1;
208 $violations{$3} = \%violation;
210 $newline =~ s/Invalid user/INVALID USER/;
211 } elsif (/^(\S+\s+\S+\s+\S+)\s+.*authentication failure.*ruser=(\S+).*rhost=(\S+)/) {
212 my %violation = $violations{$3} ? %{$violations{$3}} : %_;
214 push @{$violation{$2}}, $1;
216 $violations{$3} = \%violation;
218 $newline =~ s/authentication failure/AUTHENTICATION FAILURE/;
219 } elsif (/^(\S+\s+\S+\s+\S+)\s+.*Failed password for (\w+) from (\d{1,3}\.\d{1,3}\.d{1,3}\.d{1,3})/) {
220 my %violation = $violations{$3} ? %{$violations{$3}} : %_;
222 push @{$violation{$2}}, $1;
224 $violations{$3} = \%violation;
226 $newline =~ s/Failed password/FAILED PASSWORD/;
229 push @lines, $newline;
232 return %violations unless $update;
234 flock $readlog, LOCK_UN
235 or error "Unable to unlock $security_logfile", 1;
239 open my $writelog, '>', $security_logfile
240 or error "Unable to open $security_logfile for writing - $!", 1;
242 flock $writelog, LOCK_EX
243 or error "Unable to flock $security_logfile", 1;
245 print $writelog $_ foreach @lines;
247 flock $writelog, LOCK_UN
248 or error "Unable to unlock $security_logfile", 1;
255 # Report breakins to the authorities.
256 sub ReportBreakins () {
257 my %violations = processLogfile;
259 my $nbrViolations = keys %violations;
261 if ($nbrViolations == 0) {
262 verbose 'No violations found';
263 } elsif ($nbrViolations == 1) {
264 verbose '1 site attempting to violate our perimeter';
266 verbose "$nbrViolations sites attempting to violate our perimeter";
269 foreach (sort keys %violations) {
274 $attempts += @{$violations{$ip}{$_}} foreach (keys %{$violations{$ip}});
276 my @emails = GetEmailAddresses $ip;
279 verbose 'Unable to find any responsible parties for detected breakin '
280 . "attempts from IP $ip ($attempts breakin attempts)";
284 my $to = join ',', @emails;
285 my $subject = "Illegal attempts to break into $domain from your domain";
286 my $message = <<"END";
287 <p>Somebody from your domain with an IP Address of <b>$ip</b> has been
288 attempting to break into my domain, <b>$domain</b>. <u>Breaking into somebody
289 else's computer is illegal and criminal prosecution can result!</u> As a
290 responsible ISP it is in your best interests to investigate such activity and to
291 shutdown any such illegal activity as it is a violation of law and most likely a
292 violation of your user level agreement. It is expected that you will investigate
293 this and send the result and/or disposition of your investigation back to
294 $contact. <font color=red><b>If you fail to do so then criminal prosecution may
295 result!</b></font></p>
297 <p>Please be aware that <b>none</b> of these attempts to breakin have been
298 successful - this system is configured such that only trusted users are allowed
299 to log in as they must provide authenticated keys in advance. So your attempts
300 have been wholly unsuccessful. Still, this does not diminish the illegality nor
301 the ability of us to pursue this matter in a court of law.</p>
303 <p>There were a total of $attempts attempts to break into $domain. The following
304 is a report of the breakin attempts from IP Address $ip along with the usernames
305 attempted and the time of the attempt:</p>
307 <p>Note: $domain is located in $location. All times are $UTC:</p>
312 foreach my $user (sort keys %{$violations{$ip}}) {
313 if (@{$violations{$ip}{$user}} == 1) {
314 $message .= "<li>The user <b>$user</b> attempted access on $violations{$ip}{$user}[0]</li>";
316 $message .= "<li>The user <b>$user</b> attemped access on the following date/times:</li>";
318 $message .= "<li>$_</li>" foreach (@{$violations{$ip}{$user}});
323 $message .= '</ol><p>Your prompt attention to this matter is expected '
324 . 'and will be appreciated.</p>';
325 SendEmail $to, $subject, $message, $ip, $attempts;
328 AddToIPTables keys %violations;
335 'verbose', sub { set_verbose },
336 'debug', sub { set_debug },
337 'usage', sub { Usage },
340 'file=s', \$security_logfile,
343 Usage 'Must specify filename'
344 unless $security_logfile;
350 =head1 CONFIGURATION AND ENVIRONMENT
352 DEBUG: If set then $debug is set to this level.
354 VERBOSE: If set then $verbose is set to this level.
356 TRACE: If set then $trace is set to this level.
364 L<Getopt::Long|Getopt::Long>
368 =head2 ClearSCM Perl Modules
381 <<a href="http://clearscm.com/php/scm_man.php?file=lib/Display.pm">Display</a><br>
382 <a href="http://clearscm.com/php/scm_man.php?file=lib/Mail.pm">Mail</a><br>
383 a href="http://clearscm.com/php/scm_man.php?file=lib/Utils.pm">Utils</a><br>
388 =head1 BUGS AND LIMITATIONS
390 There are no known bugs in this script
392 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
394 =head1 LICENSE AND COPYRIGHT
396 Copyright (c) 2010, ClearSCM, Inc. All rights reserved.