Setting up an email notification for SSH logins

Hi,

I want to set up our server so that I get emailed when someone logs in via SSH. We recently had a malicious actor get in, and I want to be more up to date if it happens again. So I have a bash script:

recipient="[email protected]"

subject="SSH Login Alert"

message="SSH login detected on $(hostname) at $(date) by user $(whoami) from $(echo $SSH_CONNECTION | awk '{print $1}')"

echo "Message: $message" >> /tmp/ssh_login_debug.log

echo "$message" | /usr/bin/mail -s "$subject" "$recipient"

and /usr/local/bin/sftp_with_notifications.sh:

#!/bin/bash

# Your email notification script

/usr/local/bin/notify_login_ssh.sh

# Execute the internal-sftp command

internal-sftp

Then in /etc/ssh/sshd_config, I have:

Match User sftp_dummy99,admin,north_admin,athertons,westbrook,bfc,saliscare,camera,brettinc,katie,costumes,marike,tessa,bob,andyadmin,directmilk,newstreet,ukraine,stats,newstree2,test,raffner,newbyhost,euprwire,george,executivethreat,machinegazette,nettlegrasp,punkindustry,ukprwire,usprwire,clickpress,octobrachia,store,accounts,willr,gcsescience,teardrop,hatlamp,ibrahim,usinglaw
ChrootDirectory %h
    X11Forwarding no
    AllowTCPForwarding no
    #ForceCommand internal-sftp
    **ForceCommand /usr/local/bin/sftp_with_notification.sh**

I restart the ssh service, and then connect via SSH again. But nothing. It logs me in, but no emails

Also as a sidenote - does sshd_config get overwriten? I can see the Match User part updates with new users, so I’m not sure if the new ForceCommand would get re-written as well?

Thanks

Andy

I think only the match User line get overwritten

Cool thanks. I’m still trying to work out how to get this to work:

    #ForceCommand internal-sftp
    ForceCommand /usr/local/bin/sftp_with_notification.sh

Is it possible to do && like we do in crons? So:

ForceCommand /usr/local/bin/sftp_with_notification.sh && internal-sftp

?

The current way I have it never seems to trigger the second script (I’m not sure where internal-sftp is… is it a script?)

Ok, I worked out a way :slight_smile: Rather than editing sshd_config, I edited

/etc/pam.d/sshd

Add this to the end:

session optional pam_exec.so seteuid /usr/local/bin/notify_login_ssh.sh

So have the script:

/usr/local/bin/notify_login_ssh.sh =>

#!/bin/bash

# Change this to your email address

recipient="[email protected]"

subject="SSH Login Alert"

message="SSH login detected on $(hostname) at $(date) by user $(whoami) from $(echo $SSH_CONNECTION | awk '{print $1}')"

#echo "Message: $message" >> /tmp/ssh_login_debug.log

echo "$message" | /usr/bin/mail -s "$subject" "$recipient"

Now I get the emails fine. If you don’t want it emailing when you login, just put an extra condition in the script:

# if the IP is ours, lets skip - otherwise lets do the email
if [ "$(echo $SSH_CONNECTION | awk '{print $1}')" == "81.174.134.133" ]; then
        exit 0
fi

Hopefully that helps someone else :})

If you have CSF/LFD installed (By default is not in hestiaCP)…, it will trigger the emails to you on-time. Also it will give more security of logins. It can prevent lot of malicious login SPAMMER attempts too.

1 Like

For anyone interested, this is the new script I’ve come up with:

#!/bin/bash

this_ip=$(echo $SSH_CONNECTION | awk '{print $1}')

# IPs to skip
skip_ips=("81.174.134.133") # your IP - add in as many as you want to ignore

if [ "$PAM_TYPE" = "close_session" ]; then
    exit 0
fi

for ip in "${skip_ips[@]}"; do
    if [ "$this_ip" == "$ip" ]; then
        exit 0
    fi
done

# File to store the timestamp of the last sent message
timestamp_file="/tmp/last_msg_timestamp"

# Check if we can send a message based on the timestamp
if [ -f "$timestamp_file" ]; then
    last_sent=$(cat "$timestamp_file")
    current_time=$(date +%s)
    if (( current_time - last_sent < 300 )); then
        echo "less than 5 mins ago... skip"
        exit 0
    fi
fi

# If we are on localhost, we are most likely using the filemanager... so lets grab the last line of the access log, so wecan see the true IP accessing it
last_log=""
if [ "$this_ip" == "127.0.0.1" ]; then
    last_log=$(grep -E 'GET /fm/' /var/log/hestia/nginx-access.log | tail -n 1)
fi
last_log_sanitized=$(echo "$last_log" | sed 's/\\/\\\\/g; s/"/\\"/g')

message="SSH login detected on $(hostname) at $(date) by user $PAM_USER from $this_ip $last_log_sanitized"

curl --include --header "Authorization: Authorization: Basic xxxxx=" --request POST --header "Content-Type: application/json" --data-binary "{
        \"messages\":[ { \"source\":\"admin-script\", \"body\":\"$message \", \"to\":\"+44123412341234\" } ]
    }" 'https://rest.clicksend.com/v3/sms/send'


echo "$message" | /usr/bin/mail -s "SSH Login Alert" "[email protected]"

# Update the timestamp
date +%s > "$timestamp_file"

It uses clicksend.com to send out the SMS’s to my phone. It also has a 5 minute timer so that it doesn’t ping you lots of times if someone keeps opening new sessions (something that was very annoying!)

If you wanted the timeout to work on a per-IP basis, you could also do:

timestamp_file="/tmp/last_msg_timestamp_$this_ip"

If someone logs in via the FileManager, this uses a SSH (well, SFTP) connection - which triggers this script. So what I’ve done is also included a tail of the nginx-access.log log, so that you can see the actual IP being used to access it :slight_smile:

2 Likes