Información blog

Linux, tutoriales, noticias, sistemas, redes y seguridad informática, entre otras cosas.

domingo, 3 de febrero de 2013

Iptables y su relevancia en la protección de Linux

Habiendo abierto el tema de la seguridad, voy esta vez voy a hablar de otro aspecto fundamental en la protección de un equipo con sistema operativo Linux. Esta vez voy a hablar de iptables, una herramienta instalada por defecto que viene sin configuración alguna, haciendo que así sin más no sea útil para nada. Aún así, es una herramienta que es muy importante saber manejar, ya que dependeremos de ella para mantener seguro nuestro equipo.

Iptables se trata de un software instalado por defecto en Linux cuya funcionalidad más famosa es la de hacer de cortafuegos aunque en realidad se trata más bien de un filtro de paquetes ipv4 que los trata de diferentes formas según nuestras necesidades. Muchos usuarios conocen su existencia aunque pocos se atreven a manejarlo debido a que al principio resulta dificultoso y tedioso establecer cualquier tipo de cambio en el software desde la línea de comandos. Yo mismo tuve mis problemas al principio, aunque con un poco de práctica, uno puede entender las funcionalidades básicas y atreverse a aplicarlas sin tener que andar haciendo constantemente copy paste del código que se topa por Internet. Las posibilidades de iptables son tantas y tan amplias que es imposible escribirlas por aquí sin hacer que al lector le entre el sopor; para todo aquel que quiera ver la información completa y detallada de iptables le recomiendo escribir en la línea de comandos: man iptables. Allí aparecerá toda la información referente a él, yo solamente explicaré el manejo básico. Antes de empezar es conveniente explicar unos pocos conceptos elementales:


Una cadena es una lista de reglas que reúnen una serie de paquetes para su posterior tratamiento. Por ejemplo una cadena es una lista de reglas cuyo factor común es que provienen del exterior hacia nuestro equipo. Estas reglas ya vienen predefinidas aunque un usuario avanzado puede querer decidir crear sus propias reglas

Un “target” u objetivo, es la acción que se realiza en caso de que una regla se cumpla. En iptables se denominan targets aunque para que tengáis una mejor visión mental pensar en ellas cómo acciones.

Una tabla es la encargada de realizar las diferentes acciones que le mandemos. Digamos que cada tabla es una “oficina” encargada de una tarea específica que tan sólo ella puede hacer. Cada tabla reúne un conjunto de cadenas especificas, ya sean predefinidas o definidas por el usuario y son especificadas con el parámetro -t.

No importa sobre que tabla actuemos, podemos ejecutar los mismos comandos sobre todas por igual. Estos son algunos de ellos:

  • -A: Añade una regla a la tabla y cadena especifica.
  • -D: Borra una regla de la tabla y cadena especificada
  • -I : Inserta una regla en una posición especifica de la cadena y regla deseada. Si escribimos la posición 1, será la primera regla. Para este comando se escribe iptables –I numero. Ej: iptables –I 1 ….
  • -R: Sustituye una regla situada en una posición X. Funciona igual que iptables –I.
  • -P: política general de la tabla y cadena especifica. Digamos que si usamos esta cadena diremos luego el “target” que tendrá la cadena en general. Si usamos –P el “target” se especificara acto seguido sin parámetro alguno de por medio. Digamos la política es la regla predominante de la tabla y cadena especificada a menos que le indiquemos lo contrario.
  • -F: Borra todas las reglas de todas las cadenas de la tabla
  • -L: Lista simple de las reglas de una tabla especifica
  • -nvL: Lista detallada de las reglas de una tabla especifica
  • -N: Crea una cadena personalizada
  • -E: Renombra una cadena. Esto solo afecta al nombre, no al funcionamiento de ésta, y será un detalle meramente visual que no hará conflicto con lo ya creado hasta ahora.

Cómo todo comando, las tablas también usan parámetros, estos son algunos de ellos:
  • -p= protocolo
  • -s= dirección ip, host o nombre del dominio de origen.
  • -d= dirección de destino.
  • -i= interfaz de por donde los paquetes van a entrar
  • -o= interfaz por donde saldrán los paquetes.
  • -j= la acción a tomar tras una vez localizado el paquete. Ésta varía según la tabla en la que nos encontremos.

Hay muchísimos más parámetros, pero estos son mucho más complejos y suelen ir seguidos de –m “parámetro” --“subparametro”… Excepto si dicho parámetro maestro ya ha sido nombrado de manera implícita antes cómo –p por ejemplo el cual hace que no necesitemos usar –m. En este caso el comando sería –p “protocolo” --“subparametro”. Entre estos parámetros y subparametros yo veo uno que es esencial saberlo y además es muy fácil de aprender; se trata del subparametro --dport que especifica el número de puerto que revisará la regla. Pongamos un ejemplo muy simple.

iptables –t filter –A OUTPUT –o eth0 –p tcp --dport 80 –j REJECT.

¿Fácil verdad? Aquí decimos que todo aquello que salga por la interfaz de red llamada eth0, usando el protocolo tcp, en caso de querer pasar por el puerto 80 no pueda hacerlo. No os preocupéis sobre el OUTPUT y el REJECT, basta saber que OUTPUT es una cadena y REJECT es un “target”. Más adelante veréis el significado de éstos.

Existen 4 tablas, pero la cuarta apenas se usa nunca con lo que muchos solo cuentan cómo que solo existen tres, y en mi experiencia puedo decir que no he tenido que usar la cuarta, aún así os diré su nombre; el nombre de la cuarta tabla es raw y sirve para “no vigilar” ciertas conexiones que cumplan las reglas que introduzcamos en esta tabla. Para usar cualquiera de éstas debemos escribir –t seguido del nombre de la tabla. Comencemos con la más famosa y usada, que es la que hace de cortafuegos.

Filter: Esta es la tabla que toma por defecto iptables, es decir que en caso de no especificar ninguna, siempre se dará por hecho de que se trata con ésta, cosa que hace que algunos piensen que iptables sólo tiene una función, nada más lejos de la verdad. Esta tabla es la encargada de filtrar los paquetes. Usa cadenas INPUT, OUTPUT y FORWARD. INPUT es una cadena que reúne todo aquello que entra en el equipo, output de todo lo que sale y forward de todo aquello que se reenvía a otra ip o puerto.

Las acciones a tomar en esta tabla serían las siguientes:

ACCEPT Deja que el paquete llegue a su destino
REJECT No le deja pasar al paquete, e informa a aquel que ha intentado lanzar el paquete por dicha vía que no puede pasar por allí.
DROP No le deja pasar al paquete y además no informa de ello.
LOG Registra en el log que cierta ip con cierta mac ha pasado por el filtro.

El mejor ejemplo sería una sentencia cómo esta:

      iptables -A INPUT -s 192.168.0.0/24 -d 192.168.5.0 -p tcp -j ACCEPT

Aquí especificamos que un paquete que llegue desde cualquier ordenador con la ip 192.168.X.X (X significa lo que sea) hacia la ip 192.168.5.X (es decir a toda ip que empiece por 192.168.5) por protocolo tcp, pase por el filtro sin problemas, es decir, que llegue al destinatario. Eso de por sí puede no tener sentido, pues si solo tuviésemos esta regla, llegaría igualmente; pero si por ejemplo, hubiésemos hecho una regla que denegase el acceso, si no pusiésemos esta regla el paquete no llegaría.

Por ejemplo si hubiésemos escrito esto:

iptables -A INPUT -s 192.168.0.0/24 -j REJECT

Con esta regla habríamos denegado a todos los ordenadores procedentes de 192.168. X.X cualquier acceso a cualquier ip sin importar el protocolo que use o el puerto por el que acceda y solo usando la regla escrita anteriormente, cumpliendo las condiciones escritas en ésta, podríamos tener acceso a los ordenadores 192.168.5.X

Algunos os preguntareis si se puede usar iptables con ipv6. La respuesta es sí, pero para ello no sirve iptables, sino que se usa ip6tables, que tiene los mismos comandos y parámetros, sólo que está orientado a ipv6.

Bien, con esto ya se puede decir que aunque estamos lejos de decir que “sabemos” iptables, si que podemos hacer algunos filtros para que no entren intrusos indeseados con lo que vamos a ello: La seguridad del firewall que voy a hacer es simple y rudimentaria, pero al menos nos mantendrá protegidos de la mayoría de intrusiones indeseadas, pues solo dejaré abiertos entre 3 y 4 puertos, el 80 (Internet), el 22 (ssh. Para poder acceder por este puerto a linux debemos instalar openssh-server. Este servicio hace que podamos acceder remotamente al equipo de forma segura), el 53(DNS) y 21(ftp, este es opcional).Evidentemente, si queremos dejar alguno más abierto podemos hacerlo, pero para ello recomiendo poner unas restricciones muy especificas que solo dejen que acceda una ip(o un pequeño rango de ips) especifico.

Antes de nada yo recomiendo reunir todos los comandos en un script, pues si más adelante hacemos algún cambio indeseado en iptables, siempre podremos limpiar iptables y volver a lanzar los comandos sin introducir nada, además de que el introducir los comandos a mano no es nada practico cómo luego veremos. Aparte, podemos guardar el script en un USB para que cuando instalemos otro Linux nos evitemos volver a meter los comandos, ya sean los que he puesto yo aquí o los que introduzcáis vosotros. Si no tenéis conocimientos de shell script no pasa nada pues si seguís los pasos, os debería funcionar a la perfección.

Para ello usamos el editor que más nos guste (mcedit, nano, vi…) y creamos un fichero que yo por ejemplo titularía iptables.sh, y lo alojaría en el directorio /etc/init.d (luego veréis porqué). En caso de querer ponerle otro nombre recordad poner al final siempre .sh, ya que es la extensión que usan los scripts.


  1. ############SCRIPT DE CREACIÓN UN FIREWALL BÁSICO#############
  2. #!/bin/bash
  3. ### BEGIN INIT INFO
  4. # Provides:          Nombre del script
  5. # Required-Start:    $remote_fs  
  6. # Required-Stop:     $remote_fs  
  7. # Default-Start:     2 3 4 5
  8. #!/bin/bash
  9. #inicio indispensable en todo script
  10. #No es indispensable, pero si recomendable escribir
  11. ### BEGIN INIT INFO
  12. # Provides: iptables.sh
  13. # Required-Start: $syslog
  14. # Required-Stop: $syslog
  15. # Default-Start: 2 3 4 5
  16. # Default-Stop: 0 1 6
  17. # Short-Description: blabla
  18. # Description:
  19. #
  20. ### END INIT INFO
  21. #Primero hacemos que no nos puedan hacer ping.
  22. #Esto no es parte de iptables pero es recomendable hacerlo
  23. echo '1' > /proc/sys/net/ipv4/icmp_echo_ignore_all
  24. echo '1' >/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
  25. #Partiendo de la base de que estamos en un entorno domestico
  26. #pensamos en que nos interesa salir al exterior sin restricciones,
  27. #pero que solo queremos que entre el trafico justo a nuestro ordenador
  28. #es decir Internet, ssh y el DNS
  29. #Las politicas por defectos son ACCEPT pero me gusta escribirlas
  30. #Por si en un futuro quisiese editarlo
  31. #Cómo queremos tener por defecto todo bloqueado,
  32. #hacemos que la politica INPUT bloquee todo el acceso abriendo solo lo que nos interesa
  33. iptables -P INPUT DROP
  34. iptables -P FORWARD ACCEPT
  35. iptables -P OUTPUT ACCEPT
  36. #Permitimos el acceso del propio equipo al localhost
  37. iptables -A INPUT -i lo -j ACCEPT
  38. #Dejamos abierto el puerto 80 para permitir el acceso a Internet.
  39. #si no abrimos este puerto no podremos tener contacto con el exterior.
  40. iptables -A INPUT -p tcp --dport 80 -j ACCEPT
  41. iptables -A INPUT -p udp --dport 80 -j ACCEPT
  42. #Dejamos abierto el puerto por ssh.
  43. iptables -A INPUT -p tcp --dport 22 -j ACCEPT
  44. #DNS
  45. iptables -A INPUT -p tcp --dport 53 -j ACCEPT
  46. iptables -A INPUT -p udp --dport 53 -j ACCEPT
  47. #Opcional Esto es por si quisiesemos acceder por ftp
  48. iptables -A INPUT -p tcp --dport 21 -j ACCEPT
  49. iptables -A INPUT -p udp --dport 21 -j ACCEPT
  50. #Por otro lado está el olvidado, pero importante ipv6,
  51. #el cual también necesita un trato a menos que queramos que aprovechen esa entrada.
  52. #Si tenemos ipv6 deshabilitado no tenemos que preocuparnos de nada, de esto.
  53. #En caso contrario habría que escribir las mismas reglas que arriba pero orientadas a ipv6.
  54. ip6tables -P INPUT DROP
  55. ip6tables -P FORWARD ACCEPT
  56. ip6tables -P OUTPUT ACCEPT
  57. ip6tables -A INPUT -i lo -j ACCEPT
  58. ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
  59. ip6tables -A INPUT -p udp --dport 80 -j ACCEPT
  60. ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
  61. ip6tables -A INPUT -p tcp --dport 53 -j ACCEPT
  62. ip6tables -A INPUT -p udp --dport 53 -j ACCEPT
  63. ip6tables -A INPUT -p tcp --dport 21 -j ACCEPT
  64. ip6tables -A INPUT -p udp --dport 21 -j ACCEPT

Con esto ya tenemos un script básico, pero perfectamente funcional que nos protegerá de la mayoría de las amenazas. Esto hace que podamos usar el pc con normalidad aunque si queremos usar alguna aplicación que requiera tener un puerto nuestro abierto deberemos configurar iptables para que permita el paso. Ya terminado esto lo guardamos y salimos del editor para después escribir:
Chmod 755 iptables.sh
./iptables.sh

Como saber si funcionan nuestros cambios:

Prueba 1:
Escribir iptables –nvL y ip6tables –nvL. Deberían mostrarse las reglas creadas mediante el script.
Prueba 2:
Probamos nuestra salida a internet escribiendo en consola apt-get update o instalando alguna aplicación mediante el método que prefiráis.
Prueba 3:
Para esta prueba se necesitan tener dos equipos, a menos que tengas instalado linux en una maquina virtual, con lo cual podrías hacer la prueba. Uno es nuestro linux, el otro puede ser un portátil o lo que sea.


Requisitos para la prueba:
  • Tener los dos pcs en el mismo rango de ip. Ejemplo:

PC linux: 192.168.1.10 Mascara: 255.255.255.0
PC externo: 192.168.1.15 Mascara 255.255.255.0

Si tienes una red con un DHCP (es decir que obtengas la ip sin que tengas que configurar nada a mano), y tienes los dos equipos obteniendo ip por ese DHCP, no tienes que preocuparte de saber si están en el mismo rango. En las redes domesticas el router te proveen de ip automáticamente, con lo que tan solo asegúrate de tener los dos equipos conectados a la red.
  • Instalar Filezilla Client en el ordenador desde el que queremos acceder a linux. Hay más vías, pero creo que esta es la más sencilla.

Abrimos Filezilla y escribimos en la sección servidor la ip del equipo Linux (en caso de no saberla ejecutar ifconfig en Linux). Luego introducimos el usuario y contraseña (cómo si fueses a entrar en Linux) y usamos el puerto 22. Si nos deja el acceso, es que tenemos acceso al puerto 22. Podemos hacer la misma prueba usando ipv6 si queremos estar seguros.

Por último. Aprovechando que estamos en el mismo rango de ip probaremos a hacerle ping al equipo. Abrimos una consola ya sea en Linux o en Windows y escribimos ping ip del equipo protegido. Veréis que el equipo no responde a la llamada pues hemos hecho que haga caso omiso a ese tipo de peticiones.

Ya tenemos un ordenador protegido de amenazas exteriores pero hay un pequeño problema… Los cambios no se guardarán iptables ni en ip6tables una vez apaguemos el sistema… Eso significa que al reiniciar el equipo volveremos a estar desprotegidos… ¿cómo resolver eso? Claro podemos volver a ejecutar manualmente el script cómo antes, pero eso requeriría que nos acordásemos de ejecutarlo siempre que encendamos Linux, cosa tediosa y engorrosa. Por ello, la solución más practica es que se ejecute el script al iniciar el sistema (he ahí la razón por la que recomiendo hacer el script, guardándolo en /etc/init.d). El tener el script situado en el directorio antes mencionado, nos da la opción de ejecutarlo en el arranque, aunque para ello necesitamos escribir uno de los siguientes comandos (no importa cual, yo pongo las dos opciones):

update-rc.d iptables.sh defaults” o “insserv iptables.sh”

Ambos hacen lo mismo pero lo malo es que insserv no se usa en las versiones antiguas de linux, mientras que en las nuevas aunque las dos formas están admitidas, es más recomendable usar insserv, pues probablemente, dentro de poco sustituirá por completo update-rcd.

Con esto ya tendríamos nuestro equipo protegido desde el arranque, recordad que hay aplicaciones que requieren tener puertos abiertos con lo que si no os funcionan dichas aplicaciones, tendréis que editar iptables abriendo los puertos adecuados.

Espero que os haya sido útil. 

Un saludo.

No hay comentarios :

Publicar un comentario