Bloqueando ransomware con samba y fail2ban

Imagen de vfmBOFH

El método utilizado es simple, pero efectivo: Auditamos las acciones de los usuarios y las guardamos en log. Fail2ban se encarga de revisar el log, y si algún usuario ha escrito ficheros con el nombre/extensiones de la lista, lo bloquea. No es un método "instantáneo", ni tampoco protege para los ransom que usan extensiones aleatorias (o no usan extensiones), pero algo es algo. Empecemos por montar la auditoría:

En el smb.conf, para cada unidad que queramos auditar, aplicamos la siguiente configuración:

# Recurso de acceso R/W  publico
[publico]
        comment = Directorio compartido
        path = /ruta/al/share/publico
        vfs objects = full_audit
        full_audit: failure = none
        full_audit: success = pwrite write rename
        full_audit: prefix = IP = %I | USER = %u  | MACHINE = %m | VOLUME = %S
        full_audit: facility = local7
        full_audit: priority = NOTICE
        valid users = @winusers
        read only = No
        create mask = 0664
        directory mask = 0775
        force group = winusers
        force directory mode = 0775
        wide links = Yes

En concreto y por orden, qué operaciones se van a registrar en caso de que fallen (failure), las que se registrarán en caso de realizarse correctamente (success, pwrite -subida-, write -escritura-, rename -renombrado-), La cadena que se escribirá en el log (prefix: detallamos la ip, el usuario, la máquina y el volumen), el “facility” (local7, /var/log/syslog) y su prioridad. El resto del snip, vemos que son configuraciones bastante normales de un share samba.

Bien. Con estas directivas de auditoría, y una vez reiniciado samba, cada vez que un usuario que tenga mapeada la unidad de red \\servidor\publico escriba, suba ficheros o renombre los mismos, dejará una traza en el log similar a ésta:

Apr 21 21:02:50 srv1 smbd[31353]: IP = 192.168.1.35 | USER = fulano | MACHINE = pote | VOLUME = publico|pwrite|ok|ruta/al/archivo/archivo.extension

Y ya tenemos la traza de log que fail2ban examinará.

Para ello, una vez instalado creamos un fichero de filtro en /etc/fail2ban/filter.d/. Llamémosle samba.conf:

[Definition]
failregex = smbd.*\:\ IP\ =\ \ \|.*\.0x0$
            smbd.*\:\ IP\ =\ \ \|.*\.1999$
            smbd.*\:\ IP\ =\ \ \|.*\.*obleep$
            smbd.*\:\ IP\ =\ \ \|.*\.LOL!$
            smbd.*\:\ IP\ =\ \ \|.*\.aaa$
            smbd.*\:\ IP\ =\ \ \|.*\.abc$
            smbd.*\:\ IP\ =\ \ \|.*\.bleep$
            smbd.*\:\ IP\ =\ \ \|.*\.ccc$
[...]
ignoreregex =

Esto es un fragmento recortado, pero se deja entender bastante. Básicamente es una compilación de extensiones conocidas de archivos cifrados por los ransom más populares.

Bueno, hora de añadir nuestro filter al final de /etc/fail2ban/jail.conf:

[samba]
filter = samba
enabled = true
action = iptables-multiport[name=samba, port="135,139,445,137,138", protocol=tcp]
         mail[name=samba, dest=vfmbofh@mi.correo.no.te.dire]
logpath = /var/log/syslog
maxretry = 1
findtime = 600
bantime = 86400

Baneamos 24 horas al primer intento, y enviamos un correo avisando del tema (que no hará falta, porque el infeliz que esté infectado vendrá a darte la brasa porque no puede escribir en el share). El findtime, lo dejamos cuadrado con el que haya por default en la instalación.

Bueno. Hasta aquí la fusilada de mi blog.

Como puede verse, no es muy complicado de implementar, pero es un maldito peñazo mantener actualizada la lista de extensiones a vigilar. Así que husmeando por ahí, me he encontrado con esta web, que mantiene una base de datos de extensiones / nombres de archivo descargable libremente.

El tema es que la base de datos ésta, se baja en formato json, hay que parsearla y tal (yo uso jq, sed y tal).

Pero si tienes una base de datos consultable vía web puedes automatizar todo el mondongo.

Yo he montado un scriptillo bastante guarro que hace el trabajo. Lo pones en un cron para ejecutarse una vez al día y tira millas:

#!/bin/bash
#Licencia HLQTSDLH
#Definiciones estáticas. Cambiar en función de la anotación que hace samba en el log.
REGLAFICHERO='smbd.*\:\ IP\ =<HOST>\ \|'
REGLAEXTENSION='smbd.*\:\ IP\ =<HOST>\ \|.'
ULTIMALINEA="ignoreregex ="
############################################
ACTUAL=`date +"%Y%m%d"`
FICHERO=`curl --silent https://fsrm.experiant.ca/api/v1/combined |jq '.lastUpdated | {date}'|grep date |cut -d ' ' -f 4|sed 's/"//g'|sed 's/-//g'`
if [ $ACTUAL -gt $FICHERO ]
then
        logger "Comprobación de fichero de reglas samba f2ban ok."
        exit 0
else
        #al lío
        #recuperamos archivo de extensiones
        curl --silent https://fsrm.experiant.ca/api/v1/combined |jq '.filters'|sed 's/"//g'|sed 's/ //g'|sed 's/,//g'|sed 's/]//g'|sed "s/\[//g"|sed '/^\s*$/d' > /tmp/filters.tmp
        #generamos fichero de archivos
        cat /tmp/filters.tmp |grep -v ^* > /tmp/archivos.filter
        #generamos fichero de extensiones
        cat /tmp/filters.tmp |grep ^* > /tmp/extensiones.filter
        ####Reglas
#Hack primera línea del archivo
PRIMERALINEA=`head -n 1 /tmp/extensiones.filter|sed 's/\./\\\\./g'|sed 's/\\$/\\\\$/g'`
cat > /tmp/reglas.regla  <<EOF
[Definition]
failregex = $REGLAEXTENSION$PRIMERALINEA$
EOF
#Fin hack
        #extensiones
        sed 1d /tmp/extensiones.filter | while read LINEA #primera línea fuera, ya la hemos montado
        do
                PARSELINEA=`echo $LINEA|sed 's/\./\\\\./g'|sed 's/\\$/\\\\$/g'`
                echo -e "$REGLAEXTENSION$PARSELINEA\$" >> /tmp/reglas.regla
        done
        #archivos
        while read LINEA
        do
                PARSELINEA=`echo $LINEA|sed 's/\./\\\\./g'|sed 's/\\$/\\\\$/g'`
                echo -e "$REGLAEXTENSION$REGLA$PARSELINEA\$" >> /tmp/reglas.regla
        done < /tmp/archivos.filter
        #fin de archivo
        echo $ULTIMALINEA >> /tmp/reglas.regla
fi
mv /tmp/reglas.regla /etc/fail2ban/filter.d/samba.conf
/etc/init.d/fail2ban restart >/dev/null 2>&1
logger "Fichero de reglas samba f2ban actualizado"

Como es habitual en mí, falta control de errores y mil puñetas más. Pero hace el trabajo.

:wq!