Usually we set our Linux servers and Desktops quite secure, but however, time to time we need to watch our system if it got break in.

Is there a way to let us know right after a 'unwanted' login?

Yes, here is my tips.


The method is to write a script to monitor /var/logsecure, and send e-mail alert when find unwanted logins.

For /var/log/secure config, set the following lines in /etc/rsyslog.conf

# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure

Script description

1. Use perl to keep tracking /var/log/secure

2. search susccefully login lines(or  unsuccessful attempts)

3. ignore trusted logins

4. daemonize the above steps


#!/usr/bin/perl -w

use strict;
use POSIX qw(setsid);
use File::Tail;

my $linenumfile = '/var/log/authmonitor/linenum';     ## keep track of line num in case of crash
my $logfile = '/var/log/authmonitor/authmonitor.log'; ## log file of suspicious logins

my $secure = '/var/log/secure';                    ## secure log file to parse

## change time limits for email as needed
my $maxemails = 4;                                 ## max emails that can be sent per $timelimit
my $timelimit = 3600;                              ##
my $emailcount = 0;
my $timetonext = 0;

sub daemonize {
    chdir '/'                 or die "Can't chdir to /: $!";
    open STDIN, '/dev/null'   or die "Can't read /dev/null: $!";    
    open STDOUT, '>>/dev/null' or die "Can't write to /dev/null: $!";   
    open STDERR, '>>/dev/null' or die "Can't write to /dev/null: $!";
    defined(my $pid = fork)   or die "Can't fork: $!";   
    exit if $pid;
    setsid  or die "Can't start a new session: $!";
    umask 0;

## TODO: change mailtarget
sub sendmail {
  my $timenow = time();
  if ($timenow > $timetonext) {
      $emailcount = 0;
  if ($emailcount == 0) {
      $timetonext = $timenow + $timelimit;
  if (($emailcount >= $maxemails) && ($timenow <= $timetonext)) {
  my $msg = $_[0];
  ### Of course, the sysadmin should have editted /etc/aliases and added a
  ### real person to the alias for root! 
  my $mailfrom = 'root@localhost';
  my $mailtarget = 'root@localhost';
  my $sm = "/usr/sbin/sendmail -t";
  open( SENDMAIL, "|$sm" ) or die( "Cannot open $sm: $!" );
  print SENDMAIL "From: $mailfrom\n";
  print SENDMAIL "Reply-to: $mailtarget\n";
  print SENDMAIL "To: $mailtarget\n";
  print SENDMAIL "Subject: Suspicious SSH Connection from outside \n";
  print SENDMAIL "Content-type: text/plain\n\n";
  print SENDMAIL "Dear System Adminstrator:\n\n";
  print SENDMAIL "authmond has detected a successful login from someone outside:\n\n";
  print SENDMAIL "$msg\n\n";
  if ($emailcount == ($maxemails - 1)) {
      print SENDMAIL "Please see $logfile\n";
  close( SENDMAIL );

# flush the buffer
$| = 1;
# daemonize the program

## linenum is number of lines parsed so far in secure log file
my $linenum = "0";
my $FH;
if (-e $linenumfile) {
  open ($FH, "<$linenumfile") or die $!;
     local $/;
     $linenum = <$FH>;
  close $FH;
} else {
  open ($ FH, "+>$linenumfile") or die $!;
  print $FH "0";
  close $FH;

## cnt is number of lines in secure log file
my $cnt = 0;
open($FH, $secure) or die $!;
$cnt++ while <$FH>;
close $FH;

## start is number of lines that need to be parsed in log file; if < 0, file has been rotated
## so reset linenum and parse whole file (negative tail)
my $start = $cnt - $linenum;
if ($start < 0) {
    $linenum = 0;

## load secure log file into File::Tail module
my $file=File::Tail->new(name=>$secure, interval=>10, tail=>$start, maxinterval=>60);

## main loop - look for suspicious attempts and log, send email if found
while(1) {  
   while (defined(my $line = $file->read)) {
       #print "DBG: Line: $line\n";
       #print "Linenum: $linenum\n";
       if ($line =~ ': Accepted publickey' or $line =~ ': Accepted password' or $line =~ ': Accepted keyboard-interactive/pam') {
       if ($line !~ 'truted ip' and $line !~ 'trusted ips') {
             #print "$line";
             sendmail $line;
             open ($FH, "+>>$logfile") or die $!;
             print $FH $line;
             close $FH;
       open ($FH, "+>$linenumfile") or die $!;
       print $FH $linenum;
       close $FH;

## should never execute...
print "something wrong with authmond....\n";