Thursday, July 5, 2012

sshwatch using geoiptool.com

I've written a script called 'sshwatch' that will process the default /var/log/secure file, associate the folks that have logged in against a a geoip lookup (using geoiptool.com). The idea is that you should be wary of people logging in from countries that are not expected. It will only look up each IP address once, so if you have multiple logins from the same IP, we only do a single geoip lookup. If you put this script in /etc/cron.daily/sshwatch - you'll get an e-mail each night about who's been on your box. I think it only works on RHEL and CentOS right now. Enjoy:
#!/usr/bin/perl
# Send a little report of who's been loggin in and from where.
# Joey 

use strict;
my %userblob;
$|++;

for (`cat /var/log/secure*`) {

   if (/Accepted/) { # Somebody logged in..

      my ( $user, $ip) = ( $1, $2 ) if (/for (.*?) from (.*?) /);
      $userblob{$ip}->{'IP'} = $ip;

      unless ( $userblob{$ip}->{'COUNTRY'} ) {
         $userblob{$ip}->{'COUNTRY'} = get_country($ip);
      }

      my $seen;
      for ( @{$userblob{$ip}->{'USER'}} ) {
         $seen ++ if ( $_ eq $user );
      }
      push @{$userblob{$ip}->{'USER'}}, $user unless ($seen)
   }
}

my @mail;
while ( my ($ip, $ref) = each %userblob ) {
   push @mail, "$ip :: $ref->{'COUNTRY'} :: @{$ref->{'USER'}}\n";
}

send_mail(@mail);

sub get_country() {

   my $ip = shift;
   print "Looking up: $ip: ";
   my $url = "http://www.geoiptool.com/en/?IP=$ip";
   my $data = `GET "$url"`;
   my $country = $1 if ( $data =~ /Country:.*\n.*\> (.*?)<\/a/m );
   print "$country\n";

   return $country if ($country);
   return undef;
}

sub send_mail() {

   my @body = @_;

   open  MAIL, "|/usr/sbin/sendmail.postfix -t";
   print MAIL "to: your.e-mail\@domain.com\n"
            . "from: your.mama\@domain.com\n"
            . "Subject: SSHWatch Report\n\n";

   map { print MAIL "$_" }@body;
   close(MAIL);
}