iptables ddos configurar recent, impedir ataques denegación de servicio (DOS Denial Of Service) en Linux (Match extension recent )

Recientemente se ha puesto en contacto conmigo un compañero de fatigas llamado Miguel Angel (un saludo), a ver si le podía echar una mano con unos ataques que está teniendo. Evidentemente no usaré sus datos para nada en esta entrada.

En esta estrada vamos realizar un filtrado más preciso de las comunicaciones entrantes, para evitar ataques DOS.

En el anterior post «Impedir ataques denegación de servicio (DOS Denial Of Service) en Linux (Match extension limit)», se mostraba como realizar un filtrado limitando el número de accesos. La gran mejora de la extensión recent vs limit, es que recent mantiene una lista de IPs de origen de comunicación y los límites son establecidos por IP de origen. La extensión limit impone límites independientemente del origen, es un límite global.

Un ejemplo de filtrado para el puerto 22 sería:

Source   
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name puerto_22 --set -m comment --comment "Inicio filtrado 22 "
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name puerto_22 --update --seconds 3600 --hitcount 5 -j LOG --log-prefix "Ataque DDOS puerto 22 "
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name puerto_22 --update --seconds 3600 --hitcount 5 -j REJECT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m comment --comment "Fin filtrado 22 " -j ACCEPT

Lo que realizan estas lineas es:

1- Añade la IP (opción –set) a la lista «puerto_22», de una nueva comunicación. Si la ip existe la actualiza en la lista.

2- Actualiza la IP (opción –update) en la lista «puerto_22», fija un límite de 3600 segundos (opción –seconds 3600), con un número de hits permitidos de 5 (opción –hitcount 5) y finalmente escribe en el log (-j LOG) el intento de ataque. Esta linea no corta la comunicación entrante solo escribe en el log.

3- Esta linea es exactamente igual que la linea 2, pero modificando el target (-j REJECT). Aquí es donde se rechaza la comunicación si se supera el límite de 5 conexiones de 3600 segundos desde una misma IP.

4- Si la ejecución llega a esta linea es que no se ha superado el límite, por tanto aceptamos la comunicación entrante.

En resumidas cuentas este es un típico caso de filtrado bastante duro, 5 conexiones cada 3600 segundos desde una misma IP. Tratándose del puerto 22 es un buen límite, ya que los accesos administrativos son pocos y normalmente el administrador sabe lo que escribe y no se equivoca en trivialidades como la contraseña o el usuario.

Los límites hay que fijarlos con cuidado, evidentemente dimensionarlos al número de peticiones reales que necesite el puerto (por ejemplo el 80). Además hay que tener cuidado porque es posible que tengamos diversos clientes accediendo a través de un NAT, a efectos prácticos todas estas comunicaciones se realizarán desde la misma IP.

Un script de uno de los servidores que administro:

Source   
#!/bin/bash
iptables -F
iptables -A INPUT -m state --state ESTABLISHED,RELATED -m comment --comment "Permitir conexiones existentes " -j ACCEPT
iptables -A INPUT -i lo -m comment --comment "Permitir conexiones internas " -j ACCEPT
iptables -A INPUT -p icmp -m comment --comment "Denegar ping " -j REJECT
iptables -A INPUT -m state --state NEW --source 62.64.12.40/32 -m comment --comment "Denegar esta IP externa" -j REJECT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW --source 192.168.0.0/28 -m comment --comment "Permitir segmento red puerto 22 " -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW --source 62.67.18.45/32 -m comment --comment "Permitir IP externa puerto 22 " -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name puerto_22 --set -m comment --comment "Inicio filtrado 22 "
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name puerto_22 --update --seconds 3600 --hitcount 5 -j LOG --log-prefix "Ataque DDOS puerto 22 "
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name puerto_22 --update --seconds 3600 --hitcount 5 -j REJECT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m comment --comment "Fin filtrado 22 " -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -m state --state NEW -m recent --name puerto_53 --set -m comment --comment "Inicio filtrado 53 "
iptables -A INPUT -p tcp --dport 53 -m state --state NEW -m recent --name puerto_53 --update --seconds 1 --hitcount 10 -j LOG --log-prefix "Ataque DDOS puerto 53 "
iptables -A INPUT -p tcp --dport 53 -m state --state NEW -m recent --name puerto_53 --update --seconds 1 --hitcount 10 -j REJECT
iptables -A INPUT -p tcp --dport 53 -m state --state NEW -m comment --comment "Fin filtrado 53 " -j ACCEPT
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --name puerto_53_udp --set -m comment --comment "Inicio filtrado 53 udp"
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --name puerto_53_udp --update --seconds 1 --hitcount 10 -j LOG --log-prefix "Ataque DDOS puerto 53 udp "
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m recent --name puerto_53_udp --update --seconds 1 --hitcount 10 -j REJECT
iptables -A INPUT -p udp --dport 53 -m state --state NEW -m comment --comment "Fin filtrado 53 udp" -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --name puerto_80 --set -m comment --comment "Inicio filtrado 80 "
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --name puerto_80 --update --seconds 60 --hitcount 30 -j LOG --log-prefix "Ataque DDOS puerto 80 "
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --name puerto_80 --update --seconds 60 --hitcount 30 -j REJECT
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m comment --comment "Fin filtrado 80 " -j ACCEPT
iptables -A INPUT -p tcp --dport 81 -m state --state NEW -m recent --name puerto_81 --set -m comment --comment "Inicio filtrado 81 "
iptables -A INPUT -p tcp --dport 81 -m state --state NEW -m recent --name puerto_81 --update --seconds 60 --hitcount 30 -j LOG --log-prefix "Ataque DDOS puerto 81 "
iptables -A INPUT -p tcp --dport 81 -m state --state NEW -m recent --name puerto_81 --update --seconds 60 --hitcount 30 -j REJECT
iptables -A INPUT -p tcp --dport 81 -m state --state NEW -m comment --comment "Fin filtrado 81 " -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --name puerto_443 --set -m comment --comment "Inicio filtrado 443 "
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --name puerto_443 --update --seconds 60 --hitcount 30 -j LOG --log-prefix "Ataque DDOS puerto 443 "
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --name puerto_443 --update --seconds 60 --hitcount 30 -j REJECT
iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m comment --comment "Fin filtrado 443 " -j ACCEPT
iptables -A OUTPUT -m comment --comment "Permitir conexiones salientes " -j ACCEPT
iptables -A FORWARD -m comment --comment "Permitir conexiones forward " -j ACCEPT

Una vez activadas las reglas dependiendo de la distribución de linux, el logado por defecto es en un fichero u otro:

  • Red Hat, CentOS, Fedora en /var/log/messages
  • Debian, Ubuntu en /var/log/kern.log

Si revisamos el log de forma frecuente, podemos conocer las IPs que nos están atacando y añadir una regla de rechazando la comunicación desde la IP específica con:

Source   
iptables -A INPUT -m state --state NEW --source 62.64.12.40/32 -m comment --comment "Denegar esta IP externa" -j REJECT

Una vez más es muy recomendable echar un vistazo a man iptables.

Miguel Angel por lo que he visto en vuestros sistemas tenéis un filtrado usando recent, pero solo para el puerto 80 y no se escribe en el log el intento de ataque.

Por este motivo no se podrá identificar la IP de origen y por lo tanto no podemos añadir una regla rechazando esta IP en primera instancia.

El filtrado se ha de realizar en todos los puertos abiertos y escribiendo información en log.

Espero que os sirva de ayuda.

Deja un comentario