29 abril 2014

Cómo filtrar ataques DDoS WebHive

Para el que no lo sepa, un WebHive es una herramienta para coordinar ataques de tipo DDoS a través de la web. Su funcionamiento es realmente sencillo, simplemente cargas el código HTML en un sitio web, defines el objetivo a atacar, y haces que la gente navegue hacia el WebHive.

Una vez en la página, los visitantes comenzarán a lanzar un desproporcionado número de visitas hacia el sitio objeto del ataque. Cuanta más gente navegue a la web donde esté alojado el WebHive, más fuerte será el ataque DDoS.

Un WebHive tiene este aspecto:


El problema a la hora de gestionar este tipo de ataques es que, dada su naturaleza distribuida, es casi imposible filtrar por IP, además tampoco sería una buena estrategia ya que habría que poner numerosas reglas en el Firewall (una por cada IP atacante) que terminaría por dañar su desempeño.

La estrategia correcta es tratar de fijar un punto único común a todas las peticiones para aplicar un filtrado global. En este caso, sí que se puede identificar algo que nos sirva para ejecutar acciones de filtrado.

Lo primero que hay que hacer es activar el modo extendido de logs en nuestro servidor Apache, eso nos va a permitir obtener mucha más información de las conexiones. Para ello, en el fichero de configuración de Apache hemos de definir los logs así

CustomLog logs/access_log combined

que se corresponde a este tipo de logs:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

Vemos que de esa forma hacemos que en nuestro fichero access_log aparezca más información, entre otras cosas el Referer, que es lo que nos va a permitir filtrar

Una vez activado el log extendido, podemos ver la fisonomía de las peticiones de un ataque mediante WebHive con más detalle:


37.0.123.xx - - [28/Apr/2014:01:06:43 +0200] "OPTIONS / HTTP/1.1" 200 11692 "http://pruebahive.net76.net/hive.html" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"
37.0.123.xx - - [28/Apr/2014:01:06:43 +0200] "OPTIONS / HTTP/1.1" 200 11692 "http://pruebahive.net76.net/hive.html" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"
37.0.123.xx - - [28/Apr/2014:01:06:43 +0200] "OPTIONS / HTTP/1.1" 200 11692 "http://pruebahive.net76.net/hive.html" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"
37.0.123.xx - - [28/Apr/2014:01:06:43 +0200] "OPTIONS / HTTP/1.1" 200 11692 "http://pruebahive.net76.net/hive.html" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36"


Como se puede observar, todas llevan como referer 'http://pruebahive.net76.net/hive.html' con lo que ya tenemos un patrón para ejecutar el filtrado.

Para poder filtrar esas peticiones vamos a hacer uso de las capacidades extendidas de Iptables que permite, entre otras muchas cosas, filtrar por 'strings' con lo que, definiendo el puerto destino (80) y el patrón del referer, podemos quitarnos de golpe todas las peticiones que provengan de ese WebHive.

Para filtrar ejecutamos (como root):

# iptables -A INPUT -p tcp --dport 80 -m string --string "pruebahive.net76.net" --algo kmp -j LOG --log-ip-options --log-tcp-options --log-prefix "WebHive"


# iptables -A INPUT -p tcp --dport 80 -m string --string "pruebahive.net76.net" --algo kmp -j DROP


De esa forma, todas las peticiones que vengan de ese WebHive no impactarán en nuestro servidor web con lo que, ni consumirán 'sockets', ni recursos a nuestro servidor Apache (otra cosa es el impacto a nivel red del tráfico puro)

Si le damos un vistazo a nuestro /var/log/messages nos encontramos:


Apr 28 01:09:49 revproxy kernel: WebHiveIN=eth0 OUT= MAC=00:0c:29:9d:1a:19:8a:c9:5e:36:70:10:08:00 SRC=37.0.123.196 DST=192.168.21.11 LEN=500 TOS=0x00 PREC=0x00 TTL=46 ID=32019 DF PROTO=TCP SPT=45815 DPT=80 WINDOW=107 RES=0x00 ACK PSH URGP=0 OPT (0101080AF32986A0D2820C51) 


Apr 28 01:09:50 revproxy kernel: WebHiveIN=eth0 OUT= MAC=00:0c:29:9d:1a:19:8a:c9:5e:36:70:10:08:00 SRC=37.0.123.196 DST=192.168.21.11 LEN=486 TOS=0x00 PREC=0x00 TTL=46 ID=28012 DF PROTO=TCP SPT=45814 DPT=80 WINDOW=107 RES=0x00 ACK PSH URGP=0 OPT (0101080AF3298800D2820C41) 


Apr 28 01:09:50 revproxy kernel: WebHiveIN=eth0 OUT= MAC=00:0c:29:9d:1a:19:8a:c9:5e:36:70:10:08:00 SRC=37.0.123.196 DST=192.168.21.11 LEN=486 TOS=0x00 PREC=0x00 TTL=46 ID=11831 DF PROTO=TCP SPT=45816 DPT=80 WINDOW=107 RES=0x00 ACK PSH URGP=0 OPT (0101080AF3298940D2820C59) 

Podemos ver que, una vez hemos puesto las reglas de filtrado, es nuestro Iptables el que está tirando las conexiones y ya han dejado de aparecer en los logs de Apache.

5 comments :

masticover dijo...

Muy útil, gracias por compartirlo.


PD: ¿quién es el "contribuidor"? No aparece su nombre/nick

Redsadic dijo...

Buenas,


interesante el artículo.


El tema del Referer por eso se podrá hacer mientras los desarrolladores de webhive no actualicen el código, de forma bastante sencilla, para que los clientes no envíen el Referer.


Saludos!

Jask dijo...

Buenos días,

Tengo una pregunta al respecto. Lógicamente el servidor no se cargará al filtrar de esta manera pero la herramienta de IPtables no tendrá una carga más "grande" al estar gestionando esto y filtrando?

Gracias por el artículo :)

Alberto Carrasco dijo...

Según se mire:

- Si completamos la conexión, entonces se cargará una instancia de PHP que responderá a la petición (con la consiguiente carga en función del tipo de sitio web).
- Si rechazamos la conexión (la carga se lleva al firewall en este caso), no se completará la petición y no se iniciará la correspondiente instancia de PHP para responder a la misma.


Básicamente, "las gallinas que entran por las que salen", ya que en caso de no filtrar la carga se la lleva PHP y si filtramos la carga se la lleva Iptables.


Sin embargo, para mi es mejor el filtrado de Iptables: No tiramos ancho de banda de subida, ya que no respondemos a las peticiones ;).

Maravento dijo...

es correcto y drop se encarga de esto (y no reject) para bajar la carga del iptables