Esta pagina se ve mejor con JavaScript habilitado

Telegram SSH

 ·  🎃 kr0m

Ningún sistema es inexpugnable por lo tanto cuantas mas precauciones tomemos mas improbable será que acabemos owneados, en esta ocasión configuraremos un sistema de notificaciones vía Telegram que nos avisará cada vez que se realice un acceso a nuestro sistema vía ssh.

Primero realizamos una copia de la config PAM del servicio ssh:

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

Modificamos la config para que se ejecute nuestro script, añadimos en la primera línea:

vi /etc/pam.d/sshd

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

Ahora instalamos los módulos de PAM necesarios para correr nuestro script en python, a continuación se detalla como hacerlo en un sistema Debian/Gentoo:

apt install libpam-python python-pip

En Gentoo por alguna extraña razón no hay libpam-python, alienizamos el paquete de Debian y copiamos el módulo:

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

Instalamos dependencias del script en python:

pip install requests --user

Generamos un bot con botfather, obtendremos la apiKey.

Con userinfo sacamos en userId:
https://telegram.me/userinfobot

Escribimos nuestro 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")

NOTA: Cada vez que se hace login se ejecuta dos veces la función pam_sm_setcred y una vez cuando se hace logout, por eso el script mantiene unos estados basados en ficheros bajo /tmp/, la función pam_sm_authenticate se ejecuta cuando el usurio no existe, para evitar errores de que no hay un función definida hacemos que retorne 1.

Puede darse el caso en el que manualmente se pueda cargar un módulo pero desde PAM no, esto es debido a que el path es diferente, primero averiguamos cual es nuestro path, ejecutamos desde dentro de un interprete de python:

>>> 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

En nuestro script de PAM lo primero será comentar la importación del módulo problemático y averiguar el path, en mi caso no cargaba el módulo requests:

#import requests

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

Comparamos paths y añadimos los que falten para que el entorno sea lo mas parecido al del exterior, después de añadir los paths ya deberíamos de poder cargar el módulo:

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

Asignamos los permisos necesarios:

chmod 600 /lib/security/looter.py

Reiniciamos el servicio SSH:

/etc/init.d/sshd restart

Ahora recibiremos notificaciones en nuestro telegram cada vez que se haga logIn/Out indicándonos la ip origen, el host accedido y el user utilizado.

Si te ha gustado el artículo puedes invitarme a un RedBull aquí