Skip to content

Month: May 2017

Get real time Telegram notification when SSH login on Linux

Traditionally, Linux system admins use commands such as last, lastlog or some log analysis service to monitor user logins and catch suspicious activities. This is a good security practice. However these methods have their drawbacks – as the usual approch is to do periodic scans there could be delay between a login event and the report of incident. The delay could be minutes to hours depends on how the system is configured.

In this post I’m going to introduce a way to get near real time notification when a user login event occurred. This method make use of the popular instant messaging cilent Telegram and its Bot API to send a notification on user login so the delay is usually within just a couple of seconds!

The basic idea

Telegram Bot is a special kind of account that operated by software instead of real human being. Telegram provides a HTTP API to control the bot, to do things like send a message, or receive a message and process it as command, etc. etc. I have made use of that feature to do following things:

  1. On user login, run a script.
  2. The script calls Telegram Bot API to send a message.
  3. The message is sent by Telegram server to my Telegram account.
  4. My Telegram client on phone and PC receive the message, I know a login event occured.

All this happends right after the user logs in. I usually got the notification from Telegram on PC within 2 secs. Keep reading to see how to set up this.

Setup a Telegram bot

First of all, you’ll need to have a Telegram account and create a Telegram bot. I won’t go into detail for this as it is easy and is already well documented on Telegram website. Check it out here.

Once the setup of bot is finished, a token will be allocated for the bot. Keep that token. It will be used by the script to control the bot via Telegram HTTP API.

Connect the bot with your Telegram account

For obvious reason regarding privacy, a Telegram bot cannot initiate a message to a Telegram user. If you need to received messsages from a bot, you need to first start a chat with it and send a hello message. This process is like talking to a readl human account, just talk to the bot and send any text is OK.

After you initiate the chat, the bot and you is now in a conversation which represents by an unique ID in Telegram API. We need to find out this conversation ID, as it will be the “destination” for our script to send notification message to.

Here is how to get that chat ID – first send a message to the bot, then access the Telegram API getUpdates.

The API URL is https://api.telegram.org/bot<your bot token>/getUpdates. HTTP method GET should be used to access it. <your bot token> is the token allocated to your bot, as mentioned above.

I use curl to do this.

$ curl "https://api.telegram.org/bot<bot token>/getUpdates"
{"ok":true,"result":[{"update_id":xxxxxxxxx,
"message":{"message_id":1954,"from":{"id":xxxxxxxxx,"first_name":"Your first name","last_name":"Your last name","username":"Your telegram user name"},"chat":{"id":xxxxxxxxx,"first_name":"Your first name","last_name":"Your last name","username":"username","type":"private"},"date":1494671101,"text":"test"}}]}

The return message is a JSON text. This is how it looks after beautification.

{
  "ok": true,
  "result": [{
    "update_id": xxxxxxxxx,
    "message": {
      "message_id": 1954,
      "from": {
        "id": xxxxxxxxx,
        "first_name": "Your first name",
        "last_name": "Your last name",
        "username": "username"
      },
      "chat": {
        "id": xxxxxxxxx,          <--- This is the chat ID you need.
        "first_name": "Your first name",
        "last_name": "Your last name",
        "username": "username",
        "type": "private"
      },
      "date": 1494671101,
      "text": "test"
    }
  }]
}

Note down the value of message.chat.id, we will need it in the script.

Create a script to send message via the bot

Now we need to create a script which sends a predefined message via Telelgram.

Create a executable script file named /usr/local/bin/tgbot.sh and put below content in.

#!/bin/bash

KEY="<your bot token>"

URL="https://api.telegram.org/bot$KEY/sendMessage"

TARGET="<your chat ID>" # Telegram ID of the conversation with the bot, get it from /getUpdates API

TEXT="User *$PAM_USER* logged in on *$HOSTNAME* at $(date '+%Y-%m-%d %H:%M:%S %Z')
Remote host: $PAM_RHOST
Remote user: $PAM_RUSER
Service: $PAM_SERVICE
TTY: $PAM_TTY"

PAYLOAD="chat_id=$TARGET&text=$TEXT&parse_mode=Markdown&disable_web_page_preview=true"

# Run in background so the script could return immediately without blocking PAM
curl -s --max-time 10 --retry 5 --retry-delay 2 --retry-max-time 10 -d "$PAYLOAD" $URL > /dev/null 2>&1 &

Remember to replace <your bot token> and <your chat ID> with the real data of your own.

Basically, this script use curl to access the Telegram HTTP API to send a text message to the designated user. Those $PAM_* variables are provided by PAM, they will be explained later.

You can now run this script to test. If everything goes right, your Telegram client will receieve a message like this:

User  logged in on myhost at 2017-05-13 18:45:20 CST
Remote host: 
Remote user: 
Service: 
TTY:

That means the script is working. The real useful information is still empty, they will be filled in when running by PAM.

Run the script when a user logs in on the server

Now the final part is to make the script running when a user logs in on the server.

There are some information available on the Internet regarding this topic, however most of them just put the command to run in the user’s shell init script, such as .bashrc, or /etc/profile or a script under /etc/profile.d/. This way works, but is not secure. Because a user have access to his own shell init scripts such as .bashrc or .zshrc, a hacker who steal the user’s identitiy and log in on the server can easily remove the command from the script or remove the script itself entirely. This makes it practically useless – the script will only be run just once and send out the notification once, then the hacker is able to mute it.

A better approach is to use the capability of PAM. I’ve introduced it in an earlier post, read it if you are not familiar with PAM yet.

Here we are going to use the pam_exec module to accomplish our goal. This module is part of the PAM and it can run a command specified by user. We can use it to run the Telegram message sending script on user login, then we will be able to accomplish our goal. Here is how.

Edit the file /etc/pam.d/system-auth, this is the PAM service that will be called by many system commands that tries to authenticate a user, SSH is one of them. Put below line at the last line.

session optional pam_exec.so type=open_session seteuid /usr/local/bin/tgbot.sh

This command tells PAM to run the script /usr/local/bin/tgbot.sh after a user successfully authenticated himself and logged into the system. The pam_exec module will export a few environment variables so the script could read them and send in the message. Below are the explaination of the variables.

PAM_USER: name of the user name who is logging in.
PAM_RHOST: the remote host that the user connects from.
PAM_RUSER: the user name on the remote host that the user connects from.
PAM_SERVICE: the PAM service, which in some way represents the system service that user trying to access.
PAM_TTY: if the user logs in locally, this will be the TTY name. For remote login via SSH, it will just be “ssh”.

These variables are send in the Telegram message, so we can now who from where on when has logged in on which server via which service, enough for us to know whether it normal or suspecious.

As this file is only writable by root, a non-root user could not bypass this step. This is much secure than the shell init script method. Of course, if the root user is hacked it still could be modified and the notification could be muted. Some further facility could be deployed to mitigate this problem, such as file integrity check, which is beyond the scope of this article.

Test it

Now login in to the server via SSH, and you will be able to recieve a message on Telegram from the bot, like in below screenshot. Congratulations!

More

In fact, this is just an demostration of the functionality of pam_exec and Telegram bot. You can actually do more. A few ideas is on my mind.

  • Trigger a system task such as mount a remote filesystem on user login via pam_exec.
  • Send a log to a remote server on user login via pam_exec.
  • Send notification via Telegram on failure of a critical system crontab.
  • Send notification via Telegram when system update is available.
  • And more….
5 Comments