17 junio 2014

Haciendo un honeypot con Portsentry y Fail2ban





Hace unos días me desplacé a Santa Cruz de Tenerife a un evento organizado por el CECOES 1-1-2 en el que dí una charla titulada “En el (ciber)-amor y en la (ciber)-guerra, todo vale”. Y precisamente este título me viene al pelo para expresar lo que quiero contaros en esta entrada.

Cuando se hace una auditoría desde fuera a un sistema, una de las primeras pruebas que se llevan a cabo, es un mapeo de los puertos, o de los servicios que esa “dirección IP” ofrece. En base a eso, se intenta identificar qué tipo de servicio hay asociado a cada puerto, así como la versión del mismo. Posteriormente, se suele tirar de biblioteca para buscar vulnerabilidades existentes en las versiones detectadas, e intentar explotarlas para descubrir información extra, volcar ficheros de sistema, ejecutar código remoto o incluso ganar acceso directo al sistema. Obviamente, cuantos menos servicios se estén ejecutando en un sistema, así como más protegidos, actualizados y mejor configurados se encuentren, mucho mejor. A esto también ayuda una rigurosa configuración de la política de firewall que protege la máquina, ya sea perimetral o local, únicamente a los servicios de tráfico necesarios, tanto entrante como saliente.  

Seguramente, muchos de vosotros conoceréis ya Portsentry. Se trata de una herramienta que monitoriza un interfaz de red, en una serie de puertos que configuremos, y cuando detecte una conexión (ya sea TCP o un paquete UDP a un puerto dado) devuelva al atacante que el puerto está abierto e incluso un banner que definamos. Además, permite llevar a cabo acciones posteriores con la IP atacante, que generalmente consiste en banearle el acceso al sistema de alguna de las siguientes maneras: Añadir una ruta nula al sistema, incluirla como regla de iptables al principio de la tabla filter para INPUT o bloquearla mediante TCPWrappers. 

En mi caso, y teniendo en cuenta que cualquier escaneo, incluso un "nmap -F” probará el puerto 23 TCP, es donde pongo el señuelo. Para que esto funcione, la política de IPtables de la máquina ha de permitir el tráfico al puerto “trampa”, aunque no haya servicio escuchando “bindeado” en dicho puerto.

Esta es la regla en Firewall Builder para permitir que el tráfico llegue a portsentry


Así, cualquier dirección IP que pruebe un único TCP SYN al puerto 23 contra mi IP pública, su tráfico posterior será bloqueado, mediante una regla iptables. 

El problema que tiene portsentry, es que es capaz de bloquear una dirección IP, pero no he encontrado forma de establecer un tiempo máximo de baneo, quedándose hasta que se vuelva a aplicar el fichero con la política de iptables, siendo la opción de añadir una tarea al cron de la máquina, algo poco limpio.

Así que teniendo en cuenta que también tengo instalado Fail2ban en el sistema, que sí que es capaz de establecer ese control, he querido integrar ambas cosas.

En el caso de portsentry, cuando bloquea una dirección IP, lo deja, por defecto, en el fichero /usr/loca/psionic/portsentry/portsentry.blocked.atcp (al arrancar portsentry para que fucnione con -atcp), dejando una línea como esta: 

1402854031 - 06/15/2014 19:40:31 Host: 14.146.31.13/14.146.31.13 Port: 23 TCP Blocked"

Desde Fail2ban he creado un filtro tan sencillo como este: 

failregex = \/<HOST>  Port\: 23 TCP Blocked

y luego en el fichero /etc/fail2ban/jail.conf, un bloque como este otro:

[portsentry]
enabled = true
filter = portsentry
logpath = /usr/local/psionic/portsentry/portsentry.blocked.atcp
action = iptables-allports
             sendmail-whois-lines[name=portsentry, logpath=/var/log/fail2ban.log]
bantime = 604800
findtime = 86400
maxretry = 1

Así con que sólo vea una entrada en el fichero de log de portsentry (de hecho no puede haber más de una), debería bloquearlo… Sin embargo, lamento deciros que esto NO funciona así. 

Me daba un error que no era capaz de detectar el tipo de datetime del evento. Por ello, he tenido que modificar el fichero "/usr/share/fail2ban/server/datedetector.py", añadiendo un template de fecha específico para los logs de Portsentry en la clase DateDetector

# Portsentry 06/15/2014 19:40:31
template = DateStrptime()
template.setName("Month/Day/Year:Hour:Minute:Second")
template.setRegex("\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}")
template.setPattern("%m/%d/%Y %H:%M:%S")
self.__templates.append(template)

Con esto, ha empezado a funcionar estupendamente, y tengo la tranquilidad de que Fail2ban gestionará el tiempo máximo que las direcciones IP permanecerán baneadas.


De estas y otras herramientas hablé en mi módulo, en el curso de "Attack y Hardening de Sistemas GNU/Linux" que dimos Yago, con la colaboración del gran Dabo, y un servidor, para Securízame

Aunque las sesiones online del mismo ya terminaron, aún puedes apuntarte a verlas grabadas desde WebEx, teniendo acceso a la plataforma de documentación y las sesiones hasta el 1 de Agosto de 2014. 

Por ello, si estás interesado, date de alta en el formulario y contactaremos contigo…