Set up an email alert for SSH connections (Ubuntu + Openssh + Sendemail)


Looking to monitor my SSH server and trigger an email alert for any SSH connections to my Ubuntu server I've pulled together a very basic script that will send an email when someone logs into an SSH server. Read on...



My ssh server is based around Openssh. Openssh executes the file /etc/ssh/sshrc if it exists when a user logs in via SSH. By default I did not have an sshrc file so I created one as follows to enable an email script to be executed on connection.

From the sshd manual:

If the file ~/.ssh/rc exists, sh(1) runs it after reading the environment files but before starting the user’s shell or command. It must not produce any output on stdout; stderr must be used instead. If X11 forwarding is in use, it will receive the "proto cookie" pair in its standard input (and DISPLAY in its environment). The script must call xauth(1) because sshd will not run xauth automatically to add X11 cookies.

The primary purpose of this file is to run any initialization routines which may be needed before the user’s home directory becomes accessible; AFS is a particular example of such an environment.

This file will probably contain some initialization code followed by something similar to:
if read proto cookie && [ -n "$DISPLAY" ]; then
if [ ‘echo $DISPLAY | cut -c1-10‘ = ’localhost:’ ]; then
# X11UseLocalhost=yes
echo add unix:‘echo $DISPLAY |
cut -c11-‘ $proto $cookie
else
# X11UseLocalhost=no
echo add $DISPLAY $proto $cookie
fi | xauth -q -
fi


If this file does not exist, /etc/ssh/sshrc is run, and if that does not exist either, xauth is used to add the cookie.


The email sshrc script outlined below relies on the SendEmail program. SendEmail from Brandon Zehm is a very simple email program that doesn't require an email server to be setup on your machine i.e. no need to configure postfix, sendmail or exim4. The current challenge is the password is stored in clear text in the script which is a trade off for using such a nice and simple email app to address this I suggest 1) the script has appropriate read permissions set via chmod to stop people looking into it, and 2) use a disposable email address with a password that is unique for this purpose.

The email sent by the script below captures the:

username of the user that connect;
hostname of the machine logged into;
IP of the user that connects;
ISP of the user that connects;  
Reverse DNS of the user that connects;
Date and time of the connection; and 
a reminder of the script file which has generated the email.

 How to get it all working: 

1. Install sendemail, ssl perl and ssleay perl:

sudo apt-get install sendemail libio-socket-ssl-perl libnet-ssleay-perl

2. Create /etc/ssh/sshrc:

sudo gedit /etc/ssh/sshrc 


3. Add the following lines to your /etc/ssh/sshrc file (this script is design to use Google as the SMTP email server):

DATE=`date "+%d.%m.%Y %Hh%Mm"`
IP=`echo $SSH_CONNECTION | awk '{print $1}'`
REVERSE=`dig -x $IP +short`

WHO=$(whois $IP | grep desc | tail -1 | cut -c 17-)

MESSAGE="SSH Connection from $USER on "`echo "$HOSTNAME"`
MESSAGE=$MESSAGE`echo "\nIP : $IP \n"`
MESSAGE=$MESSAGE`echo "\nISP : $WHO \n"`
MESSAGE=$MESSAGE`echo "\nHost: $REVERSE \n"`
MESSAGE=$MESSAGE`echo "\nDate: $DATE \n"`
MESSAGE=$MESSAGE`echo "\nFrom /etc/ssh/sshrc \n"`

SUBJECT="SSH Connection from "$USER" on "$HOSTNAME

sendemail -v -f addresstosendemailfrom -s smtp.gmail.com:587 -xu username -xp 'password' -t addresstosendemailto -o tls=yes -u $SUBJECT -m "$MESSAGE" > /dev/null 2>&1


This script is also here since I haven't easily figure how to embed code in blogger yet
Save and exit 

Note if ~/.ssh/rc exists the /etc/ssh/sshrc script will not be executed. 

> /dev/null 2>&1  - note this line is used to redirect the sendemail command output to /dev/null. This effectively suppresses the sendemail command so that it operates silently i.e. when you log in via SSH the SSH terminal does not see the output of the email script. You can run the script without > /dev/null 2>&1 but you'll see the output of the command in the ssh terminal and it may alert anyone connecting that their log in has tripped an email.

$HOSTNAME - hostname doesn't work for me in the email I can't figure out why, the script works fine on the local machine but not when executed from SSHRC, if anyone has a solution please add a comment. Thanks 

9 comments:

  1. hi
    i have followed your steps, did not have a sshrc file in the beginning, but i am getting a Syntax error: EOF in backquote substitution foe line 16. even though there is only 15 lines of text in your tutorial. have you come across this before?

    ReplyDelete
    Replies
    1. suggests to me you may have copied a line break, I need to work out how to properly embed code into blogger but it doesn't look straightforward.

      Until then http://pastebin.com/mFsFKJPZ

      Delete
    2. Thanks for the update!
      It is mostly working now. i am still getting a few issues with the REVERSE line, but that gone is not an issue.

      Are you aware of a way to trigger this sort of process, when someone makes a sftp connection? i ask as most users dont have terminal access, and subsequently dont trigger the mail process.

      Your help has been fantastic so far. i hope it is possible

      Thanks again

      Delete
    3. I don't think sftp has the ability to kick off a script. Note the ssh rc script actually runs in the SSH session which itself is intended for shell command execution. I suspect you could watch the sftp log with something like tail and grep and when a login is detected then fire off a script - a little messy since you need to have a continuous watch or a watch job.

      Delete
  2. DATE=`date "+%d.%m.%Y %Hh%Mm"`
    IP=`echo $SSH_CONNECTION | awk '{print $1}'`
    REVERSE=`dig -x $IP +short`
    WHO=$(whois $IP | grep desc | tail -1 | cut -c 17-)

    MESSAGE="SSH Connection from $USER on "`echo "$HOSTNAME"`
    MESSAGE=$MESSAGE`echo "\nIP : $IP \n"`
    MESSAGE=$MESSAGE`echo "\nISP : $WHO \n"`
    MESSAGE=$MESSAGE`echo "\nHost: $REVERSE \n"`
    MESSAGE=$MESSAGE`echo "\nDate: $DATE \n"`
    MESSAGE=$MESSAGE`echo "\nFrom /etc/ssh/sshrc \n"`

    SUBJECT="SSH Connection from "$USER" on "$HOSTNAME

    sendemail -v -f test@gmail.com -s smtp.gmail.com:587 -xu test -xp 'testpassword' -t test2@gmail.com -o tls=yes -u $SUBJECT -m "$MESSAGE"

    please help me debug this error with tls.

    May 03 13:35:34 ubuntu-server sendemail[4740]: DEBUG => Connecting to smtp.gmail.com:587
    May 03 13:35:34 ubuntu-server sendemail[4740]: DEBUG => My IP address is: x.x.x.x
    May 03 13:35:35 ubuntu-server sendemail[4740]: SUCCESS => Received: 220 mx.google.com ESMTP wl5sm11816102pac.18 - gsmtp
    May 03 13:35:35 ubuntu-server sendemail[4740]: INFO => Sending: EHLO ubuntu-server
    May 03 13:35:35 ubuntu-server sendemail[4740]: SUCCESS => Received: 250-mx.google.com at your service, [y.y.y.y], 250-SIZE 35882577, 250-8BITMIME, 250-STARTTLS, 250 ENHANCEDSTATUSCODES
    May 03 13:35:35 ubuntu-server sendemail[4740]: INFO => Sending: STARTTLS
    May 03 13:35:35 ubuntu-server sendemail[4740]: SUCCESS => Received: 220 2.0.0 Ready to start TLS
    invalid SSL_version specified at /usr/share/perl5/IO/Socket/SSL.pm line 332

    please refer the below informtion where the line 332 refers to "($arg_hash) || return;" please help me

    );

    #Avoid passing undef arguments to Net::SSLeay
    defined($arg_hash->{$_}) or delete($arg_hash->{$_}) foreach (keys %$arg_hash);

    my $vcn_scheme = delete $arg_hash->{SSL_verifycn_scheme};
    if ( $vcn_scheme && $vcn_scheme ne 'none' ) {
    # don't access ${*self} inside callback - this seems to create
    # circular references from the ssl object to the context and back

    # use SSL_verifycn_name or determine from PeerAddr
    my $host = $arg_hash->{SSL_verifycn_name};
    if (not defined($host)) {
    if ( $host = $arg_hash->{PeerAddr} || $arg_hash->{PeerHost} ) {
    $host =~s{:[a-zA-Z0-9_\-]+$}{};
    }
    }
    $host ||= ref($vcn_scheme) && $vcn_scheme->{callback} && 'unknown';
    $host or return $self->error( "Cannot determine peer hostname for verification" );

    my $vcb = $arg_hash->{SSL_verify_callback};
    $arg_hash->{SSL_verify_callback} = sub {
    my ($ok,$ctx_store,$certname,$error,$cert) = @_;
    $ok = $vcb->($ok,$ctx_store,$certname,$error,$cert) if $vcb;
    $ok or return 0;
    my $depth = Net::SSLeay::X509_STORE_CTX_get_error_depth($ctx_store);
    return $ok if $depth != 0;

    # verify name
    my $rv = verify_hostname_of_cert( $host,$cert,$vcn_scheme );
    # just do some code here against optimization because x509 has no
    # increased reference and CRYPTO_add is not available from Net::SSLeay
    return $rv;
    };
    }

    ${*$self}{'_SSL_arguments'} = $arg_hash;
    ${*$self}{'_SSL_ctx'} = IO::Socket::SSL::SSL_Context->new($arg_hash) || return;
    ${*$self}{'_SSL_opened'} = 1 if $is_server;

    return $self;
    }

    ReplyDelete
  3. If i select the "tls=no" then i see the below information. which make me beleive the google does not allow unencrypted connection.


    May 03 13:48:35 ubuntu-server sendemail[5266]: DEBUG => Connecting to smtp.gmail.com:587
    May 03 13:48:35 ubuntu-server sendemail[5266]: DEBUG => My IP address is: x.x.x.x
    May 03 13:48:36 ubuntu-server sendemail[5266]: SUCCESS => Received: 220 mx.google.com ESMTP t1sm11880579pab.12 - gsmtp
    May 03 13:48:36 ubuntu-server sendemail[5266]: INFO => Sending: EHLO ubuntu-server
    May 03 13:48:36 ubuntu-server sendemail[5266]: SUCCESS => Received: 250-mx.google.com at your service, [y.y.y.y], 250-SIZE 35882577, 250-8BITMIME, 250-STARTTLS, 250 ENHANCEDSTATUSCODES
    May 03 13:48:36 ubuntu-server sendemail[5266]: NOTICE => Authentication not supported by the remote SMTP server!
    May 03 13:48:36 ubuntu-server sendemail[5266]: INFO => Sending: MAIL FROM:
    May 03 13:48:36 ubuntu-server sendemail[5266]: ERROR => Received: 530 5.7.0 Must issue a STARTTLS command first. t1sm11880579pab.12 - gsmtp

    please help thanks in advance!!!

    ReplyDelete
  4. test@ubuntu-server:~$ ssh -V
    OpenSSH_6.0p1 Debian-3ubuntu1, OpenSSL 1.0.1c 10 May 2012


    sorry forgot to mention which version i was running.

    ReplyDelete
  5. Its a bug, work around here

    http://raspberrypi.stackexchange.com/questions/2118/sendemail-failure

    ReplyDelete
  6. Thank you thats working great!

    ReplyDelete