14 nov

IPtables bloqueos de ataques

Esta vez vamos hacer un post tirando más a bloc de notas (el segundo después del de los certificados, igual ya es la edad), ya que si hemos trabajado con iptables, las reglas que vamos a comentar están al orden del día.

Las explicaciones están basadas en una debian, la idea principal es añadir algunas reglas por defecto que nos permitan proteger nuestro sistemas ante algunos tipos de ataques, por ejemplo DDOS o Pings de la muerte!, no son la panacea, pero algo hacen.

Lo primero que voy hacer es intentar protegerme, para que en el caso que se nos vaya la mano (algo que suele pasar) con alguna regla, pues no nos quedemos sin acceso a la máquina, así en mi caso como estoy conectado por ssh,  lo que voy hacer es controlar que mi usuario este conectado y en el caso que se desconecte, pues borramos todas las reglas y santas pascuas. Seria algo tan sencillo como

#!/bin/bash
USUARIO=Nombre
who | grep ${USUARIO}

if [ $? -ne 0 ]; then
  echo "Stopping firewall and allowing everyone..."
  iptables -F
  iptables -X
  iptables -t nat -F
  iptables -t nat -X
  iptables -t mangle -F
  iptables -t mangle -X
  iptables -P INPUT ACCEPT
  iptables -P FORWARD ACCEPT
  iptables -P OUTPUT ACCEPT
exit 1
fi

Y lo podemos ejecutar cuando empecemos, por ejemplo con un while, tal que así.


while true ;do /bin/bash script.sh && sleep 10; done

Bueno pues ahora vamos a mirar las reglas que podemos ir poniendo y las vamos a ir explicando, así si se entiende pues cada cual puede utilizarlas como mejor le vaya.

Vamos a utilizar muy mucho -m recent, básicamente los que nos permite hacer es crear un fichero temporal donde vamos almacenar las ips que cumplan los patrones del ataque, de esta manera podremos comprobar el numero de veces que una ip esta intentando acceder a nuestro sistema. También vamos hacer uso del -N, pongamos, por ejemplo que queremos logar (que va a ser el caso) aquellas peticiones que cumplan nuestras reglas, en este caso tendremos que realizar dos reglas, la primera para logar y la segunda para hacer el DROP. Por ejemplo,

iptables -A INPUT -s 10.0.0.0/8 -j LOG --log-level 4 -log-prefix 'SourceDrop '
iptables -A INPUT -s 10.0.0.0/8 -j DROP

Esto si tenemos unas cuantas reglas en un rollo bastante grande, así que para mejorar lo que haremos es utilizar chains, como funcionan? pues muy fácil, creamos un chail tal que así

iptables -N LOGandDROP

Con la opcion -A lo que vamos hacer es añadir las reglas que queremos que tenga el chail.

iptables -A LOGandDROP -j LOG --log-level 6 --log-prefix 'IPDROP '
iptables -A LOGandDROP -j DROP

Y ahora si queremos volver a crear la regla de antes lo que haremos es

iptables -A INPUT -s 10.0.0.0/8 -j LOGandDROP

Nos ahorramos como el 50% de las reglas…. en este caso. Vamos al lío.

Control de los accesos al puerto 22, uno de los puertos que solemos tener abiertos es el 22 así que vamos a montar unas reglas para que en el caso que detectemos muchos accesos en un periodo de tiempo, pues los bloqueemos, esta va a ser bien bien la base de la mayoría de reglas. Vamos hacer un chain que se llame SSH, para ser originales

iptables -N SSH
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j SSH
iptables -A SSH -m recent --set --name SSH --rsource
iptables -A SSH -m recent --update --seconds 30 --hitcount 5 --name SSH --rsource -j LOG --log-prefix "Firewall SSH-Bruteforce: " --log-level 6
iptables -A SSH -m recent --update --seconds 30 --hitcount 5 --name SSH --rsource -j DROP

Donde

–name es el nombre de la “clase” que defines ,

–rsource que se mantenga en la lista utilizando la ip remota

–rcheck mirar si la ip esta en la lista

update si esta en la lista hace una actualización del timestamp

–seconds numero de segundos para rastrear la dirección

hitcount numero de peticiones que aceptamos en el numero de segundo que definimos.

En este ejemplo que tenemos? muy fácil tenemos primero la regla de INPUT donde le decimos que si se cumple lo que tiene que haces es ir al chai SSH, o sea que si la petición vienen al 22 aplicara las reglas de chai SSH, y que hacen estas reglas? Pues si la ip que hace la petición al puerto 22 no hizo mas de 5 hits en el tiempo en segundo que hemos dicho hará el accept, en caso contrario pues DROP que te crió!.

Esto lo podemos hacer para todos los puertos que nos interese o para rangos, grupos etc Ahora vamos a mirar de protegernos del scanner de puertos.

Aplicaremos las siguientes reglas y las explicamos.

Paquetes mal formados o vacíos

En la primera lo que estamos haciendo es decirle que todas las peticiones entrantes sin –tcp-flags(SYN, ACK, FIN, RST, URG, PSH) que haga más de 3 por minuto y con un pico máximo de 5 se envíen al log


iptables -A INPUT -p tcp --tcp-flags ALL NONE -m limit --limit 3/m --limit-burst 5 -j LOG --log-prefix "Firewall Scan Ports "

En la siguiente lo que hacemos es decirle que aquellas ip que estén en la blacklist que se bloqueen durante 60 segundos.


iptables -A INPUT -p tcp --tcp-flags ALL NONE -m recent --name blacklist_60 --set -m comment --comment "Drop/Blacklist ip Scan Ports" -j DROP

Mas cosas.

TCP-reset

Lo que sale en el gif que me encontré que lo explica muy bien. http://i29.tinypic.com/103ybo8.jpg


iptables -N tcp-reset
iptables -A tcp-reset -m limit --limit 3/second --limit-burst 8 -j LOG --log-prefix "Firewall tcp-reset " --log-level 6
iptables -A tcp-reset -p tcp -j REJECT --reject-with tcp-reset
iptables -A tcp-reset -j REJECT

ICMP- control

iptables -N ICMP
iptables -A ICMP -p icmp -m limit --limit 1/s --limit-burst 2 -j LOG --log-prefix "Firewall PING-DROP" --log-level 6
iptables -A ICMP -p icmp -m limit --limit 1/s --limit-burst 2 -j DROP

syn-flood –> Denial-of -service

iptables -N syn-flood
iptables -A syn-flood -m limit --limit 50/second --limit-burst 100 -j LOG --log-prefix "Firewall syn-flood "
iptables -A syn-flood -j DROP

Paquetes mal formados.


iptables -N PKT_FAKE
iptables -A PKT_FAKE -m state --state INVALID -j DROP
iptables -A PKT_FAKE -p tcp --dport 80 --tcp-flags ALL ACK,RST,SYN,FIN -j LOG --log-prefix "Firewall PKT_FAKE "
iptables -A PKT_FAKE -p tcp --dport 80 --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "Firewall PKT_FAKE "
iptables -A PKT_FAKE -p tcp --dport 80 --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "Firewall PKT_FAKE "
iptables -A PKT_FAKE -p tcp --dport 80 ! --syn -m state --state NEW -j LOG --log-prefix "Firewall PKT_FAKE "
iptables -A PKT_FAKE -f -j LOG --log-prefix "Firewall PKT_FAKE "
iptables -A PKT_FAKE -j RETURN

Drop lista de ips IANA


iptables -A INPUT -s 0.0.0.0/7 -j DROP
iptables -A INPUT -s 2.0.0.0/8 -j DROP
iptables -A INPUT -s 5.0.0.0/8 -j DROP
iptables -A INPUT -s 7.0.0.0/8 -j DROP
iptables -A INPUT -s 10.0.0.0/8 -j DROP
iptables -A INPUT -s 23.0.0.0/8 -j DROP
iptables -A INPUT -s 27.0.0.0/8 -j DROP
iptables -A INPUT -s 31.0.0.0/8 -j DROP
iptables -A INPUT -s 36.0.0.0/7 -j DROP
iptables -A INPUT -s 39.0.0.0/8 -j DROP
iptables -A INPUT -s 42.0.0.0/8 -j DROP
iptables -A INPUT -s 49.0.0.0/8 -j DROP
iptables -A INPUT -s 50.0.0.0/8 -j DROP
iptables -A INPUT -s 77.0.0.0/8 -j DROP
iptables -A INPUT -s 78.0.0.0/7 -j DROP
iptables -A INPUT -s 92.0.0.0/6 -j DROP
iptables -A INPUT -s 96.0.0.0/4 -j DROP
iptables -A INPUT -s 112.0.0.0/5 -j DROP
iptables -A INPUT -s 120.0.0.0/8 -j DROP
iptables -A INPUT -s 169.254.0.0/16 -j DROP
iptables -A INPUT -s 172.16.0.0/12 -j DROP
iptables -A INPUT -s 173.0.0.0/8 -j DROP
iptables -A INPUT -s 174.0.0.0/7 -j DROP
iptables -A INPUT -s 176.0.0.0/5 -j DROP
iptables -A INPUT -s 184.0.0.0/6 -j DROP
iptables -A INPUT -s 192.0.2.0/24 -j DROP
iptables -A INPUT -s 197.0.0.0/8 -j DROP
iptables -A INPUT -s 198.18.0.0/15 -j DROP
iptables -A INPUT -s 223.0.0.0/8 -j DROP
iptables -A INPUT -s 224.0.0.0/3 -j DROP

Como le hemos dicho que nos envie los problemas al log lo que deberemos hacer es montar que iptables envie el log a un fichero, como? pues por el rsyslog, asi que vamos al lio.

Vamos a crear las carpetas donde vamos a dejar los logs, en mi caso los tengo en mnt así que haremos


mkdir -p /mnt/log/firewall
touch /mnt/log/firewall/iptables.log
chmod 600 /mnt/log/firewall/iptables.log
chown root:adm //mnt/log/firewall/iptables.log

Lo normal es que se envien los logs a rsyslog y sea este el que debamos configurar para que escriba en el log, la configuracion del rsyslog la coge por defecto del directorio /etc/rsyslog.d/, ahí debermeos crear el fichero de configuracion para el firewall, tal que asi.


vi /etc/rsyslog.d/firewall.conf

 


:msg, startswith, "Firewall " -/mnt/usb/firewall/iptables.log
& ~

Vale ahora vamos a configurar el logrotate, para que vaya limpiando el log y no se nos haga infumable. creamos el fichero de configuracion en


vim /etc/logrotate.d/iptables.log

 


/mnt/usb/firewall/iptables.log
 {
 rotate 5
 daily
 size 10M
 dateext
 missingok
 create 600 root adm
 notifempty
 compress
 delaycompress
 postrotate
 invoke-rc.d rsyslog reload > /dev/null
 endscript
 }

Reinicimos el servicio


/etc/init.d/rsyslog restart

Ahora podemos comprobar que funciona, haciendo una peticion nc al puerto 22. Y parasa esto.

while true; do nc -vz -w3 IP 22 && sleep 2 ; done
Connection to ---------- 22 port [tcp/ssh] succeeded!
Connection to ---------- 22 port [tcp/ssh] succeeded!
Connection to ---------- 22 port [tcp/ssh] succeeded!
Connection to ---------- 22 port [tcp/ssh] succeeded!
nc: connect to ---------- port 22 (tcp) timed out: Operation now in progress
nc: connect to ---------- port 22 (tcp) timed out: Operation now in progress
nc: connect to ---------- port 22 (tcp) timed out: Operation now in progress
nc: connect to ---------- port 22 (tcp) timed out: Operation now in progress

Al cabo de 30 segundos sin recivir peticiones liberaremos la ip.

Resumen lista de reglas

iptables -N LOGandDROP
iptables -A LOGandDROP -j LOG --log-level 6 --log-prefix 'IPDROP '
iptables -A LOGandDROP -j DROP
iptables -N SSH
iptables -A INPUT -p tcp -m tcp --dport 22 -m state --state NEW -j SSH
iptables -A SSH -m recent --set --name SSH --rsource
iptables -A SSH -m recent --update --seconds 30 --hitcount 5 --name SSH --rsource -j LOG --log-prefix "Firewall SSH-Bruteforce: " --log-level 6
iptables -A SSH -m recent --update --seconds 30 --hitcount 5 --name SSH --rsource -j DROP
iptables -N HTTP
iptables -A INPUT -p tcp -m tcp --dport 80 -m state --state NEW -j HTTP
iptables -A HTTP -m recent --set --name HTTP --rsource
iptables -A HTTP -m recent --update --seconds 30 --hitcount 30 --name HTTP --rsource -j LOG --log-prefix "Firewall HTTP-Bruteforce: " --log-level 6
iptables -A HTTP -m recent --update --seconds 30 --hitcount 30 --name HTTP --rsource -j DROP
iptables -N HTTPS
iptables -A INPUT -p tcp -m tcp --dport 443 -m state --state NEW -j HTTPS
iptables -A HTTPS -m recent --set --name HTTPS --rsource
iptables -A HTTPS -m recent --update --seconds 30 --hitcount 30 --name HTTPS --rsource -j LOG --log-prefix "Firewall HTTPS-Bruteforce: " --log-level 6
iptables -A HTTPS -m recent --update --seconds 30 --hitcount 30 --name HTTPS --rsource -j DROP
iptables -N ICMP
iptables -A ICMP -p icmp -m limit --limit 1/s --limit-burst 2 -j LOG --log-prefix "Firewall PING-DROP" --log-level 6
iptables -A ICMP -p icmp -m limit --limit 1/s --limit-burst 2 -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL NONE -m limit --limit 3/m --limit-burst 5 -j LOG --log-prefix "Firewall Scan Ports "
iptables -A INPUT -p tcp --tcp-flags ALL NONE -m recent --name blacklist_60 --set -m comment --comment "Drop/Blacklist ip Scan Ports" -j DROP
iptables -N syn-flood
iptables -A syn-flood -m limit --limit 50/second --limit-burst 100 -j LOG--log-prefix "Firewall syn-flood "
iptables -A syn-flood -j DROP
iptables -N PKT_FAKE
iptables -A PKT_FAKE -m state --state INVALID -j DROP
iptables -A PKT_FAKE -p tcp --dport 80 --tcp-flags ALL ACK,RST,SYN,FIN -j LOG --log-prefix "Firewall PKT_FAKE_80 "
iptables -A PKT_FAKE -p tcp --dport 80 --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "Firewall PKT_FAKE_80 "
iptables -A PKT_FAKE -p tcp --dport 80 --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "Firewall PKT_FAKE_80 "
iptables -A PKT_FAKE -p tcp --dport 80 ! --syn -m state --state NEW -j LOG --log-prefix "Firewall PKT_FAKE_80 "
iptables -A PKT_FAKE -p tcp --dport 443 --tcp-flags ALL ACK,RST,SYN,FIN -j LOG --log-prefix "Firewall PKT_FAKE_443 "
iptables -A PKT_FAKE -p tcp --dport 443 --tcp-flags SYN,FIN SYN,FIN -j LOG --log-prefix "Firewall PKT_FAKE_443 "
iptables -A PKT_FAKE -p tcp --dport 443 --tcp-flags SYN,RST SYN,RST -j LOG --log-prefix "Firewall PKT_FAKE_443 "
iptables -A PKT_FAKE -p tcp --dport 443 ! --syn -m state --state NEW -j LOG --log-prefix "Firewall PKT_FAKE_443 "
iptables -A PKT_FAKE -f -j LOG --log-prefix "Firewall PKT_FAKE "
iptables -A PKT_FAKE -j RETURN
iptables -N tcp-reset
iptables -A tcp-reset -m limit --limit 3/second --limit-burst 8 -j LOG --log-prefix "Firewall tcp-reset " --log-level 6
iptables -A tcp-reset -p tcp -j REJECT --reject-with tcp-reset
iptables -A tcp-reset -j REJECT
iptables -A INPUT -s 0.0.0.0/7 -j DROP
iptables -A INPUT -s 2.0.0.0/8 -j DROP
iptables -A INPUT -s 5.0.0.0/8 -j DROP
iptables -A INPUT -s 7.0.0.0/8 -j DROP
iptables -A INPUT -s 10.0.0.0/8 -j DROP
iptables -A INPUT -s 23.0.0.0/8 -j DROP
iptables -A INPUT -s 27.0.0.0/8 -j DROP
iptables -A INPUT -s 31.0.0.0/8 -j DROP
iptables -A INPUT -s 36.0.0.0/7 -j DROP
iptables -A INPUT -s 39.0.0.0/8 -j DROP
iptables -A INPUT -s 42.0.0.0/8 -j DROP
iptables -A INPUT -s 49.0.0.0/8 -j DROP
iptables -A INPUT -s 50.0.0.0/8 -j DROP
iptables -A INPUT -s 77.0.0.0/8 -j DROP
iptables -A INPUT -s 78.0.0.0/7 -j DROP
iptables -A INPUT -s 92.0.0.0/6 -j DROP
iptables -A INPUT -s 96.0.0.0/4 -j DROP
iptables -A INPUT -s 112.0.0.0/5 -j DROP
iptables -A INPUT -s 120.0.0.0/8 -j DROP
iptables -A INPUT -s 169.254.0.0/16 -j DROP
iptables -A INPUT -s 172.16.0.0/12 -j DROP
iptables -A INPUT -s 173.0.0.0/8 -j DROP
iptables -A INPUT -s 174.0.0.0/7 -j DROP
iptables -A INPUT -s 176.0.0.0/5 -j DROP
iptables -A INPUT -s 184.0.0.0/6 -j DROP
iptables -A INPUT -s 192.0.2.0/24 -j DROP
iptables -A INPUT -s 197.0.0.0/8 -j DROP
iptables -A INPUT -s 198.18.0.0/15 -j DROP
iptables -A INPUT -s 223.0.0.0/8 -j DROP
iptables -A INPUT -s 224.0.0.0/3 -j DROP

Ahora para que siempre este disponible al reiniciar la maquina haremos.


#!/bin/bash
iptables-save > /etc/firewall.conf
echo "#!/bin/sh" > /etc/network/if-up.d/iptables
echo "iptables-restore < /etc/firewall.conf" >> /etc/network/if-up.d/iptables
chmod +x /etc/network/if-up.d/iptables

Ale a difrturalo!