This page looks best with JavaScript enabled

Telegram SSH

 ·  🎃 kr0m

No system is inexpugnable, so the more precautions we take, the less likely we are to be owned. In this case, we will configure a notification system via Telegram that will alert us every time someone accesses our system via ssh.

First, we make a copy of the PAM config for the ssh service:

mkdir /root/pam.dBackup
cp /etc/pam.d/sshd /root/pam.dBackup/

We modify the config to execute our script, adding the following line at the beginning:

vi /etc/pam.d/sshd

auth requisite pam_python.so /lib/security/looter.py

Now we install the necessary PAM modules to run our python script. Here’s how to do it on a Debian/Gentoo system:

apt install libpam-python python-pip

In Gentoo, for some strange reason, there is no libpam-python. We alienate the Debian package and copy the module:

emerge -av dev-python/pip

wget http://ftp.br.debian.org/debian/pool/main/p/pam-python/libpam-python_1.0.6-1_amd64.deb
alien --to-tgz libpam-python_1.0.6-1_amd64.deb
cp ./lib/x86_64-linux-gnu/security/pam_python.so /lib64/security/
chmod 755 /lib64/security/pam_python.so

We install the dependencies of the python script:

pip install requests --user

We generate a bot with botfather, and obtain the apiKey.

With userinfo, we get the userId:
https://telegram.me/userinfobot

We write our script:

vi /lib/security/looter.py

import spwd
import crypt
import requests
import syslog
import os.path
import time
import socket

# http://pam-python.sourceforge.net/doc/html/

def sendMessage(msg):
    #syslog.openlog(facility=syslog.LOG_AUTH)
    #syslog.syslog("----- Sending TelegramBot message ------")
    #syslog.closelog()

    apiKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    userId = "YYYYYYYY"
    data = {"chat_id":userId,"text":msg}
    url = "https://api.telegram.org/bot{}/sendMessage".format(apiKey)

    #nowEpoch = int(time.time())
    #if os.path.isfile('/tmp/lastTelegramMessage'):
    #    file = open('/tmp/lastTelegramMessage', "r")
    #    lastEpoch = int(file.read())
    #    lastMessage = nowEpoch - lastEpoch
    #    #print ("lastCall: %i" % lastCall)
    #    if lastMessage < 8:
    #        return

    #file = open('/tmp/lastTelegramMessage',"w")
    #file.write('%d' % nowEpoch)
    #file.close

    r = requests.post(url,json=data)

# Called function 3 times: 2 times login action, 1 time logout action
def pam_sm_setcred(pamh, flags, argv):
    hostname = socket.gethostname()
    if (pamh.rhost != 'A.A.A.A' and pamh.rhost != 'B.B.B.B'):
        #syslog.openlog(facility=syslog.LOG_AUTH)
        #syslog.syslog("-- AUTHPAM -- sm_setcred")
        #syslog.syslog("-- AUTHPAM -- From: " + str(pamh.rhost) + " -- User: " + str(pamh.get_user())  + " -- Data: " + str(pamh.pamh))

        sessionFile = '/tmp/looter' + str(pamh.pamh)
        if os.path.isfile(sessionFile):
            file = open(sessionFile, "r")
            loginN = int(file.read())
            file.close
            #syslog.syslog("-- AUTHPAM -- File EXISTS, value: " + str(loginN))
            if loginN == 1:
                #syslog.syslog("-- AUTHPAM -- File content: 1")
                file = open(sessionFile,"w")
                file.write('2')
                file.close
            if loginN == 2:
                #syslog.syslog("-- AUTHPAM -- File content: 2")
                sendMessage("SSH Activity detected from: " + str(pamh.rhost) + "\n- Host: " + str(hostname) + "\n- User: " + str(pamh.get_user()) + "\n- Action: LogOut")
                os.remove(sessionFile)
        else:
            sendMessage("SSH Activity detected from: " + str(pamh.rhost) + "\n- Host: " + str(hostname) + "\n- User: " + str(pamh.get_user()) + "\n- Action: LogIn")
            file = open(sessionFile,"w")
            file.write('1')
            file.close

    return pamh.PAM_SUCCESS

def pam_sm_authenticate( pamh, flags, argv ):
    return 1

#def pam_sm_acct_mgmt( pamh, flags, argv ):
#        syslog.openlog(facility=syslog.LOG_AUTH)
#        syslog.syslog("-- AUTHPAM -- sm_acct_mgmt")
#
#def pam_sm_chauthtok( pamh, flags, argv ):
#        syslog.openlog(facility=syslog.LOG_AUTH)
#        syslog.syslog("-- AUTHPAM -- sm_chauthtok")
#
#def pam_sm_open_session( pamh, flags, argv ):
#        syslog.openlog(facility=syslog.LOG_AUTH)
#        syslog.syslog("-- AUTHPAM -- sm_open_session")
#
#def pam_sm_close_session( pamh, flags, argv ):
#        syslog.openlog(facility=syslog.LOG_AUTH)
#        syslog.syslog("-- AUTHPAM -- sm_close_session")

NOTE: Every time a login is made, the pam_sm_setcred function is executed twice, and once when a logout is made. Therefore, the script maintains some states based on files under /tmp/. The pam_sm_authenticate function is executed when the user does not exist, to avoid errors that there is no defined function, we make it return 1.

It may happen that a module can be loaded manually but not from PAM, this is because the path is different. First, we need to find out our path by running the following command inside a Python interpreter:

>>> import sys
>>> print sys.path
', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/home/kr0m/.local/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages/pip-9.0.1-py2.7.egg', '/usr/lib64/python2.7/site-packages/dnspython-1.16.0-py2.7.egg', '/usr/lib64/python2.7/site-packages/pystun-0.1.0-py2.7.egg', '/usr/lib64/python2.7/site-packages/gtk-2.0

In our PAM script, the first step is to comment out the import statement of the problematic module and find out the path. In my case, the requests module was not loading:

#import requests

syslog.openlog(facility=syslog.LOG_AUTH)
syslog.syslog("Python version: " + str(sys.version))
syslog.syslog("PATH: " + str(sys.path))

We compare the paths and add any missing ones to make the environment as similar as possible to the external one. After adding the paths, we should be able to load the module:

sys.path.append('/usr/local/lib/python2.7/dist-packages')
sys.path.append('/root/.local/lib/python2.7/site-packages')
sys.path.append('/usr/lib/python2.7/dist-packages')

import requests

We assign the necessary permissions:

chmod 600 /lib/security/looter.py

We restart the SSH service:

/etc/init.d/sshd restart

Now we will receive notifications on our Telegram every time there is a logIn/Out, indicating the source IP, the accessed host, and the user used.

If you liked the article, you can treat me to a RedBull here