Esta pagina se ve mejor con JavaScript habilitado

Parseo accesos SSH mediante script Python

 ·  🎃 kr0m

Seguro que si sóis unos paranóicos como yo siempre os rondará por la cabeza la idea de que alguno de vuestros servidores pueda estar comprometido sin tan siquiera saberlo, en este artículo explicaré como programar un sencillo parseador de logs mediante Python, de este modo cuando se produzca un acceso SSH seremos informados vía Telegram.

Para mejorar la seguridad del servicio SSH primero denegaremos el acceso como root al servidor y deshabilitaremos el acceso por password:

vi /etc/ssh/sshd_config

PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes

Reiniciamos el servicio:

service sshd restart

Nuestro script de parseo necesitará algunas dependencias, instalamos Python y Pip:

pkg install python py38-pip

Instalamos las dependencias mediante Pip:

pip install requests

El parseador tendrá el siguiente código:

vi .scripts/sshAccess.py

#!/usr/local/bin/python
import time
import os
import re
import requests
import socket

print('')
print('---------------------------------')
print('| Auth Log Parser v0.1b by kr0m |')
print('---------------------------------')

def sendMessage(msg):
    apiKey = "API_KEY"
    userId = "USER_ID"
    data = {"chat_id":userId,"text":msg}
    url = "https://api.telegram.org/bot{}/sendMessage".format(apiKey)
    r = requests.post(url,json=data)

logfile = open("/var/log/auth.log","r")
logfile.seek(0, os.SEEK_END)
while True:
    logline = logfile.readline()
    if not logline:
        time.sleep(0.1)
        continue
    else:
        #print('- LogLine: %s' % logline)
        m = re.search(".*Accepted (.*) for (.*) from (.*) port.*", logline)
        if m:
            print('>> SSH LogIN -> User: %s - IP: %s - AuthType: %s' % (m.group(2), m.group(3), m.group(1)))
            hostname = socket.gethostname()
            message = 'SSH LogIN: '+hostname+'\n User: '+m.group(2)+'\n IP: '+m.group(3)+'\n AuthType: '+m.group(1)
            sendMessage(message)
            continue

        m = re.search(".*Disconnected from user (.*) (.*) port.*", logline)
        if m:
            print('>> SSH LogOut -> User: %s - IP: %s' % (m.group(1), m.group(2)))
            hostname = socket.gethostname()
            message = 'SSH LogOut: '+hostname+'\n User: '+m.group(1)+'\n IP: '+m.group(2)
            sendMessage(message)
            continue

Asignamos los permisos necesarios:

chmod 700 .scripts/sshAccess.py

Demonizamos el script mediante un script de RC:

vi /usr/local/etc/rc.d/sshAccess

#! /bin/sh
#
# $FreeBSD$
#

# PROVIDE: sshAccess
# REQUIRE: DAEMON
# KEYWORD: shutdown 

. /etc/rc.subr

name="sshAccess"
rcvar="${name}_enable"
extra_commands="status"

start_cmd="${name}_start"
stop_cmd="${name}_stop"
status_cmd="${name}_status"

sshAccess_start(){
    echo "Starting service: ${name}"
    /usr/sbin/daemon -S -p /var/run/${name}.pid -T sshAccess -u root /root/.scripts/sshAccess.py
}

sshAccess_stop(){
    if [ -f /var/run/${name}.pid ]; then
        echo "Stopping service: ${name}"
        kill -s INT $(cat /var/run/${name}.pid)
        sleep 3
    else
        echo "It appears ${name} is not running."
    fi
}

sshAccess_status(){
    if [ -f /var/run/${name}.pid ]; then
        echo "${name} running with PID: $(cat /var/run/${name}.pid)"
    else
        echo "It appears ${name} is not running."
    fi
}


load_rc_config ${name}
run_rc_command "$1"

Asignamos los permisos y propietario/grupo necesarios al script RC:

chmod 555 /usr/local/etc/rc.d/sshAccess
chown root:wheel /usr/local/etc/rc.d/sshAccess

Habilitamos el servicio y lo arrancamos:

sysrc sshAccess_enable="YES"
service sshAccess start

Cuando alguien acceda nuestro servidor recibiremos una notificación como esta:

Cuando haga logout también:

Si no hemos sido nosotros algo huele muy mal, seguramente nuestro servidor haya sido comprometido.

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