Seguridad informática.

Apuntes de Linux - Manual básico de iptables

Iptables puede ser comprensible y muy sencillo en su uso, este manual básicamente está dirigido al usuario recién llegado a GNU/Linux y que no se atreve a crear su propio firewall. Hace años que quería realizar este 'HoWTo' debido a muchas preguntas que me realizaban y aún me realizan bastantes usuarios.

Cabe decir que 'iptables' fué el sustituto de 'ipchains' a partir de los kernel 2.4 haciendo así que tanto el uso sea más amigable, la flexibilidad y la estabilidad fuesen lo más óptimas posible. Así lo veo bajo mi punto de vista tras haber trabajado con kernels 2.2, 2.4, 2.6 y sucesivas versiones del mismo.

- Funcionamiento.

Un firewall consiste reálmente en un filtro que analiza todos los paquetes leyendo el encabezado que recibe un interface determinado. Como bien sabemos puede llevar a cabo normálmente cuatro acciones:

. Aceptar <--- ACCEPT
. Desechar <--- DROP
. Rechazar <--- REJECT
. Redigirir <---- FORWARD

Es por así llamarlo un filtro a nivel del kernel (núcleo del sistema) que se encarga a través de sencillas reglas contenidas en las correspondientes tablas que los paquetes lleguen a cualquier tipo de proceso.

Las tres tablas que utiliza son:

. INPUT <--- Entrada
. OUTPUT <--- Salida
. FORWARD <--- Redirección

La explicación del funcionamiento es treméndamente sencillo:

Tenemos un paquete entrante por cualquier interface el cual a continuación es examinado por el kernel buscando su destino. A continuación como norma general suele tomar como parámetro 'INPUT' o utilizar la tabla 'FORWARD' para realizar la comparación con las reglas establecidas en las mismas y llevar a cabo ACCEPT-DROP-REJECT.

. Conceptos.

Vamos a analizar por encima las órdenes básicas y algunas estructuras de cadena que hemos de pasarle a 'iptables'.

Para tener primero antes de nada un concepto global siempre es aconsejable consultar la ayuda de la aplicación:

22:13:55 ------:~ > iptables -h
iptables v1.4.18

Usage: iptables -[ACD] chain rule-specification [options]
iptables -I chain [rulenum] rule-specification [options]
iptables -R chain rulenum rule-specification [options]
iptables -D chain rulenum [options]
iptables -[LS] [chain [rulenum]] [options]
iptables -[FZ] [chain] [options]
iptables -[NX] chain
iptables -E old-chain-name new-chain-name
iptables -P chain target [options]
iptables -h (print this help information)

Commands:
Either long or short options are allowed.
--append -A chain Append to chain
--check -C chain Check for the existence of a rule
--delete -D chain Delete matching rule from chain
--delete -D chain rulenum
Delete rule rulenum (1 = first) from chain
--insert -I chain [rulenum]
Insert in chain as rulenum (default 1=first)
--replace -R chain rulenum
Replace rule rulenum (1 = first) in chain
--list -L [chain [rulenum]]
List the rules in a chain or all chains
--list-rules -S [chain [rulenum]]
Print the rules in a chain or all chains
--flush -F [chain] Delete all rules in chain or all chains
--zero -Z [chain [rulenum]]
Zero counters in chain or all chains
--new -N chain Create a new user-defined chain
--delete-chain
-X [chain] Delete a user-defined chain
--policy -P chain target
Change policy on chain to target
--rename-chain
-E old-chain new-chain
Change chain name, (moving any references)
Options:
--ipv4 -4 Nothing (line is ignored by ip6tables-restore)
--ipv6 -6 Error (line is ignored by iptables-restore)
[!] --proto -p proto protocol: by number or name, eg. `tcp'
[!] --source -s address[/mask][...]
source specification
[!] --destination -d address[/mask][...]
destination specification
[!] --in-interface -i input name[+]
network interface name ([+] for wildcard)
--jump -j target
target for rule (may load target extension)
--goto -g chain
jump to chain with no return
--match -m match
extended match (may load extension)
--numeric -n numeric output of addresses and ports
[!] --out-interface -o output name[+]
network interface name ([+] for wildcard)
--table -t table table to manipulate (default: `filter')
--verbose -v verbose mode
--line-numbers print line numbers when listing
--exact -x expand numbers (display exact values)
[!] --fragment -f match second or further fragments only
--modprobe= try to insert modules using this command
--set-counters PKTS BYTES set the counter during insert/append
[!] --version -V print package version.

Vamos a centrarnos en las órdenes básicas:

iptables -F : Realiza un borrado general de todas las reglas.
-L : Lista las reglas aplicadas.
-A : Añade una entrada.
-D : Borra una entrada.

La estructura para añadir una regla en la tabla 'INPUT' es la siguiente:

--
iptables -A INPUT -i (interface) -s (ip) -p (protocolo) --dport (puertodedestino) -j (accion)

Vamos a analizar un poco las opciones que podemos utilizar:

. -i (interface) | -o (interface) : Creo que poca explicación requiere ya que se trata de especificar con que interface de red deseamos trabajar. Puede ser el de loopback (lo), un interface wireless (wlanX), interface ethernet (ethX), interface PPP (pppX). Donde 'X' indica el número del mismo si trabajamos con múltiples interfaces de un mismo tipo. Normálmente utilizaremos el parámetro -o para indicar un interface de salida, pongo por el caso de una máquina realizando NAT conectada a un switch. Lo habitual sería '-i eth0' y '-o eth1'.

. -s (ip) | -d (ip) : Se refiere a la dirección IP de la conexión entrante (-s) o por el contrario de tratarse de la dirección IP de una máquina a la que sean dirigidos nuestros paquetes (-d). Podemos especificar la entrada de varias maneras. Las más habituales son por rango de IP, por ejemplo 192,168,1,0/24; Añadiendo una ip determinada 192,168,1,1 o por dominio www.google.es .

. -p (protocolo) : Podemos utilizar los protocolos tcp, udp e icmp. En el caso de indicar 'all' la regla creada afectará a todos los protocolos.

. --dport (puerto) | --sport (puerto) : Lo primero antes de nada es hacer referencia al fichero '/etc/services'. Ahí se encuentra la relación de número de puerto virtual y los servicios asociados a los mismos establecidos y documentados en los 'RFC'.

Debemos enfocarlo de manera que nos refiramos a una máquina local, por ejemplo. Nuestra máquina local está ejecutando un MTA, entonces crearemos la regla al puerto de destino 25, lo que se traduce a '–dport 25'.

. -j (acción) : Como hemos visto anteriormente tenemos tres opciones, 'ACCEPT' (aceptar), 'DROP' (desechar) y 'REJECT' (rechazar).

Las políticas de iptables genéricamente vienen siendo demasiado permisivas, en el caso de precisar un conjunto de las mismas más restrictivas las cambiaríamos de esta manera:

[root@------ ----]# iptables -P INPUT DROP
[root@------ ----]# iptables -F INPUT
[root@------ ----]# iptables -P OUTPUT ACCEPT
[root@------ ----]# iptables -F OUTPUT

- Ejemplos prácticos.

Un ejemplo práctico con el servicio SSH, denegaremos el acceso desde cualquier dirección externa:

iptables -A INPUT -i eth0 -s 0.0.0.0/0 -p tcp --dport 22 -j DROP

La mejor forma de entender el funcionamiento es mediante la relación “iptables añade una regla a la tabla INPUT a través del interface eth0 desde cualquier dirección externa mediante el protocolo tcp al puerto local 22 y la desecha”.

Para consultar el contenido solamente de esta tabla:

[root@------ ----]# iptables -L INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP tcp -- anywhere anywhere tcp dpt:ssh

Para borrar la cadena tenemos dos opciones. O bien utilizar el borrado por la enumeración de cada regla teniendo en cuenta su posición en la tabla:

[root@------ ----]# iptables -D INPUT 1
[root@------ ----]# iptables -L INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination

Podemos también utilizar una cadena de estructura similar a la que hemos introducido anteriormente para añadirla. Sólamente cambiaremos el parámetro '-A' por '-D':

[root@------ ----]# iptables -A INPUT -i eth0 -s 0.0.0.0/0 -p tcp --dport 22 -j DROP
[root@------ ----]# iptables -L INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP tcp -- anywhere anywhere tcp dpt:ssh
[root@------ ----]# iptables -D INPUT -i eth0 -s 0.0.0.0/0 -p tcp --dport 22 -j DROP
[root@------ ----]# iptables -L INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination

Otro ejemplo práctico sería:

iptables -A INPUT -i eth0 -s 192.168.1.0/24 -p tcp --dport 80 -j ACCEPT

En este caso, “iptables añade un regla a la tabla INPUT a través del interface eth0 desde cualquier dirección de la red local mediante el protocolo tcp al puerto local 80 y la acepta”.

Podemos jugar con muchas opciones y quizá ser un poco malos con un host o ip en particular. Yo por ejemplo este ejemplo con paquetes ICMP lo tengo integrado en el SDI (Sistema de Detección de Intrusiones) que utilizo en mis máquinas mediante un script. Me gusta utilizar los detectores de intrusiones activos por la sencilla razón de tomar medidas antes de que los atacantes logren acceso a cualquier equipo. Siempre los primeros pasos para una intrusión es el mapeo de puertos, y así es como toma la dirección IP atacante como variable realizando la siguiente acción en la tabla 'INPUT'.

[root@------ ----]# ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.067 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.072 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.070 ms
64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.068 ms
^C
--- localhost ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2997ms
rtt min/avg/max/mdev = 0.067/0.069/0.072/0.006 ms

Vamos a ser “malos” con un atacante añadiendo su IP y la opción DROP (desecho) a la tabla INPUT:

..

[root@------ ----]# iptables -A INPUT -p ICMP -s 127.0.0.1 -j DROP

Ejecutamos ping de nuevo:

[root@------ ----]# ping localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
^C
--- localhost ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4008ms

Listamos el contenido de las tablas:

[root@------ ----]# iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP icmp -- localhost anywhere

Chain FORWARD (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

Borramos la regla creada:

[root@------ ----]# iptables -D INPUT 1

Un buen ejemplo de como podemos sacarle más partido todavía a 'iptables', no solamente es a nivel 'filtro' aceptando y denegando conexiones, paquetes, etc … Podemos utilizar la máquina para redirigir tráfico entre una red LAN y una WAN. En este caso aporto la configuración de mi propio script para iptables, en realidad aparece comentada porque muy rara vez la utilizo, de todas formas siempre es bueno tenerla en la recámara 'comentada'. Es muy sencilla, muy lejos de lo que muchos pueden llegar a pensar.

#echo Iniciando NAT ...
#modprobe iptable_nat
#iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
#echo 1 > /proc/sys/net/ipv4/ip_forward

Para finalizar añado algunas entradas más con las cuales podemos “asegurar” un poco nuestro equipo como medida de precaución:

. Ping deshabilitado.
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all

. Broadcast deshabilitado.
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts

. Redirecciones de ping deshabilitadas.
echo 0 > /proc/sys/net/ipv4/conf/all/accept_redirects

. Protección anti-flood (SYN).
iptables -N syn-flood
iptables -A INPUT -i eth0 -p tcp --syn -j syn-flood
iptables -A syn-flood -m limit --limit 1/s --limit-burst 4 -j RETURN
iptables -A syn-flood -j DROP

. Registro de cualquier tipo de actividad extraña.
echo 1 > /proc/sys/net/ipv4/conf/all/log_martians

Siguiendo estas explicaciones y adaptando las necesidades que podáis tener en cuanto a los servicios que están disponibles en vuestra red local o cualquier otro tipo de circunstancias no creo que haya problema alguno para que configureis vuestro propio firewall basado en iptables.

That's all folks!