Sie sind auf Seite 1von 8

iptables/netfilter

Vamos a aprender a utilizar la herramienta iptables. Iptables es una herramienta basada en


netfilter, que es el componente del núcleo de Linux encargado de interceptar y manipular
paquetes de red. Iptables nos permite filtrar paquetes, haciendo función de firewall, además de
traducir direcciones de red (NAT) y mantener registros de log.

Primeros pasos con iptables


Para empezar, vamos a aprender a usar iptables en un equipo cliente, configurando los paquetes
que recibimos y que enviamos a nuestra red. Más adelante, aprenderemos cómo filtrar los
paquetes que se reciben y reenvían dentro de un router.

Iptables se basa en tres tablas (literalmente chains, cadenas) que contienen reglas que nos
permiten filtrar el tráfico. Esas tablas son:

• INPUT (reglas de entrada): Filtran los paquetes que se reciben en nuestros interfaces de
red.
• FORWARD (reglas de reenvío): Filtran los paquetes que se reenvían de un interfaz de
red a otro.
• OUTPUT (reglas de salida): Filtran los paquetes que se van a enviar por nuestros
interfaces de red.

Estas tablas contienen reglas que, para cada paquete, se van comprobando en orden hasta que
una de ellas coincide con las características del paquete (IP, puerto, etc.) y se decide si el paquete
se acepta o se rechaza (funcionan de manera muy similar a las tablas de enrutamiento). Si no
coincide ninguna regla, se aplica la política por defecto de esa tabla.

Ordenes básicas
https://help.ubuntu.com/community/IptablesHowTo

Para empezar, iptables -h nos mostrará una lista con los parámetros que podemos usar.

Para ver la configuración actual de iptables, podemos usar varias opciones:

• iptables -L es la más usual y nos muestra una lista de las reglas que hay en cada
tabla en un formato fácil de interpretar para el usuario. Por ahora, las tres tablas
deberían estar vacías.
• iptables -L -v nos da un poco más de información acerca de las reglas.
• iptables -S nos da un listado de las reglas usando el formato de parámetros de
iptables. Por ahora aparecen únicamente las reglas que sirven para establecer la política
por defecto de cada tabla.

Políticas por defecto


Para modificar la política por defecto de una tabla usaremos iptables -P. Para cada una de
las tablas (y para las reglas) podemos seleccionar una de las siguientes políticas:
• ACCEPT: Se acepta el paquete.
• DROP: Se descarta el paquete.

Por defecto, todas las tablas usan la política ACCEPT, lo que significa que se aceptan todos los
paquetes que se reciben y que se envían por nuestros interfaces de red.

Para empezar, vamos a cambiar la política por defecto de la tabla OUTPUT a DROP. Con esto,
todos los paquetes que enviemos por cualquiera de nuestros interfaces de red serán
descartados por defecto. Como no tenemos ninguna regla en la tabla OUTPUT que indique lo
contrario, esto debería cortar completamente los paquetes enviados.

Empieza haciendo ping a cualquier equipo. Ahora cambia la política con la orden:

iptables -P OUTPUT DROP

Comprueba si puedes seguir haciendo ping. Si puedes, algo has hecho mal (y mira que es difícil
porque sólo has tenido que escribir una línea). Vuelve a cambiar la política por defecto a ACCEPT
y comprueba que vuelves a poder hacer ping normalmente.

De la misma forma, comprueba el funcionamiento de la política por defecto en la tabla INPUT.


Cámbiala a DROP y prueba a hacer ping hacia ese equipo. Vuelve a cambiarla a ACCEPT y
comprueba que ping vuelve a funcionar.

La tabla FORWARD la vamos a dejar tranquilita por ahora.

Dependiendo de las políticas por defecto, podemos usar configurar nuestro firewall de dos
formas:

• Usando ACCEPT por defecto y bloqueando determinados paquetes/servicios con reglas


individuales.
• Usando DROP por defecto y permitiendo determinados paquetes/servicios con reglas
individuales.

Dependiendo de la seguridad que necesitamos (y lo paranoicos que seamos) usaremos un


modelo u otro, aunque para un servidor que requiera una seguridad elevada lo más normal es
usar políticas DROP por defecto (al menos para la tabla INPUT).

Añadiendo reglas
Vamos a probar ahora a añadir reglas individuales. De esta forma podremos bloquear o permitir
el tráfico solamente para un determinado puerto, servicio, conjunto de IPs, etc.

Comprueba que todas las políticas por defecto están a ACCEPT e introduce la siguiente orden
para bloquear el tráfico saliente del servicio HTTP:

iptables -A OUTPUT -p tcp --dport http -j DROP

Le estamos diciendo a iptables que debe añadir una regla [-A] a la tabla OUTPUT para los
paquetes que usen el protocolo tcp [-p] y que tengan como puerto de destino [--dport] el puerto
80 (que es el puerto por defecto del protocolo HTTP) (evidentemente, también podemos poner
directamente 80). Si todos esos parámetros coinciden, se le aplicará a ese paquete la política
especificada con el parámetro [-j], en este caso descartar el paquete.

Comprueba que con esto estamos bloqueando las peticiones HTTP desde nuestro equipo hacia
el exterior. Un informático de pro usaría, por ejemplo, wget www.google.es, pero podéis usar
cualquier navegador de Internet. Comprueba que, sin embargo, cualquier otro servicio funciona,
por ejemplo haciendo ping www.google.es.

Échale un vistazo a las reglas con iptables -L y antes de continuar limpia (flush) la tabla
OUTPUT con el comando iptables -F OUTPUT. Comprueba que se ha limpiado.

A continuación, vamos a crear una regla para bloquear el tráfico de entrada. Si tienes apache
instalado y funcionando puedes probar con el puerto 80. Si no, comprueba si tienes funcionando
el servicio SSH (si no lo tienes, instálalo con apt-get). Usaremos un cliente de SSH
(probablemente Putty) desde otro equipo para comprobar si se están filtrando correctamente
los paquetes o no.

Añade una regla ahora a la tabla INPUT:

iptables -A INPUT -p tcp --dport ssh -j DROP

Comprueba que ahora no puedes conectarte al servicio SSH. Borra la regla individualmente con
el siguiente comando:

iptables -D INPUT 1

El parámetro [-D] nos permite borrar la regla indicada de la tabla correspondiente, en este caso
la regla número 1 de la tabla INPUT. Como siempre, comprueba con iptables -L que se ha
modificado correctamente (es la última vez que digo esto, ya sabéis que después de cada
comando debéis comprobar si todo va bien).

Usando la política por defecto DROP


Vamos a probar ahora la otra forma de hacer las cosas. Este método es mucho más seguro pero
ya veréis que divertido es configurarlo. Limpia todas las tablas y cambia la política por defecto
de todas ellas (la tabla FORWARD no la vamos a usar, pero cámbiala ya que estamos) a DROP.

Ahora, abre el tráfico saliente hacia el puerto 80 y comprueba que puedes usar wget para
descargarte la página de Google. ¿Problemas? Seguro que sí.

El primer problema es que si usáis el nombre de dominio (www.google.es) necesitaréis también


tener abierto el puerto correspondiente al servicio DNS. Luego hacemos esto. Por ahora, usad
directamente la IP de Google (os sale con el comando ping, por ejemplo).

¿Sigue sin funcionar? Por supuesto que sigue sin funcionar. ¿A alguien se le ocurre por qué?
Pues porque aunque podemos mandar el paquete con la petición HTTP no podemos recibir el
paquete de respuesta. Tendremos que añadir una regla a la tabla INPUT que nos permita recibir
paquetes cuyo puerto de origen sea el 80 [--sport].
Ahora vamos a abrir también el puerto DNS. Buscad en por ahí qué puerto usa y atentos al
protocolo de capa 4 (¿TCP? ¿UDP?). Una vez abierto correctamente, ya podréis descargaros
páginas web tranquilamente usando sus nombres de dominio.

Permitiendo conexiones ESTABLISHED


Un método ampliamente utilizado cuando usamos DROP como política estándar es aceptar las
conexiones ya establecidas. Esto nos evita tener que abrir específicamente los puertos de
respuesta de todas las conexiones y nos permite además usar servicios que asignen puertos
dinámicamente.

Vamos a probar esta configuración con nuestro comando wget. Limpiad todas las tablas y
aseguraos de que las políticas por defecto están a DROP. Empezaremos introduciendo dos reglas
de salida: para el DNS y para el HTTP. Con esto, como ya sabemos, no nos va a funcionar todavía
el asunto, ya que los paquetes de vuelta no van a llegar a su destino.

Ahora, introducid la siguiente regla en la tabla INPUT:

iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Con esto, estamos aceptando paquetes que pertenezcan a conexiones ya establecidas


(ESTABLISHED) o relacionadas con otra conexión (RELATED).

Comprobad que ahora sí funciona todo bien.

Vamos con lo siguiente: abrir el firewall para que podamos conectarnos con el protocolo FTP.
Limpiad las tablas para no confundiros con las reglas. Añadid la regla de conntrack para la tabla
INPUT y reglas para DNS y FTP (puerto 21) para la tabla OUTPUT.

Conectaros usando ftp ftp.mozilla.org (login: anonymous, contraseña: la que os de la


gana). ¿Todo correcto? Ahora probad a usar un simple comando ls para ver un listado de
archivos. Esto ya no funciona. ¿Por qué? El servidor FTP necesita abrir una conexión en el sentido
contrario para enviarnos los datos del listado de ficheros (usa conexiones distintas para el flujo
de control y los datos). En condiciones normales, podríamos abrir el puerto de datos (por defecto
ftp-data está en el puerto 20) para aceptar conexiones entrantes, pero FTP tiene una gran
tendencia a asignar dinámicamente puertos así que nos serviría para mucho.

Para esto, tenemos la regla que nos acepta conexiones RELATED. ¿Y por qué no funciona?
Porque además de permitir el tráfico de salida relacionado con las conexiones ya existentes, en
el caso del FTP también tenemos que permitir el tráfico de salida relacionado con conexiones ya
existentes (ya que salen datos por puertos distintos del 21). Aprovecho para enseñaros el
parámetro [-I] que nos permite insertar una regla en cualquier lugar de la lista (lo hacemos
porque estas reglas especiales se suelen poner al principio).

iptables -I OUTPUT 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Comprobad que ya podéis usar el comando ls dentro del ftp y se permiten todas las conexiones
necesarias correctamente.
Si todavía no funciona, es porque falta un módulo de iptables que le añade al módulo conntrack
la funcionalidad de detectar las conexiones FTP. En algunas distribuciones de Linux (incluidas
versiones anteriores de Debian) viene instalado por defecto, pero si no viene se puede instalar
con:

modprobe nf_conntrack_ftp

Es posible que aun con esto todavía no os funcione. Eso es porque en las últimas versiones de
Debian hay que especificar para qué paquetes queremos usar este módulo conntrack_ftp. Para
eso se usa una regla en una tabla especial de iptables que se llama raw (y que se escapa a lo que
vamos a dar en este tema). Así simplemente copiadla:

iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp

Esta regla lo único que hace es decirle a iptables que los paquetes con destino al puerto 21 los
tiene que marcar para que conntrack use el módulo de ftp. Ya debería funcionar el FTP sí o sí.

Aprovechad para activar las conexiones SSH entrantes. Ahora sólo nos hace falta la regla INPUT
ya que en OUTPUT tenemos permitidos los paquetes de vuelta.

Más opciones de filtrado


http://www.netfilter.org/documentation/HOWTO/packet-filtering-HOWTO-7.html

Vamos a ver el resto de opciones que tenemos para filtrar paquetes en nuestras reglas. Por
ahora sólo hemos filtrado por el protocolo de capa 4 del paquete (TCP o UDP) y por el puerto de
entrada o de salida (también capa 4). Aquí tenéis un resumen de los filtros que se pueden usar
en cada regla:

- [-p]: Protocolo del paquete. Si el protocolo que elegimos es TCP o UDP podremos indicar
a continuación el puerto de destino u origen con las opciones [--dport] y [--sport].
También podemos elegir ICMP.
- [-s]: Origen del paquete (source). Nos permite especificar la dirección IP de origen del
paquete. Podemos especificar las direcciones de cuatro formas distintas:
o Usando el nombre de dominio, como localhost o www.google.es.
Ej.: iptables -A INPUT -s www.google.es -j ACCEPT
o Usando la dirección IP.
Ej.: iptables -A INPUT -s 173.194.34.216 -j ACCEPT
o Usando la dirección IP y la máscara expresada como un número del 0 al 32.
Ej.: iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT
o Usando la dirección IP y la máscara expresada como cuatro octetos.
Ej.: iptables -A INPUT -s 192.168.1.0/255.255.255.0 -j ACCEPT
- [-d]: Destino del paquete. Mismas opciones que [-s].
- [-i]: Nos permite especificar el interfaz de entrada del paquete. Se puede usar en la tabla
INPUT para que la regla afecte solamente a los paquetes que nos llegan por un
determinado interfaz (como eth0, lo, etc.).
- [-o]: Nos permite especificar el interfaz de salida del paquete. Se puede usar en la tabla
OUTPUT para que la regla afecte solamente a los paquetes que se envían por un
determinado interfaz.
- [-m]: Nos permite usar extensiones para realizar filtros más complejos. Algunas de las
extensiones que podemos usar son:
o [-m mac]: Nos permite usar la opción [--mac-source] para especificar la MAC de
origen que queremos filtrar. Sólo se usa en la tabla INPUT.
o [-m limit]: Nos permite usar la opción [--limit] para controlar la cantidad de
paquetes que se filtran. La cantidad se especifica en paquetes/unidad de
tiempo. Por ejemplo -m limit --limit 5/s filtrará 5 paquetes por segundo.
o [-m owner]: Nos permite filtrar los paquetes generados localmente
dependiendo del proceso que lo está generando, especificado mediante su PID
[--pid-owner], el usuario que lanzó el proceso [--uid-owner] o el grupo al que
pertenece el usuario que lanzó el proceso [-gid-owner].
o [-m tcp] y [-m udp]: Nos permite especificar los puertos de entrada y de salida.
No es necesario usarlas explícitamente ya que son dos extensiones que se
activan automáticamente al usar [-p]. Si usáis [--sport] o [--dport] y después
sacáis un listado de las reglas con iptables -S, veréis la sintaxis completa.

Con cualquiera de estas opciones, podemos usar el operador negación [!] para indicar lo
contrario. Por ejemplo, si con:

iptables -A OUTPUT -d 192.168.1.1 -j ACCEPT

permitimos el envío de paquetes a la IP 192.168.1.1, con:

iptables -A OUTPUT ! -d 192.168.1.1 -j ACCEPT

permitimos el envío de paquetes a cualquier dirección que no sea la 192.168.1.1.

Registrando el tráfico mediante logs


Además de filtrar paquetes y decidir cuáles se permiten y cuáles se rechazan, iptables nos
permite guardar un registro de los paquetes que filtremos para realizar funciones de auditoría y
detección de amenazas.

Esto se consigue mediante una política extendida que podemos usar en nuestras regla además
de las ya conocidas ACCEPT y DROP. Algunas de las políticas extendidas son:

• REJECT: Tiene el mismo efecto que DROP, pero además envía un mensaje ICMP de
“puerto no conectable”. A veces nos interesará que suceda esto y otras no.
• LOG: Nos permite guardar un registro de los paquetes que concuerden con la regla. Con
la política LOG podemos usar los siguientes parámetros adicionales:
o [--log-level]: Nos permite elegir el nivel de registro de syslog que queremos
usar. Si no sabéis lo que es esto, podéis echarle un vistazo a los diferentes
niveles en http://www.aboutdebian.com/syslog.htm. El nivel normal a la hora
de hacer pruebas es el 7 (debug).
o [--log-prefix]: Nos permite elegir el encabezamiento que aparecerá en el log
para cada uno de nuestros paquetes registrados. Esto nos permite identificar
qué líneas del log pertenecen a nuestros filtros.

Las reglas LOG tienen una particularidad adicional y es que después de activarse una regla LOG
se sigue buscando en las demás reglas (al contrario que ACCEPT, DROP o REJECT, que en cuanto
concuerda una regla ya se termina el procesamiento de ese paquete). Esto es necesario para
poder guardar un registro de los paquetes y además poder decidir si los aceptamos o no.
Debemos tener esto en cuenta, pues, a la hora de filtrar y registrar paquetes. Primero
deberemos realizar el registro (LOG) y luego decidir si lo aceptamos o lo rechazamos.

Por ejemplo, vamos a permitir el tráfico de salida HTTP y registrar todas las conexiones por ese
puerto. La regla que vamos a usar para realizar el registro será:

iptables -A OUTPUT -p tcp -m tcp --dport 80 -m limit --limit 5/sec -j


LOG --log-prefix "iptables http: " --log-level 7

Varias cosas: en la sintaxis veréis que hemos usado la extensión limit. Esto nos permite controlar
el número de paquetes que vamos a filtrar (en este caso, cinco por segundo). Esto es importante
si vamos a filtrar muchos paquetes y no nos queremos encontrar con log de un tamaño de 500
MB. También hemos seleccionado el nivel de log más alto (menos importante) y le hemos puesto
un prefijo iptables http: a nuestras entradas en el log.

¡Ojo! No se os olvide que esta regla tiene que ir obligatoriamente antes que la regla de ACCEPT.
Si no, una vez que el paquete haya sido aceptado, se interrumpirá la comprobación de reglas y
no se producirá el registro.

Una vez configurado todo, probad a descargaros alguna página con wget y echadle un vistazo al
log. Como siempre nos pasa con Linux, la ubicación del archivo de log puede variar con la
distribución. En Ubuntu está en /var/log/syslog. Como este archivo suele tener un tamaño
considerable (ya que en él se registran todos los sucesos importantes en el sistema), filtraremos
con grep las líneas que nos interesan. Esto es bastante fácil ya que le pusimos un encabezado a
nuestras líneas para poder identificarlas. Así:

cat /var/log/syslog | grep “iptables http:”

nos dará un listado de todas las líneas de log que hayamos registrado desde nuestra regla. Podéis
ver todos los datos que se registran para cada paquete que haya pasado por esa regla (IPs de
origen y destino, puertos, etc.).

Registrando los paquetes rechazados


Para registrar los paquetes aceptados por alguna regla ACCEPT tan sólo tenemos que colocar
una regla similar LOG delante de ésta. Pero, ¿cómo registramos los paquetes rechazados si
estamos usando una política DROP (que espero que estéis usando exclusivamente, por la cuenta
que os trae)?

Pues muy fácil: bastará con colocar las reglas LOG detrás de las reglas ACCEPT. Si el paquete ha
sido aceptado, no pasará de la regla ACCEPT y seguirá comprobando reglas hacia delante. Para
registrar un paquete que no ha sido aceptado por un conjunto de reglas, pondremos la regla
LOG detrás de la última regla ACCEPT. Si queremos registrar todo el tráfico que haya sido
bloqueado, pondremos una regla LOG al final de la tabla que registre todo lo que llegue hasta
allí.

Das könnte Ihnen auch gefallen