$ cyanpencil's blog - posts - about - contact

Get notified on Telegram on every ssh login

Step 1: Create a telegram bot

Step 2: Test if the bot is working

You can send messages using the Telegram HTTP API; it’s particularly useful because we can call that from the command line using curl:

curl "https://api.telegram.org/bot$KEY/sendMessage" -d "chat_id=$USERID&text=hello world!"

where $KEY is your bot token and $USERID is your telegram chat id you got before.

You should receive on telegram a message from your newly created bot saying “hello world!”

Step 2: Script to send messages to you from the bot

Now let’s set up a script that gathers information on a ssh client and sends a message to you giving various info such as the user, the IP, and sometimes even the location of the client. We will use the environment variable $SSH_CONNECTION, that contains the client IP and port. This variable is set up each time by sshd for each tty it allocates (that means, for each different connection we will have a different variable in our environment). We will also make a request to https://ipinfo.io, which will give us information such as the AS number and (sometimes) the geolocation of a given IP. The following script will send a message to you like the one in the screenshot above:



DATE_EXEC="$(date "+%d %b %Y %H:%M")" 
if [ -n "$SSH_CONNECTION" ] && [ -z "$TMUX" ] && [[ ! $PAM_TYPE =~ "close_session" ]] ; then 
	IP=$(echo $SSH_CONNECTION | awk '{print $1}') # get client IP address.
	HOSTNAME=$(hostname -f) 
	IPADDR=$(hostname -i | awk '{print $1}') # get server IP address
	curl https://ipinfo.io/$IP -s -o $TMPFILE # info on client IP (json)
	CITY=$(cat $TMPFILE | sed -n 's/^  "city":[[:space:]]*//p' | tr "\"," "  ") 
	REGION=$(cat $TMPFILE | sed -n 's/^  "region":[[:space:]]*//p' | tr "\"," "  ")
	COUNTRY=$(cat $TMPFILE | sed -n 's/^  "country":[[:space:]]*//p' | tr "\"," "  ")
	ORG=$(cat $TMPFILE | sed -n 's/^  "org":[[:space:]]*//p' | tr "\"," "  ")
	TEXT="[$PAM_USER]\n$DATE_EXEC\n$PAM_USER logged in to $HOSTNAME ($IPADDR) \nip:$IP \ncountry: $COUNTRY\ncity: $CITY \nregion: $REGION \norg:$ORG"
	TEXT=$(echo $TEXT | sed "s/\\\n/%0a/g")
	curl -s --max-time 10 -d "chat_id=$USERID&disable_web_page_preview=1&text=$TEXT" $URL > /dev/null
	rm $TMPFILE #clean up after

Substitute the values of USERID and KEY variables with your chat id and bot token you got before. After saving, make sure that the script has the right permissions: chmod 705 your_script.sh (readable and executable by everyone).

Step 3: Execute script on every ssh login

There are various ways we can call the script:

1. Use the pam_exec module

Open the file /etc/pam.d/sshd and append the following line at the end:

session optional pam_exec.so /<path_to_yourscript.sh>

2. Inside sshd config

Open the file /etc/ssh/sshd_config and append the following line:

ForceCommand /<path_to_yourscript.sh>; bash -c ${SSH_ORIGINAL_COMMAND:-bash -il}

We force the execution of our alert script and then continue execution to the given command if it was provided, or to the login shell (bash -il) if the variable $SSH_ORIGINAL_COMMAND is not set.

You can set up more fine-grained checks on when sending the telegram alert this way. Suppose your server is inside a VPN, but it’s also exposed to the internet. Let’s say you want to be alerted only when someone logs in from the internet. Append the following lines to /etc/ssh/sshd_config:

Match Address *,!
	PermitRootLogin no
	ForceCommand /<path_to_yourscript.sh>; bash -c ${SSH_ORIGINAL_COMMAND:-bash -il}

The line Match Address *,! will catch every client that is not connected through your VPN ( We disable root logins from outside our VPN, and ensure that the first command on every successful ssh connection will be executing your script.

You can find much more information on how to set Match rules and other useful commands inside man sshd_config.

3. Inside profile.d

If you’re using a Debian-like system, you can just copy your script inside the /etc/profile.d directory. It will be automatically executed on every login!

Adapted and expanded from: 8192.one’s blog