DDoS: Mitigando denegación de servicio con IPtables

Publicado por Diego Córdoba en

En esta oportunidad veremos algunos tips y técnicas para mitigar o reducir el efecto de los ataques de denegación de servicio distribuidos, o DDoS por sus siglas en inglés, utilizando el firewall iptables en un sistema GNU/Linux.

En la guía se analizarán algunos puntos importantes:

  • Utilizar las cadenas y tablas de iptables para bloquear ataques DDoS.
  • Tunear algunas configuraciones del kernel para mitigar los ataques DDoS.
  • Usar iptables para bloquear los ataques DDoS basados en TCP.
  • Usar iptables para bloquear los floods o inundación de paquetes SYN mediante SYNPROXY.
ddos denial-of-service hack hacking security iptables linux

Este artículo explica algunos métodos que pueden llegar a ser útiles para protección de ataques DDoS en un servidor/firewall, pero cabe aclarar que los ataques de denegación de servicio, y más los grandes, resultan casi imposible de mitigar, incluso para firewalls por hardware especializados. No obstante, con iptables se pueden hacer muchas cosas útiles!

El artículo está orientado a profesionales con conocimientos medios en GNU/Linux, por lo que no se ahondarán las bases de iptables. Sin embargo, si estás interesado en aprender, puedes apuntarte al curso de iptables que dictamos online desde @juncotic.

Sin entrar demasiado en detalles, iptables representa la utilidad de nivel de usuario para administrar y configurar el filtrado de paquetes del kernel Linux, y representa la herramienta por defecto de prácticamente cualquier distribución de este sistema operativo.

Si bien generalmente se usa para bloquear puertos o direcciones IP, también brinda una gran cantidad de opciones de configuración que permiten, entre otras cosas, bloquear, o al menos limitar los efectos de ataques de denegación de servicio y denegación de servicio distribuido.

Configuración del kernel

Antes que nada es importante traer algunas configuraciones del kernel Linux que permiten mejorar la performance y mitigar mejor los ataques de DDoS.

Casi todas las distros actuales, o mejor, desde el kernel Linux v3.12, iptables incorpora un módulo denominado SYNPROXY. SYNPROXY es un módulo de netfilter, en el núcleo Linux, y está optimizado para gestionar millones de paquetes por segundo utilizando toda la CPU disponible sin tener problemas de bloqueos de concurrencia entre conexiones.

En un futuro artículo hablaremos más detenidamente de SYNPROXY, sus características y funcionamiento.

Volviendo al objetivo del apartado, configuraciones del núcleo, aquí pondré algunas interesantes (fuente)

kernel.printk = 4 4 1 7 
kernel.panic = 10 
kernel.sysrq = 0 
kernel.shmmax = 4294967296 
kernel.shmall = 4194304 
kernel.core_uses_pid = 1 
kernel.msgmnb = 65536 
kernel.msgmax = 65536 
vm.swappiness = 20 
vm.dirty_ratio = 80 
vm.dirty_background_ratio = 5 
fs.file-max = 2097152 
net.core.netdev_max_backlog = 262144 
net.core.rmem_default = 31457280 
net.core.rmem_max = 67108864 
net.core.wmem_default = 31457280 
net.core.wmem_max = 67108864 
net.core.somaxconn = 65535 
net.core.optmem_max = 25165824 
net.ipv4.neigh.default.gc_thresh1 = 4096 
net.ipv4.neigh.default.gc_thresh2 = 8192 
net.ipv4.neigh.default.gc_thresh3 = 16384 
net.ipv4.neigh.default.gc_interval = 5 
net.ipv4.neigh.default.gc_stale_time = 120 
net.netfilter.nf_conntrack_max = 10000000 
net.netfilter.nf_conntrack_tcp_loose = 0 
net.netfilter.nf_conntrack_tcp_timeout_established = 1800 
net.netfilter.nf_conntrack_tcp_timeout_close = 10 
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10 
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 20 
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 20 
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 20 
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 20 
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 10 
net.ipv4.tcp_slow_start_after_idle = 0 
net.ipv4.ip_local_port_range = 1024 65000 
net.ipv4.ip_no_pmtu_disc = 1 
net.ipv4.route.flush = 1 
net.ipv4.route.max_size = 8048576 
net.ipv4.icmp_echo_ignore_broadcasts = 1 
net.ipv4.icmp_ignore_bogus_error_responses = 1 
net.ipv4.tcp_congestion_control = htcp 
net.ipv4.tcp_mem = 65536 131072 262144 
net.ipv4.udp_mem = 65536 131072 262144 
net.ipv4.tcp_rmem = 4096 87380 33554432 
net.ipv4.udp_rmem_min = 16384 
net.ipv4.tcp_wmem = 4096 87380 33554432 
net.ipv4.udp_wmem_min = 16384 
net.ipv4.tcp_max_tw_buckets = 1440000 
net.ipv4.tcp_tw_recycle = 0 
net.ipv4.tcp_tw_reuse = 1 
net.ipv4.tcp_max_orphans = 400000 
net.ipv4.tcp_window_scaling = 1 
net.ipv4.tcp_rfc1337 = 1 
net.ipv4.tcp_syncookies = 1 
net.ipv4.tcp_synack_retries = 1 
net.ipv4.tcp_syn_retries = 2 
net.ipv4.tcp_max_syn_backlog = 16384 
net.ipv4.tcp_timestamps = 1 
net.ipv4.tcp_sack = 1 
net.ipv4.tcp_fack = 1 
net.ipv4.tcp_ecn = 2 
net.ipv4.tcp_fin_timeout = 10 
net.ipv4.tcp_keepalive_time = 600 
net.ipv4.tcp_keepalive_intvl = 60 
net.ipv4.tcp_keepalive_probes = 10 
net.ipv4.tcp_no_metrics_save = 1 
net.ipv4.ip_forward = 0 
net.ipv4.conf.all.accept_redirects = 0 
net.ipv4.conf.all.send_redirects = 0 
net.ipv4.conf.all.accept_source_route = 0 
net.ipv4.conf.all.rp_filter = 1

Estas configuraciones tienden a maximizar el rendimiento del sistema bajo un ataque de DDoS, y mejora la efectividad de las reglas de iptables que establezcamos. En otro artículo específico explicaré más en detalle estas líneas.

Bloqueando ataques de DDoS con IPtables

Ahora veremos algunos ejemplos de reglas que nos pueden servir para bloquear o mitigar muchos de los ataques de DDoS.

Cabe aclarar que los tipos de ataques de DDoS son muchos, e intentar bloquearlos a todos ellos resulta casi imposible. Afortunadamente disponemos del módulo del kernel denominado nf_conntrack, que puede ayudar a mitigar muchos ataques basados en TCP que no usan paquetes con flag SYN.

Esto incluye los ataques de ACK o SYN-ACK y ataques basados en los flags falsos o erróneos de TCP.

Bloquear paquetes inválidos

Lo primero es bloquear todos los paquetes inválidos, es decir, aquellos que no sean paquetes SYN (de establecimiento de conexión) y que tampoco pertenezcan a ninguna conexión activa:

iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROP

Bloquear paquetes nuevos que no son SYN

Ahora a bloquear todos los paquetes que no pertenecen a ninguna conexión establecida, y además no usan el flag SYN. Similar a la anterior, pero captura algunos paquetes que no filtra la regla anterior:

iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP

Bloquear valores anoramales de MSS

Vamos a bloquear ahora paquetes nuevos, es decir, aquellos que contengan el flag SYN activado, pero que además tengan un valor de MSS (Maximum Segment Size) fuera de lo normal, ya que los paquetes SYN suelen ser pequeños, y paquetes SYN grandes podrían indicar inundación de SYN (SYN flood):

iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

Bloquear paquetes con flags erróneos

Ahora algunas reglas para filtrar paquetes con flags erróneos, aquellos flags o combinaciones de los mismos que un paquete normal no utilizaría.

iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,FIN FIN -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL ALL -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP 
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP

Bloquear paquetes de subredes privadas

Esto es importante para evitar el spoofing o inundación de tráfico por parte de atacantes. Estas reglas bloquean tráfico que proviene de direcciones IP’s privadas, ya que usualmente en la interfaz WAN no se recibe tráfico privado, sino aquel proveniente de direcciones IP’s públicas.

iptables -t mangle -A PREROUTING -s 224.0.0.0/3 -j DROP 
iptables -t mangle -A PREROUTING -s 169.254.0.0/16 -j DROP 
iptables -t mangle -A PREROUTING -s 172.16.0.0/12 -j DROP 
iptables -t mangle -A PREROUTING -s 192.0.2.0/24 -j DROP 
iptables -t mangle -A PREROUTING -s 192.168.0.0/16 -j DROP 
iptables -t mangle -A PREROUTING -s 10.0.0.0/8 -j DROP 
iptables -t mangle -A PREROUTING -s 0.0.0.0/8 -j DROP 
iptables -t mangle -A PREROUTING -s 240.0.0.0/5 -j DROP 
iptables -t mangle -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP

Se asume que el equipo utiliza como dirección de loopback una del rango 127.0.0.0/8.

Bloquear tráfico ICMP

Bloqueamos todo el tráfico ICMP entrante. Si bien algunos tipos de mensajes ICMP pueden llegar a ser útiles en caso de congestión de red o fragmentación, en general no suelen haber inconvenientes con bloquear todo el tráfico ICMP entrante con una regla similar a esta:

iptables -t mangle -A PREROUTING -p icmp -j DROP

Esta regla, además de bloquear el ping, también bloquea los paquetes de inundación icmp, icmp de fragmentación, y por supuesto, el ping flood, o «Ping de la muerte» (Ping of Death).

Bloquear tráfico por cantidad de conexiones

Otra regla interesante es la que permite bloquear a equipos que superan un umbral determinado de cantidad de conexiones establecidas. Por ejemplo, si un host en Internet establece 85 conexiones contra el puerto 80 de nuestro servidor web, seguramente sea un tipo de ataque, y podemos bloquearlo con algo como esto:

iptables -A INPUT -p tcp -m connlimit --connlimit-above 85 -j REJECT --reject-with tcp-reset

Bloquear tráfico por cantidad de conexiones por unidad de tiempo

Otro punto importante es el de limitar la cantidad de conexiones por unidad de tiempo, y por ráfaga, desde una misma dirección IP. Esto es interesante ya que muchas veces un atacante intentará inundar de tráfico nuestros servidores intentando establecer muchas conexiones. Así, por ejemplo, si quisiéramos limitar a que una máquina remota pueda establecer como máximo 50 conexiones por segundo, con una ráfaga de 18 conexiones entre segundos, podríamos crear dos reglas en este orden:

iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m limit --limit 50/s --limit-burst 18 -j ACCEPT 
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j DROP

Bloquear paquetes fragmentados

Adicionalmente, una buena técnica es la de bloquear también los paquetes fragmentados. Normalmente no es necesario, pero a veces la inundación de paquetes UDP fragmentados pueden consumir mucho ancho de banda y producir una denegación de servicio. Para mitigar esto podemos descartar todo el tráfico fragmentado con algo así:

iptables -t mangle -A PREROUTING -f -j DROP

Bloquear tráfico TCP RST

Por otro lado, una buena idea puede ser limitar también los floods de paquetes taggeados con el flag de reset RST en TCP, aunque acá podría necesitarse un análisis más profundo:

iptables -A INPUT -p tcp --tcp-flags RST RST -m limit --limit 4/s --limit-burst 4 -j ACCEPT 
iptables -A INPUT -p tcp --tcp-flags RST RST -j DROP

Usando SYNPROXY para mitigar los SYN Floods

Como se mencionó arriba, SYNPROXY es un nuevo target de iptables desde la v3.12 del kernel Linux (iptables v1.4.21) en la mayoría de las distros.

Su objetivo principal es el de verificar si el equipo remoto terminó de establecer la conexión (handshake) de TCP luego de enviar el primer segmento SYN. Si luego de este primer segmento no hubo ningún otro envío, SYNPROXY descarta el mensaje.

Las reglas anteriores ya bloquean la mayoría de los ataques de DDoS basados en mensajes TCP, pero la inundación SYN es un poco más complicada de mitigar, y aquí es que entra en acción SYNPROXY.

Siempre, esto como aclaración, el rendimiento de iptables será mayor si pueden encontrarse reglas que permitan, mediante una selección de patrones, bloquear tráfico específico, sin embargo a veces esto es difícil de lograr sin una herramienta como SYNPROXY.

Veamos un ejemplo simple brevemente explicado… SYNPROXY da para un artículo entero (o más :P):

iptables -t raw -A PREROUTING -p tcp -m tcp --syn -j CT --notrack 
iptables -A INPUT -p tcp -m tcp -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460 
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

La primer regla permite configurar algunos parámetros asociados a conexiones. En este caso, desactiva el tracking de conexiones para los paquetes SYN que llegan al firewall. El target CT únicamente está disponible en la tabla raw.

La segunda regla matchea con todo el tráfico tcp cuyo estado de conexión es INVALID o UNTRACKED (como los paquetes SYN que pasan por la regla 1). Esta regla ejecuta el target SYNPROXY y le manda a SYNPROXY el paquete SYN del cliente. SYNPROXY intenta establecer el handshake respondiendo con el SYN+ACK al cliente. El cliente «legal» responderá con su ACK. Si esto ocurre, es decir, SYNPROXY verifica que el cliente intentó establecer una conexión legal, SYNPROXY establece el handshake contra el servidor real, y una vez resuelto, deja al cliente interactuando contra el server.

Estas reglas sirven para todos los puertos, pero pueden restringirse a puertos específicos con los parámetros de selección que ya conocemos.

En el caso de que SYNPROXY no pueda establecer la conexión, descarta el tráfico del cliente y el servidor real nunca recibe ni siquiera el mensaje SYN (espero se entienda eso… sí, ya estoy pensando en un nuevo artículo de SYNPROXY detallado :)).

Conclusiones

Para terminar, un par de reglas que pueden servir para mitigar los escaneos de puertos, y con ello, mejorar la seguridad en los servidores, aunque no tenga que ver específicamente con DDoS, quizás si un atacante no ve (o le resulta difícil ver) los puertos abiertos, va a tener que sortear un escollo más a la hora de establecer un ataque de DDoS.

iptables -N port-scan 
iptables -A port-scan -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 3 -j RETURN 
iptables -A port-scan -j DROP

Espero que resulte de interés! Y por supuesto, cualquier duda que tengan espero sus comentarios!

Como mencioné en el artículo, en un futuro escribiré extensiones de este post para hablar de algunos temas puntuales, como configuraciones del núcleo, y detalles del SYNPROXY.

Hasta la próxima!!


¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!


Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador