Renuncia de responsabilidad:
La versión original de este artículo fue publicada por IBM
developerWorks y es propiedad de Westtech Information Services. Este
documento es una versión actualizada del artículo original y contiene
mejoras introducidas por el Equipo de Documentación de Gentoo.
Este documento carece de soporte activo.
|
Cortafuegos dinámicos iptables
1.
Introducción
Seguridad de red flexible (y divertida)
La mejor forma de ver los beneficios de las macros de cortafuegos dinámicos es
verlas en acción. Para lograr esto, imaginemos que soy el administrador de un
proveedor de servicios de internet (ISP) y que he configurado un cortafuegos
Linux para proteger a mis clientes y a los sistemas internos de usuarios
maliciosos en internet. Para lograrlo, mi cortafuegos utiliza la completa
funcionalidad de iptables en el núcleo 2.4 para permitir que las conexiones de
salida sean establecidas por mis clientes y servidores y, por supuesto, para
permitir conexiones entrantes, pero solo para los servicios "públicos", como
web, ftp, ssh y SMTP. Dado que he usado un diseño de denegación por defecto,
cualquier conexión de internet a cualquier servicio que no sea público, como la
caché de proxy de squid o el servidor Samba, serán automáticamente rechazadas.
De hecho, tengo un cortafuegos muy decente que ofrece un buen nivel de
protección para cualquiera de nuestros clientes en la ISP.
Durante la primera semana o así, el cortafuegos funciona estupendamente, pero
entonces algo malo ocurre: Roberto, alguien que trabaja en un ISP de la
competencia, decide inundar mi red con paquetes en un intento por denegar el
servicio a mis clientes. Lamentablemente, Roberto ha estudiado cuidadosamente
mi cortafuegos y sabe que mientras que estoy protegiendo muchos servicios
internos, los puertos 25 y 80 deben estar públicamente accesibles, por lo que
puedo recibir correo y servir solicitudes HTTP. Roberto decide aprovecharse de
ello lanzando un ataque que consuma la mayor parte del ancho de banda contra mi
servidor web y de correo.
En aproximadamente un minuto o así Roberto comienza su ataque, noto que la
conexión al satélite comienza a verse saturada con paquetes. Después de echar
un vistazo a la situación con tcpdump determino que este es otro ataque
de Roberto, y averiguo las direcciones IP que está usando para ello. Ahora que
dispongo de esta información, lo único que necesito hacer es bloquear estas
direcciones IP, con ello se resolverá el problema -- una solución bastante
sencilla, según creo.
Responder a un ataque
Cargo inmediatamente la macro con la configuración de mi cortafuegos en vi y
comienzo a buscar una solución en mis reglas iptables, modificando mi
cortafuegos para que bloquee los paquetes entrantes que manda Roberto. Después
de un minuto o así, encuentro el lugar exacto para hacer la modificación
adecuada en la regla DROP y la añado. Entonces reinicio el cortafuegos, pero
cometí un pequeño error al crear las reglas. Cargo las macros del cortafuegos
de nuevo, resuelvo el problema y treinta segundos después el cortafuegos está
listo para bloquear el ataque del mes de Roberto. Al principio parece que he
frustrado el ataque... Hasta que los teléfonos de la compañía comienzan a
sonar. Aparentemente, Roberto ha sido capaz de inhabilitar mi red durante 10
minutos y ahora los clientes llaman para saber qué es lo que ha sucedido. Aún
peor, después de unos minutos noto que la conexión al satélite vuelve a estar
saturada de nuevo. Parece que Roberto está usando un nuevo conjunto de
direcciones IP para sus ataques. En respuesta, comienzo a revisar las macros
del cortafuegos, excepto que en esta ocasión estoy un poco asustado -- después
de todo, puede que mi solución no sea tan buena.
Esto es lo que fue mal en la sitación anterior. A pesar de que tengo un
cortafuegos decente en el lugar y de que identifiqué rápidamente la causa del
problema en la red, no fui capaz de modificar el funcionamiento de mi
cortafuegos para responder al problema a tiempo. Por supuesto, cuando atacan
nuestra red, querríamos responder inmediatamente y vernos forzados a alterar la
configuración del archivo de comandos de nuestro cortafuegos atemorizados, no
solo incrementará nuestro estrés, sino que además será muy poco eficaz.
2.
Macros
ipdrop
Sería mucho mejor si tuviera una macro especial ipdrop que está diseñada
con el propósito específico de insertar las reglas necesarias para bloquear las
direcciones IP que se le especifiquen. Con dicha macro, bloquear con un
cortafuegos no volverá a requerir dos minutos; le tomará cinco segundos como
mucho. Dado que la macro me evita la tarea de editar las reglas del cortafuegos
a mano, elimina la mayor fuente de problemas. Todo lo que me queda por hacer es
determinar la dirección IP que debería bloquear y teclear después:
Listado de Código 2.1: Ignorar una IP |
# ipdrop 129.24.8.1 on
IP 129.24.8.1 drop on.
|
La macro ipdrop bloqueará inmediatamente 129.24.8.1, la dirección IP mala de
Roberto por esta semana. Esta macro mejora nuestras defensas sustancialmente,
dado que bloquear ahora una IP ni tan siquiera requiere pensar. Veamos ahora la
implementación de mi macro ipdrop:
Listado de Código 2.2: macro ipdrop |
#!/bin/bash
source /usr/local/share/.sh
args 2 $# "${0} IPADDR {on/off}"
if [ "$2" == "on" ]
then
APPEND="-A"
INSERT="-I"
rec_check ipdrop $1 "$1 already blocked" on
record ipdrop $1
elif [ "$2" == "off" ]
then
APPEND="-D"
INSERT="-D"
rec_check ipdrop $1 "$1 not currently blocked" off
unrecord ipdrop $1
else
echo "Error: \"off\" or \"on\" expected as second argument"
exit 1
fi
iptables $INSERT INPUT -s $1 -j DROP
iptables $INSERT OUTPUT -d $1 -j DROP
iptables $INSERT FORWARD -d $1 -j DROP
iptables $INSERT FORWARD -s $1 -j DROP
echo "IP ${1} drop ${2}."
|
ipdrop: explicación
Si echamos un vistazo a las cuatro últimas líneas resaltadas, veremos los
comandos que insertan las reglas apropiadas en las tablas del cortafuegos. Como
puede verse la definición de la variable de entorno $INSERT varía, dependiendo
de si lo ejecutamos en el modo "on" u "off". Cuando se ejecuten las líneas de
iptables, las reglas correspondientes se insertarán o se eliminarán
adecuadamente.
Ahora, veamos la función de las reglas, que deberían funcionar a la perfección
con cualquier tipo de cortafuegos, e incluso en un sistema sin cortafuegos;
todo lo que se necesita es el soporte iptables integrado en nuestro núcleo 2.4.
Bloqueamos los paquetes entrantes desde la dirección IP que causa los problemas
(la primera línea iptables), bloqueamos los paquetes salientes a dicha
dirección IP (la siguiente línea iptables) y después evitamos las redirecciones
en cada dirección para dicha IP (las últimas dos líneas iptables). Una vez se
apliquen dichas reglas, nuestro sistema descartará cualquier paquete
proveniente que caiga en una de esas categorías.
Otro apunte rápido: hacemos llamadas a "rec_check", "unrecord", "record", y
"args". Son funciones de ayuda especiales en bash definidas en dynfw.sh
. La función "record" graba la ip bloqueada en el archivo
/root/.dynfw-ipdrop, mientras que "unrecord" lo elimina de
/root/.dynfw-ipdrop. La función "rec_check" se usa para abortar la
macro con un mensaje de error si se intenta bloquear de nuevo una dirección IP
ya bloqueada, o quitar el bloqueo a una dirección IP que no está bloqueada. La
función "args" se asegura de que recibimos la cifra correcta de argumentos y
también muestra una información de gran ayuda. He creado el archivo
dynfw-1.0.tar.gz que contiene todas estas herramientas; ver la sección de
Recursos al final de este artículo para obtener más
información.
tcplimit
La siguiente macro de cortafuegos dinámica es útil si se necesita limitar el
uso de un servicio de red basado en TCP, algo que posiblemente sobrecargue la
CPU en el servidor. Se llama "tcplimit", esta macro coge un puerto TCP, una
tasa, una escala y "on" u "off" como argumento:
Listado de Código 2.3: Limitar el uso de un servicio particular basado en TCP |
# tcplimit 873 5 minute on
Port 873 new connection limit (5/minute, burst=5) on.
|
tcplimit usa el nuevo módulo de iptables "state" (hay que asegurarse de
haberlo habilitado en el núcleo o de haber cargado el módulo) para permitir
solo un cierto número de conexiones entrantes en un determinado periodo de
tiempo. En este ejemplo, el cortafuegos únicamente permitirá cinco conexiones
por minuto a mi servidor rsync (puerto 873) -- y es posible especificar el
número de conexiones que se deseen por segundo/minuto/hora o día, tal y como se
necesite.
tcplimit ofrece una buena forma de limitar servicios que no sean
esenciales -- para que la inundación de tráfico en un servicio no esencial no
estropee nuestra red o el servidor. En mi caso, uso tcplimit para
establecer el límite superior de uso de rsync para prevenir que mi línea DSL se
vea saturada por excesivas conexiones rsync. Los servicios cuya conexión se ha
visto limitada se almacenan en /root/.dynfw-tcplimit y si alguna
vez quiero inhabilitar el nuevo límite de conexiones, sencillamente puedo
teclear:
Listado de Código 2.4: Inhabilitar la limitación de conexiones |
# tcplimit 873 5 minute off
Port 873 new connection limit off.
|
tcplimit funciona creando una cadena completamente nueva en la tabla
"filter". Esta nueva cadena rechazará todos los paquetes que excedan el límite
especificado. Entonces, se inserta una única regla en la cadena de entrada
(INPUT) que redirige todos los paquetes de conexión nuevos (NEW) dirigidos al
puerto de destino (873 en este caso) a esta cadena especial, limitando
efectivamente las nuevas conexiones de entrada, sin afectar a los paquetes que
forman parte de una conexión ya establecida.
Cuando tcplimit deja de funcionar, la regla INPUT y la cadena especial
son eliminadas. Este es el tipo de cosas que realmente hacen considerar la
importancia de tener una macro que maneje, después de haberla comprobado
concienzudamente, las reglas de nuestro cortafuegos por nosotros. Así como con
ipblock, la macro tcplimit debe ser compatible con cualquier tipo
de cortafuegos, e incluso con ningún cortafuegos, siempre que se tenga la
funcionalidad necesaria de iptables habiltada en el núcleo.
host-tcplimit
host-tcplimit es muy parecido a tcplimit, pero limita las nuevas
conexiones IP provenientes de una dirección IP concreta dirigidas a un puerto
TCP en concreto de nuestro servidor. host-tcplimit es muy útil para
limitar el abuso de una única persona de los recursos de nuestra red. Por
ejemplo, digamos que tenemos un servidor CVS y descubrimos que un nuevo
desarrollador parece estar usando una macro que actualiza su código fuente con
respecto al repositorio cada 10 minutos, usando una gran cantidad de recursos
de la red innecesariamente a lo largo del día. De todas formas, mientras
intentamos redactar un mensaje explicándole lo erróneo de su forma de proceder,
recibimos el siguiente mensaje:
Listado de Código 2.5: Mensaje recibido |
¡Hola chicos!
Me alegra formar parte de vuestro proyecto en desarrollo. He configurado una
macro para que actualice mi copia local del código cada diez minutos. Voy a
estar fuera durante dos semanas porque me marcho de viaje, pero cuando vuelva
tendré todo el código fuente actualizado y ¡estaré listo para ayudar! Salgo por
la puerta en este preciso instante... ¡Nos vemos en dos semanas!
Sinceramente,
Sr. Novato
|
En dichas situaciones, un sencillo comando host-tcplimit resolverá el
problema:
Listado de Código 2.6: Comando host-tcplimit |
# host-tcplimit 1.1.1.1 2401 1 day on
|
Ahora, el Sr. Novato (dirección IP 1.1.1.1) ha sido limitado a una conexión CVS
por día (puerto 2401), evitando el desperdicio de un gran ancho de banda en la
red.
user-outblock
La última y posiblemente la más intrigante de todas mis macros de cortafuegos
dinámicas es user-outblock. Esta macro proporciona una forma ideal de
permitir a un usuario en particular hacer telnet o ssh en nuestro sistema, pero
sin permitir a este usuario realizar ninguna nueva conexión saliente desde la
línea de comandos. He aquí una situación en la que user-outblock
resultaría muy práctico. Digamos que una familia en concreto tiene una cuenta
en mi ISP. Mamá y papá usan un cliente gráfico de correo electrónico para leer
su correo y para navegar por la red de vez en cuando, pero su hijo aspira a ser
un genio de la informática, y usa generalmente su acceso al intérprete de
comandos para hacer cosas malas en las computadoras de otras personas.
Un día, nos topamos con que ha establecido conexiones ssh con varios sistemas
que aparentemente pertenecen al ejército pakistaní -- oh. Nos gustaría emplear
a este joven en actividades más benéficas, por lo que hacemos lo siguiente:
Primero, hacemos una revisión de nuestro sistema y nos aseguramos de quitar el
bit suid de todos los binarios de red, como ssh:
Listado de Código 2.7: Eliminar el bit suid de todos los binarios de red |
# chmod u-s /usr/bin/ssh
|
Ahora, todos los procesos que intente usar para interactuar con la red tendrán
como propietario su UID. Ahora podremos usar user-outblock para bloquear todo
el tráfico de salida TCP iniciado por dicho UID (que además es el 2049):
Listado de Código 2.8: Bloquear todas las conexiones de salida TCP de un UID |
# user-outblock 2049 on
UID 2049 block on.
|
Ahora, puede ingresar y leer su correo, pero no podrá usar nuestro servidor
para establecer conexiones ssh ni cosas similares. Ahora podría instalar un
cliente ssh en su PC doméstico. De todos modos, no sería demasiado complicado
elaborar otra macro de cortafuegos dinámico que limitase su PC doméstico a la
web, correo y las conexiones salientes ssh (en nuestro servidor únicamente).
3.
Recursos
Tarballs
Dado que he encontrado estas macros dinámicas de cortafuegos muy útiles, las he
incluido todas en un pequeño tarball (dynfw-1.0.1.tar.bz2)
que se puede descargar e instalar en nuestra máquina.
Para instalarlas, extraemos el tarball y ejecutamos la macro que se incluye
install.sh. Esta macro instalará una macro compartida bash en
/usr/local/share/dynfw.sh, e instalará todas las macros dinámicas del
cortafuegos en /usr/local/sbin. Si se desea tenerlos en
/usr/share y /usr/sbin en su lugar, sencillamente tecleamos
esto antes de ejecutar install.sh:
Listado de Código 3.1: Exportar la localización del directorio de instalación |
# export PREFIX=/usr
|
He añadido también la página en Gentoo Linux
macros dinámicas de cortafuegos (en inglés) que se puede visitar para
obtener la última versión del tarball. Me gustaría continuar mejorando y
añadiendo nuevas cosas a la colección, alcanzando la meta de hacer realidad un
recurso verdaderamente útil para todos los administradores de sistemas a lo
largo del mundo. Ahora que disponemos de iptables en el núcleo es el momento de
sacarle partido.
Si todo este material acerca del cortafuegos iptables es nuevo para nosotros,
recomiendo encarecidamente el
2.4
stateful firewall tutorial (es necesario registrarse), que contiene
instrucciones completas acerca de cómo elaborar nuestro cortafuegos con
seguimiento de estado basado en iptables.
tcpdump es una herramienta esencial
de bajo nivel para explorar los intercambios de paquetes y para verificar que
nuestro cortafuegos está funcionando correctamente. Si no disponemos de la
misma, hay que obtenerla. Si disponemos de la misma, hemos de empezar a usarla.
Si ya se está usando, ¡excelente! :)
Visitar la página del equipo netfilter
para encontrar muchos recursos excelentes, incluyendo el código fuente
de iptables,
y las excelentes guías no fiables
de Rusty (traducidas al español siguiendo el enlace). Incluyen una guía
de conceptos básicos de red, una de filtrado de paquetes, una acerca de NAT y
el netfilter hacking HOWTO (no dispone de traducción al español) para los
desarrolladores. También hay un PUF
netfilter disponible, así como algunas otras cosas.
Afortunadamente, hay muchos recursos de netfilter en línea; pero, de todos
modos, no hay que olvidar los más básicos. La página del manual de iptables
es muy detallada y es un ejemplo brillante de lo que cualquier página de manual
debería ser.
Tenemos el Advanced Linux Routing
and Traffic Control HOWTO. Disponible en español en formato PDF
Enrutamiento avanzado y control de
tráfico en Linux, que dispone de una sección que muestra cómo usar
iptables para marcar paquetes, para después usar la funcionalidad de Linux para
encaminar dichos paquetes basándose en estas marcas.
Hay una lista de
correo netfilter (iptables) disponible, así como una para los
desarrolladores
netfilter. Se puede acceder a sus archivos en esos mismos enlaces.
|