Clicky

Cómo evitar y bloquear peticiones GET, anti w00tw00t con iptables

Bloquea a los "snifers" o escaners de vulnerabilidad en tu servidor Linux

Harto estaba ya, jaaaartiiiito que dirían en Andalucía, desde que hace un poco más de un mes solucioné un pequeño bug en una aplicación de Pligg que no permitía el registro de usuarios en la página.

Desde entonces no he parado de borrar post de robots spamers en la tabla "pligg_links", reescribiendo en la base de datos Mysql el correo electrónico del usuario inyectado por el programa malicioso y cambiando su contraseña, sin borrar el registro entero ni el nombre de usuario para que al menos con ese "user name" no enviase nuevos post. Menos mal que tengo por defecto puesto el Pligg para que los post no sean publicados inmediatamente (discard), sino mi amigo el bot de Google ya me habría puesto en la lista negra de sus webs atacantes y hubieráis visto el temido cartelito rojo que lanza Firefox.

NetSniffer

Para sortear y bloquear el acceso de estos programas spamers (los vendían según iforman aquí  por $189), he tomado dos medidas, la primera añadir al recapchca que ya tenía durante el último paso del registro de usuarios, otro módulo recapkcha al enviar un nuevo post, que en otro artículo explicaré como hacerlo para Pligg 9.5.5 y, la segunda, el tema de este artículo: bloquear con iptables las peticiones GET /w00tw00t de scaneo de cabeceras HTTP 1.1 que los bots malignos envían al servidor para encontrar vulnerabilidades al recatcha, que por cierto es un colador si no se tomán medidas que complementen su trabajo.

Me queda aún el tema de bloquear también los ataques spamers a los comentarios en los posts del Pligg, pero voy a esperar unos días a ver cómo responden estas dos medidas, o si ya, como he hecho, con ajustar a la baja los permisos para que comenten los usuarios es suficiente. Ya contaré, y si es preciso tomar alguna decisión para que no se incluyan URLs en los mencionados comentarios ya pondré otro artículo explicando como lo he hecho.

De cualquier forma la forma de trabajar estos scripts es sumamente peligrosa. Os pongo debajo dos capturas de pantalla, una de la base de datos Mysqul desde "PhpMyAdmin" de la tabla pligg_links, la otra tiene la misma información pero vista en el administrador de noticias de Pligg.

PhpMyAdmin con contenido spammer

En esta primera se pueden ver todavía las entradas de los spamers, que a propósito no he borrado para hacer el artículo, con los "Link_id" números 274, 275, 278, 279, 280, 283 y 284. Las números 232 y 241 son, respectivamente, de un usuario y otra mia. De estas dos últimas, una, la 232, tiene un regristro en "link_url" con el enlace de la URL que va la página de la noticia original que manda el usuario. La otra, la mia número 241, no tiene este enlace por que es un post "original" y no enlaza a ninguna página externa (es un interesante vídeo sobre el aprovechamiento de la energía de las mareas con molinos generadores gigantes, os recomiendo verlo).

Si observaís, las de los spamers también tienen todas una URL en el registro "link_url" pero... ¡¡ no tienen nada en el registro "link_title" !! Aquí el segundo recapcha puesto antes del submit (envíar) del post ya ha hecho su trabajo: ¡¡¡ Estas noticias no se publicarán porque les falta el título !!!, que siempre lleva un enlace.

 Adminstrador de noticias en Pligg

Lo podemos ver más claramente en esta imagen de arriba de una porción del Administrador de Noticias del Pligg. En la primera columna "Estatus", vemos las que están "discard", en espera de ser revisadas, incluyendo una mía que hice para comprobar el funcionamiento del recapkcha (entrada 241 en el visor PhpMyAdmin). Vemos que hay tres "nick" que corresponden a usuarios spamers: el amigo "acisyaarin", el colega "sorkue" y el no menos famoso revienta-post  "pseudobetween" (aquí el amigo se ha esmerado eligiendo el nombrecito). "danDDy77" es un usuario aprobado y respetado al que corresponde la entrada número 232. Pero también vemos que las Columnas "Título - Abre en nueva ventana" que se corresponden con los users spamers están en blanco. Son los registros sin contenido correspondientes a los "link_url" números 274, 275, 278, 279, 280, 283 y 284, que veíamos en la imagen del PhpMyAdmin.

Bueno, ya podemos dormir tranquilos, sabemos que con el doble recapkcha, uno en el registro de usuario y otro en el envío del post, son rechazas las noticias y no se publican, aunque tengas habilitado el sistema para que lo haga autómaticamente. Pero ... ¿Qué pasa con esas URLs que los bots spamers maliciosos han escrito en mi flamante base de datos? ¿Porqué voy a dejarles que consuman espacio y recursos en mi servidor? Además, que también ocupan mi tiempo y trabajo teniendo que borrar estas entradas de la base de dato. NO, no y no. Vamos a impedirsélo.

La forma de trabajar de estos scripts es escaneando palabras clave entre los contenidos de nuestras aplicaciones, en este caso, como en otros CMS (sistemas de gestión de contenidos), bien pueden haber buscado "Powered by Pligg" o los autores de la plantilla, o incluso la declararación de código libre GNU que suelen llevar las cabeceras, o al pie, los archivos de las plantillas o módulos, ejemplo:

// The source code packaged with this file is Free Software, Copyright (C) 2005 by
// Ricardo Galli <gallir at uib dot es>.
// It's licensed under the AFFERO GENERAL PUBLIC LICENSE unless stated otherwise.
// You can get copies of the licenses here:
//         http://www.affero.org/oagpl.html
// AFFERO GENERAL PUBLIC LICENSE is also included in the file called "COPYING".

Una forma de obstruirles el maléfico trabajo es eliminar estas alusiones a los nombres propios de los desarrolladores dentro de cada archivo. Pero alguien podría molestarse por esto, ya que aunque estas aplicaciones sean gratuítas los autores también tienen el orgullo personal de ver sus nombres en la "obra" por haber sido los creadores.

Otra es con diferentes módulos de seguridad instalados en nuestro servidor Apache corriendo sobre Linux. Hay muchos de ellos, podréis investigarlo, yo he encontrado un artículo excelente que utiliza el módulo "iptables", el Firewall de Linux, para configurar una defensa contra este tipo de ataques. También hay mucho escrito sobre la forma de trabajar de esta aplicación. Básicamente podemos decir que actúa como un portero de discoteca (nuestro servidor) con diferentes puertas (puertos), permitiendo pasar a la fiesta (nuestros contenidos) a quien le entrega la entrada auténtica, sin falsificar. Perdonad por la parrafada, vamos al grano.

Si miramos el access_log de apache (en el caso de mi servidor, un Gentoo Release 2 de OVH, la ruta es /home/log/httpd/access_log ó /var/log/httpd/access_log) veremos multitud de entradas que identifica este tipo de ataque "sniffer", así:

217.195.204.194 - - [04/Feb/2010:11:59:04 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
217.195.204.194 - - [04/Feb/2010:12:22:30 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
217.195.204.194 - - [04/Feb/2010:12:42:56 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
64.22.126.175 - - [04/Feb/2010:15:03:07 +0100] "GET /w00tw00t.at.ISC.SANS.test0:) HTTP/1.1" 400 334
64.22.126.175 - - [04/Feb/2010:18:30:52 +0100] "GET /w00tw00t.at.ISC.SANS.test0:) HTTP/1.1" 400 334
74.86.166.34 - - [04/Feb/2010:18:55:22 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
74.86.166.34 - - [04/Feb/2010:19:02:47 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
74.86.166.34 - - [04/Feb/2010:19:10:02 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
74.86.166.34 - - [04/Feb/2010:19:16:57 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
74.86.166.34 - - [04/Feb/2010:19:24:11 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
64.22.126.175 - - [04/Feb/2010:19:29:31 +0100] "GET /w00tw00t.at.ISC.SANS.test0:) HTTP/1.1" 400 334
74.86.166.34 - - [04/Feb/2010:19:31:15 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
217.195.204.194 - - [04/Feb/2010:19:32:19 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
217.195.204.194 - - [04/Feb/2010:19:49:55 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334
217.195.204.194 - - [04/Feb/2010:20:08:07 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334

Como vemos el servidor las rechaza con error 400 pero los log se han llenado de escritura.
Este es el script para filtrar estos bot snifers con iptables:

#!/bin/bash

# agregue las siguientes líneas al principio de las reglas de iptables

# Aceptar loopback
iptables -A INPUT -i lo -j ACCEPT

# Comprobando que la IP está en la lista negra de w00tlist
# Si la IP está en la lista se rechaza de inmediato y se actualiza la lista negra en 6 horas
iptables -A INPUT -p tcp -m recent --name w00tlist --update --seconds 21600 -j DROP

# Crear una cadena w00tchain que agregue la dirección IP a la Lista negra de w00tlist
# y se restablecerá la conexión (no se olvide del prámetro '-p tcp' necesario para el uso de '--reject-with tcp-reset')
iptables -N w00tchain
iptables -A w00tchain -m recent --set --name w00tlist -p tcp \ -j REJECT --reject-with tcp-reset

# Creamos nuestra cadena w00t:
iptables -N w00t

# redirigimos los paquetes TCP a nuestro canal:
iptables -A INPUT -p tcp -j w00t

################################################## ###
# Ponga aquí sus propias reglas de iptables:
# Aceptar conexiones establecidas, etc. un ejemplo en la primera línea:

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
...
...
...
...

################################################## ###

# Cadena w00t
# Buscar el primer SYN y crear la lista:
iptables -A w00t -m recent -p tcp --syn --dport 80 --set

# Buscar los paquetes SYN, ACK, y actualización de la lista:
iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK SYN,ACK --sport 80 --update

# Buscar el paquete ACK y actualización de la lista:
iptables -A w00t -m recent -p tcp --tcp-flags PSH,SYN,ACK ACK --dport 80 --update

# Busca la firma hexadecimal en el primer PSH+ACK.
# Si está presente, se redirije a la lista negra de w00tchain y
# se corta la conexión de la IP.
# Y se elimina de nuestra lista, que no queremos filtrar cualquier paquete adicional de la conexión
iptables -A w00t -m recent -p tcp --tcp-flags PSH,ACK PSH,ACK --dport 80 --remove \ -m string --to 80 --algo bm --hex-string '|485454502f312e310d0a0d0a|' -j w00tchain

Espere un par de horas para que nuestros "amigos" w00t DFind se vean rechazados, y, si los ha limpiado antes, normalmente no debería tener ningún rastro en los registros. Sin embargo, tendrá la alegría de ver el número de paquetes descartados, como en este ejemplo, escriba el comando:

iptables -L INPUT -nvx

Chain INPUT (policy ACCEPT 9544 packets, 527735 bytes)
    pkts      bytes target     prot opt in     out     source     destination

4366     208456 DROP       tcp  --  *      *       0.0.0.0/0  0.0.0.0/0    recent: UPDATE seconds: 21600 name: w00tlist side: source
32364445 9421412023 w00t       tcp  --  *      *       0.0.0.0/0  0.0.0.0/0

También se pueden ver cuántos paquetes w00t han sido rechazadas con el comando:

iptables -L w00t -nvx

Y también puede ver todas las direcciones IP (dependiendo de su sistema) en la lista negra con:

cat /proc/net/ipt_recent/w00tlist

Yo las veo en el mío así:

cat /proc/net/xt_recent/w00tlist

Es posible filtrar los otros puertos (SSH, etc), por ejemplo, para bloquear los intentos de desbordamiento de búfer (--hex-string '|90 90 90 90 90 90|'). Sin embargo, no traten de filtrar de forma sistemática cualquier tipo de patrón de cadena (por ejemplo: filtros antispam en el puerto SMTP!) Porque no sólo no es el principal objetivo de iptables, sino que también es posible y fácil para un atacante dividir los patrones en paquetes más pequeños y así evitar la detección.

Después de realizar estos pasos el único y último registro que tengo en el access_log de mi servidor de estos spammers es este:

217.195.204.194 - - [10/Feb/2010:23:55:51 +0100] "GET /w00tw00t.at.ISC.SANS.DFind:) HTTP/1.1" 400 334

¿Cómo deshacerse de (casi) todos los escáneres de HTTP?

Siempre en tus registros de Apache, te habrás dado cuenta muchos signos de vulnerabilidad con exploraciones en busca de defectos como PHP, awstats, etc. O peor aún, la investigación de vulnerabilidades de IIS mientras estás usando un servidor Linux. En lugar de crear cientos de reglas de mod_security, con la que hemos visto anteriormente tampoco se protege completamente a Apache pero es más probable que el tiempo de respuesta sea terriblemente lento, vamos a deshacernos de casi (subrayo "casi", porque hay excepciones) todos estos escáneres idiotas con una sola regla de iptables.

Vamos a ver cómo debe presentarse un HTTP 1/1. Si la dirección IP de su servidor es "110.220.110.220" y su dominio es "dominio.com, cuando un usuario solicita la página raíz de su sitio "/", su aplicación debe contener al menos dos líneas siguientes:

 GET / HTTP/1.1
 Host: dominio.com

Ahora, la misma consulta con un escáner de vulnerabilidad:

 GET / HTTP/1.1
 Host: 110.220.110.220

La diferencia radica en la acogida ":" (dos puntos). El usuario conoce el nombre de dominio, pero el escáner no lo sabe. Analiza las IPs, no los campos y por lo tanto es fácilmente detectable.

Así que simplemente puede bloquear estos escáneres con iptables rechazando todas las peticiones HTTP entrantes que utilizan su IP en lugar del nombre de dominio:

# iptables -I INPUT -d xxx.xxx.xxx.xxx -p tcp --dport 80 -m string --to 700 \ --algo bm --string 'Host: xxx.xxx.xxx.xxx' -j DROP

Usted tendrá que sustituir las dos xxx.xxx.xxx.xxx con la IP de su servidor. La filtración se hace aquí en los primeros 700 octetos (--to 700) debido a que otros campos y variables pueden estar entre las líneas "GET" y "Host:".

Espere un par de horas y ejecute el comanto #  iptables -L INPUT -nvx para ver el número de lectores que están atrapados en el servidor de seguridad sin haber tenido tiempo de contaminar sus registros. No olvidar, por supuesto, que usted tiene que perder su tiempo con el 'drop' 

Jesus_Caceres