Tutorial

Cómo configurar Packet Filter (PF) en FreeBSD 12.1

SecurityFirewallFreeBSD

El autor seleccionó el COVID-19 Relief Fund para que reciba una donación como parte del programa Write for DOnations.

Introducción

El firewall posiblemente sea una de las líneas de defensa más importantes contra los ataques cibernéticos. La capacidad de configurar un firewall desde cero es una habilidad increíble que permite al administrador tomar el control de sus redes.

Packet Filter (PF) es una renombrada aplicación de firewall que se mantiene upstream por el proyecto orientado a la seguridad OpenBSD. Se expresa de forma más expresiva como una herramienta de filtrado de paquetes, de ahí su nombre, y es conocida por su sintaxis sencilla, facilidad de uso y gran cantidad de funciones. PF es un firewall con estados por defecto, que almacena información sobre las conexiones en una tabla de estados a la que puede accederse con fines analíticos. PF es parte del sistema básico de FreeBSD y cuenta con el apoyo de una fuerte comunidad de desarrolladores. Aunque existen diferencias entre las versiones FreeBSD y OpenBSD de PF en relación con las arquitecturas del kernel, en general su sintaxis es similar. Dependiendo de su complejidad, los conjuntos de reglas comunes pueden modificarse para que funcionen en cualquier distribución con un esfuerzo relativamente pequeño.

A través de este tutorial, creará un firewall desde cero en un servidor FreeBSD 12.1 con PF. Diseñará un conjunto de reglas básico que puede usarse como plantilla para futuros proyectos. También explorará algunas de las funciones avanzadas de PF, como la limpieza de paquetes, la prevención de ataques por fuerza bruta, la monitorización y el registro, y otras herramientas de terceros.

Requisitos previos

Antes de iniciar este tutorial, necesitará lo siguiente:

  • Un servidor FreeBSD 12.1 (ZFS o UFS). Puede usar nuestro tutorial Cómo comenzar con FreeBSD para configurar su servidor con su configuración deseada.
  • FreeBSD no tiene un firewall habilitado por defecto; la personalización es una característica propia de la filosofía de FreeBSD. Por tanto, cuando inicie su servidor por primera vez, necesitará protección temporal mientras que se configura PF. Si usa DigitalOcean, puede habilitar su firewall en la nube de inmediato tras iniciar el servidor. Consulte Inicio rápido del firewall de DigitalOcean para obtener instrucciones sobre cómo configurar un firewall en la nube. Si está usando otro proveedor en la nube, determine la ruta más rápida para la protección inmediata antes de comenzar. Sea cual sea el método que elija, su firewall temporal debe permitir solo el tráfico SSH entrante y puede permitir todos los tipos de tráfico saliente.

Paso 1: Crear su conjunto de reglas preliminares

Comenzará este tutorial esbozando un conjunto de reglas prelimnares que proporcionan protección básica y acceso a los servicios críticos de Internet. En este momento, tendrá un servidor FreeBSD 12.1 en ejecución con un firewall en la nube activo.

Existen dos enfoques a la hora de crear un firewall: denegación por defecto y permiso por defecto. El enfoque denegación por defecto bloquea todo el tráfico, y solo permite lo que se especifica en una regla. El enfoque permiso por defecto, hace justo lo contrario: pasa todo el tráfico y solo bloquea lo que se especifica en una regla. Utilizará el enfoque denegación por defecto.

Los conjuntos de reglas PF se escriben en un archivo de configuración llamado /etc/pf.conf, que también es su ubicación predeterminada. Está bien guardar este archivo en otro lugar siempre que se especifique en el archivo de configuración de /etc/rc.conf. Para este tutorial, usará la ubicación predeterminada.

Inicie sesión en su servidor con su usuario no root:

  • ssh freebsd@your_server_ip

A continuación, cree su archivo /etc/pf.conf:

  • sudo vi /etc/pf.conf

Nota: Si desea ver el conjunto de reglas básico completo en cualquier punto de este tutorial, puede consultar los ejemplos del paso 4 o del paso 8.

PF filtra los paquetes según tres acciones principales: block, pass y match. Cuando se combinan con otras opciones, forman reglas. Se realiza una acción cuando un paquete cumple con el criterio especificado en una regla. Como puede esperar, las reglas pass y block aplicarán pass y block al tráfico, respectivamente. Una regla match realiza una acción sobre un paquete cuando encuentra un criterio de coincidencia, pero no lo pasa o bloquea. Por ejemplo, puede realizar la traducción de dirección de red (NAT) sobre un paquete que coincida sin pasarlo o bloquearlo, y permanecerá allí hasta que le diga que haga algo en otra regla, como dirigirlo a otro equipo o puerta de enlace.

A continuación, añada la primera regla a su archivo /etc/pf.conf:

/etc/pf.conf
block all

Esta regla bloquea todas las formas de tráfico en cada dirección. Ya que no especifica una dirección, los valores por defecto son in y out. Esta regla es legítima para una estación de trabajo local que deba estar aislada del mundo, pero es muy poco práctica y no funcionará en un servidor remoto porque no permite tráfico SSH. De hecho, si tuviese PF habilitado habría bloqueado usted mismo su acceso al servidor.

Revise su archivo /etc/pf.conf para permitir el tráfico SSH con la siguiente línea resaltada:

/etc/pf.conf
block all
pass in proto tcp to port 22

Nota: De forma alternativa, puede usar el nombre del protocolo:

/etc/pf.conf
block all
pass in proto tcp to port ssh

Para mantener la consistencia, usaremos los números de puerto, a menos que exista una razón válida para no hacerlo. Hay una lista detallada de protocolos y sus números de puertos respectivos en el archivo /etc/services, que le aconsejamos que vea.

PF procesa las reglas de forma secuencial de arriba a abajo, por tanto, su conjunto de reglas inicialmente bloquea todo el tráfico, pero luego lo pasa si el criterio de la siguiente línea se cumple, como en el caso del tráfico SSH.

Ahora podrá permitir tráfico SSH en su servidor. No obstante, bloqueará toda forma de tráfico saliente. Esto es problemático por que no puede acceder a los servicios críticos desde Internet para instalar paquetes, actualizar sus ajustes de fecha y hora, etc.

Para corregir esto, añada la siguiente regla resaltada al final de su archivo /etc/pf.conf:

/etc/pf.conf
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }

Su conjunto de reglas ahora permite tráfico SSH, DNS, HTTP, NTP y HTTPS saliente, y bloquea todo el tráfico entrante (con la excepción de SSH). Coloca los números de puerto y protocolos entre corchetes, lo que forma una lista en la sinaxis de PF, permitiéndole añadir más números de puertos si es necesario. También añada una regla de paso para el protocolo UDP en los puertos 53 y 123 porque DNS y NTP a menudo alternan entre los protocolos TCP y UDP. Casi completó el conjunto de reglas preliminares. Solo debe agregar algunas reglas para lograr una funcionalidad básica.

Complete el conjunto de reglas preliminares con las reglas resaltadas:

Preliminary Ruleset /etc/pf.conf
set skip on lo0
block all
pass in proto tcp to port { 22 }
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass out inet proto icmp icmp-type { echoreq }

Guarde el archivo y ciérrelo.

Creará la regla set skip para el dispositivo loopback porque no necesita filtrar tráfico y probablemente haga que se aplique rastreo en su servidor. Añada una regla pass out inet para el protocolo ICMP, que le permite usar la utilidad ping(8) para resolver problemas. La opción inet representa la familia de direcciones IPv4.

ICMP es un protocolo de mensajería polivalente usado por los dispositivos de red para varios tipos de comunicaciones. La utilidad ping, por ejemplo, utiliza un tipo de mensaje conocido como echo request, que ha añadido a su lista icmp_type. Como precaución, solo permite los tipos de mensaje que necesita para evitar que dispositivos no permitidos se pongan en contacto con su servidor. A medida que sus necesidades aumentan, puede añadir más tipos de mensajes a su lista.

Ahora tiene un conjunto de reglas en funcionamiento que proporciona funcionalidad básica para la mayoría de las máquinas. En la siguiente sección, vamos a confirmar que todo funcione correctamente habilitando PF y probando su conjunto de reglas preliminares.

Paso 2: Probar su conjunto de reglas preliminares

En este paso, probará su conjunto de reglas preliminares, realizará la transición de su firewall en la nube a su firewall de PF y permitirá que PF tenga todo el control. Activará su conjunto de reglas con la utilidad pfctl, que es la herramienta de línea de comandos integrada de PF, y el método principal para interactuar con PF.

Los conjuntos de reglas PF no son otra cosa que archivos de texto, lo cual significa que no hay procedimientos delicados implicados en la carga de nuevos conjuntos de reglas. Puede cargar un nuevo conjunto de reglas y el anterior desaparecerá. En escasas ocasiones, si es necesario, existe la necesidad de eliminar un conjunto de reglas existente.

FreeBSD utiliza una web de secuencias de comandos shell conocida como el sistema rc para administrar cómo se inician los servicios en el momento del arranque; especificamos esos servicios en varios archivos de configuración rc. Para los servicios globales como PF, utiliza el archivo /etc/rc.conf. Debido a que los archivos rc son críticos para el bienestar de un sistema de FreeBSD, no deberían editarse directamente. En su lugar, FreeBSD ofrece una utilidad de línea de comandos conocida como sysrc diseñada para ayudarle a editar estos archivo de forma segura.

Habilitaremos PF usando la utilidad de línea de comandos sysrc:

  • sudo sysrc pf_enable="YES"
  • sudo sysrc pflog_enable="YES"

Verifique estos cambios imprimiendo el contenido de su archivo /etc/rc.conf:

  • sudo cat /etc/rc.conf

Verá lo siguiente:

Output
pf_enable="YES" pflog_enable="YES"

También habilitará el servicio pflog que, a su vez, permite que el demonio pflogd inicie sesión en PF. Trabajará con el inicio de sesión en un paso posterior.

Se especifican dos servicios globales en su archivo /etc/rc.conf, pero estos no se inicializarán hasta que reinicie el servidor o los ponga en marcha manualmente. Reinicie el servidor de forma que pueda probar también su acceso SSH.

Inicie PF reiniciando el servidor:

  • sudo reboot

La conexión se caerá. Dele unos minutos para actualizarse.

Ahora, realice SSH de nuevo en el servidor:

  • ssh freebsd@your_server_ip

Aunque inicializó sus servicios de PF, en realidad no cargó su conjunto de reglas /etc/pf.conf, lo cual significa que su firewall no está aún activo.

Cargue el conjunto de reglas con pfctl:

  • sudo pfctl -f /etc/pf.conf

Si no hay errores o mensajes, significa que su conjunto de reglas no tiene errores y el firewall está activo.

Ahora que PF está en ejecución, puede desconectar su servidor de su firewall en la nube. Esto puede conseguirse en el panel de control de su cuenta de DigitalOcean eliminando su Droplet de su portal de firewall en la nube. Si está usando otro proveedor en la nube, asegúrese que lo que esté usando para la protección temporal esté desactivado. Es casi seguro que ejecutar dos firewalls en un servidor causará problemas.

Por seguridad, reinicie su servidor de nuevo:

  • sudo reboot

Tras unos minutos, vuelva a hacer SSH en su servidor:

  • ssh freebsd@your_server_ip

PF es ahora su firewall activo. Puede asegurarse de que esté ejecutándose accediendo a algunos datos con la utilidad pfctl.

Vamos a ver algunas estadísticas y contadores con pfctl -si:

  • sudo pfctl -si

Pasará los indicadores -si, que significa mostrar info. Esta es una de las muchas combinaciones de parámetros de filtros que puede usar con pfctl para analizar datos sobre la actividad de su firewall.

Verá los siguientes datos tabulares (los valores variarán según el equipo):

Output
Status: Enabled for 0 days 00:01:53 Debug: Urgent State Table Total Rate current entries 5 searches 144 1.3/s inserts 11 0.1/s removals 6 0.1/s Counters match 23 0.2/s bad-offset 0 0.0/s fragment 0 0.0/s short 0 0.0/s normalize 0 0.0/s memory 0 0.0/s bad-timestamp 0 0.0/s congestion 0 0.0/s ip-option 0 0.0/s proto-cksum 0 0.0/s state-insert 0 0.0/s state-limit 0 0.0/s src-limit 0 0.0/s synproxy 0 0.0/s map-failed 0 0.0/s

Debido a que acaba de activar su conjunto de reglas, no verá aún mucha información. Sin embargo, este resultado muestra que PF ya registró 23 reglas que coinciden, lo cual significa que se hallaron 23 coincidencias para los criterios de su conjunto de reglas. El resultado también confirma que su firewall está funcionando.

Su conjunto de reglas también permite que el tráfico saliente acceda a algunos servicios críticos de Internet, incluyendo la utilidad ping.

Vamos a comprobar la conectividad a Internet y el servicio DNS con ping contra google.com:

  • ping -c 3 google.com

Ya que ejecutó el indicador de recuento -c 3, verá tres respuestas de conexión correcta:

Output
PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

Asegúrese de que puede acceder al repositorio pkgs con el siguiente comando:

  • sudo pkg upgrade

Si hay paquetes para actualizar, hágalo ahora.

Si ambos servicios están funcionando, significa que su firewall está activo y puede continuar. Aunque su conjunto de reglas preliminares ofrece protección y funcionalidad, sigue siendo un conjunto de reglas elemental y podría tener algunas mejoras. En las secciones restantes, completará su conjunto de reglas básico y usará algunas de las funciones avanzadas de PF.

Paso 3: Completar su conjunto de reglas básico

En este paso, creará a partir del conjunto de reglas preliminares para completar su conjunto de reglas básico. Reorganizará algunas de sus reglas y trabajará con conceptos más avanzados.

Incorporar macros y tablas

En su conjunto de reglas preliminares, ha predefinido el código de todos sus parámetros en cada regla, es decir, los números de los puertos que forman las listas. Esto puede ser muy difícil de administrar en el futuro, dependiendo de la naturaleza de sus redes. Con fines organizativos, PF incluye macros, listas y tablas. Ya incluyó las listas directamente en sus reglas, pero también puede separarlas de ellas y asignarlas a una variable usando macros.

Abra su archivo para transfefrir algunos de sus parámetros a macros:

  • sudo vi /etc/pf.conf

Ahora, añada el siguiente contenido a la parte superior del conjunto de reglas:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq }"
. . .

Modifique sus reglas SSH y ICMP anteriores con sus nuevas variables:

/etc/pf.conf
. . .
pass in on $vtnet0 proto tcp to port { 22 }
. . .
pass inet proto icmp icmp-type $icmp_types
. . .

Sus reglas SSH y ICMP anteriores ahora usan macros. Los nombres de variables se indican mediante la sintaxis del símbolo de dólar en PF. Asigna su interfaz vtnet0 a una variable con el mismo nombre solo como formalidad, lo que le ofrece la opción de cambiarle el nombre en el futuro si es necesario. Otros nombres comunes de variables para las interfaces de cara al público son $pub_if o $ext_if.

A continuación, implementará una tabla, que es similar a un macro, pero diseñada para albergar grupos de direcciones IP. Crearemos una tabla para las direcciones IP no enrutables, que a menudo juegan un papel en los ataques de denegación de servicio (DOS). Puede usar las direcciones IP especificadas en RFC6890, que define registros de direcciones IP con fines especiales. Su servidor no debería enviar o recibir paquetes a o desde estas direcciones a través de la interfaz de cara al público.

Cree esta tabla añadiendo el siguiente contenido directamente bajo el macro icmp_types:

/etc/pf.conf
. . .
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }
. . .

Ahora, añada sus reglas para la tabla <rfc6890> debajo de la regla set skip on lo0:

/etc/pf.conf
. . .
set skip on lo0
block in quick on egress from <rfc6890>
block return out quick on egress to <rfc6890>
. . .

Aquí introduce la opción return, que complementa su regla block out. Esto soltará los paquetes y enviará un mensaje RST al host que intentó realizar esas conexiones, lo que es útil para analizar la actividad del host. Luego, se añade la palabra clave egress, que automáticamente encuentra las rutas predeterminadas de cualquier interfaz concreta. Este es normalmente un método más limpio de encontrar rutas predeterminadas, especialmente con redes complejas. La palabra clave quick ejecuta las reglas de inmediato sin considerar el resto del conjunto de reglas. Por ejemplo, si un paquete con una dirección IP ilógica intenta establecer conexión con el servidor, le convendrá cortar la conexión de inmediato y no tendrá motivos para ejecutar ese paquete a través del conjunto de reglas restante.

Proteger sus puertos SSH

Ya que su puerto SSH está abierto al público, está sujeto a ataques. Una de las señales de aviso más obvias de un atacante es las cantidades masivas de intentos de inicio de sesión. Por ejemplo, si la misma dirección IP intenta iniciar sesión en su servidor 10 veces en un segundo, puede asumir que no se hizo con manos humanas, sino con un software informático que está intentando averiguar su contraseña de inicio de sesión. Estos tipos de vulneraciones de seguridad sistemáticas a menudo se denominan ataques por fuerza bruta y normalmente tienen éxito si las contraseñas del servidor son inseguras.

Advertencia: Recomendamos encarecidamente usar autenticación con clave pública en todos los servidores. Consulte el tutorial de DigitalOcean sobre la autenticación basada en claves.

PF tiene funciones integradas para lidiar con ataques por fuerza bruta o de tipo similar. Con PF puede limitar el número de intentos de conexión simultáneos permitidos por un único host. Si un host supera esos límites, la conexión se detendrá y se le prohibirá el acceso al servidor. Para conseguir esto, usará el mecanismo de sobrecarga de PF, que mantiene una tabla de direcciones IP baneadas.

Modifique su regla SSH anterior para limitar el número de conexiones simultáneas desde un host único como sigue:

/etc/pf.conf
. . .
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
. . .

Añade la opción keep state que le permite definir el criterio de estado para la tabla de sobrecarga. Se pasa el parámetro max-src-conn para especificar el número de conexiones simultáneas permitidas desde un único host por segundo y el parámetro max-src-conn-rate para especificar el número de nuevas conexiones permitidas desde un único host por segundo. Especifica 15 conexiones para max-src-conn y 3 conexiones para max-src-conn-rate. Si un host supera estos límites, el mecanismo overload añade el IP de origen a la tabla <bruteforce>, que prohíbe las conexiones desde el servidor. Finalmente, la opción flush global cierra la conexión.

Ha definido una tabla de sobrecarga en su regla SSH, pero no ha declarado esa tabla en su conjunto de reglas.

Añada la tabla <bruteforce> debajo de la macro icmp_types:

/etc/pf.conf
. . .
icmp_types = "{ echoreq }"
table <bruteforce> persist
. . .

La palabra clave persist permite que exista una tabla vacía en el conjunto de reglas. Sin ella, PF indicará que no hay direcciones IP en la tabla.

Estas medidas garantizan que su puerto SSH está protegido por un potente mecanismo de seguridad. PF le permite configurar soluciones rápidas para protegerse de formas de vulneraciones de seguridad catastróficas. En las siguientes secciones, dará los pasos para limpiar los paquetes a medida que llegan a su servidor.

Limpiar su tráfico

Nota: En las siguientes secciones se describen los fundamentos básicos de la suite de protocolos TCP/IP. Si planea crear aplicaciones web o redes, le convendrá dominar estos conceptos. Eche un vistazo al tutorial Introducción a la terminología, interfaces y protocolos de red de DigitalOcean.

Debido a la complejidad de la suite de protocolos TCP/IP, y a la perseverancia de actores maliciosos, los paquetes a menudo llegan con discrepancias y ambigüedades como fragmentos de IP que se solapan, direcciones IP fraudulentas, y mucho más. Es imperativo que limpie su tráfico antes de que entre en el sistema. El término técnico para este proceso es normalización.

Cuando los datos viajan por Internet, normalmente se desglosan en fragmentos más pequeños en el origen para acomodarse a los parámetros de transmisión del host de destino, donde se vuelven a montar en paquetes completos. Desafortunadamente, un intruso puede secuestrar este proceso de varias formas que van más allá del alcance de este tutorial. Sin embargo, con PF puede gestionar la fragmentación a través de una regla. PF incluye una palabra clave scrub que normaliza los paquetes.

Añada la palabra clave scrub directamente antes de su regla block all:

/etc/pf.conf
. . .
set skip on lo0
scrub in all fragment reassemble max-mss 1440
block all
. . .

Esta regla realiza una limpieza de todo el tráfico entrante. Incluye la opción fragment reassemble para evitar el ingreso de fragmentos en el sistema. En vez de eso, se almacenan en la memoria caché hasta que se vuelvan a ensamblar en paquetes completos, lo cual significa que sus reglas de filtro solo tendrán que tratar con paquetes uniformes. También incluye la opción max-mss 1440 que representa el tamaño máximo del segmento de los paquetes TCP reesamblados, también conocida como carga útil. Especifica un valor de 1440 bytes, que consigue un equilibrio entre tamaño y rendimiento, dejando suficiente espacio para los encabezados.

Otro aspecto importante de la fragmentación es un término conocido como la unidad de transmisión máxima (MTU). Los protocolos TCP/IP permiten a los dispositivos negociar tamaños de paquetes para realizar conexiones. El host de destino utiliza mensajes ICMP para informar a la IP de origen de su MTU, un proceso conocido como descubrimiento de ruta MTU. El tipo de mensaje ICMP específico es el destination unreachable (destino inalcanzable). Habilitará el descubrimiento de la ruta MTU añadiendo el tipo de mensaje unreach a su lista icmp_types.

Usará la MTU predeterminada de su servidor de 1500 bytes, que puede determinarse con el comando ifconfig:

  • ifconfig

Verá el siguiente resultado que incluye su MTU actual:

Output
vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=6c07bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6> . . .

Actualice la lista icmp_types para incluir el tipo de mensaje destination unreachable:

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach}"
. . .

Ahora que tiene las políticas implementadas para gestionar la fragmentación, los paquetes que entren en su sistema serán uniformes y consistentes. Esto es deseable porque hay muchos dispositivos intercambiando datos en Internet.

Ahora trabajará para evitar otro problema de seguridad conocido como spoofing de IP. Los atacantes a menudo cambian sus IP de origen para que parezca que residen en un nodo confiable en una organización. PF incluye una directiva antispoofing para gestionar las IP de origen falsificadas. Cuando se aplica a una interfaz específica, el antispoofing bloquea todo el tráfico de la red de esa interfaz (a menos que se origine desde esa interfaz). Por ejemplo, si aplica antispoofing a una interfaz que reside en 5.5.5.1/24, el tráfico desde la red de 5.5.5.0/24 no puede comunicarse con el sistema a menos que se origine desde esas interfaces.

Añada el siguiente contenido resaltado para aplicar antispoofing a su interfaz vtnet0:

/etc/pf.conf
. . .
set skip on lo0
scrub in
antispoof quick for $vtnet0
block all
. . .

Guarde el archivo y ciérrelo.

Esta regla de antispoofing establece que el tráfico de las redes vtnet0 solo puede pasar a través de la interfaz de vtnet0 o se desconectará rápidamente con la palabra clave quick. Los agentes maliciosos no podrán ocultarse en la red de vtnet0 y comunicarse con otros nodos.

Para demostrar su regla de antispoofing, imprimirá su conjunto de reglas en la pantalla en su formato detallado. Las reglas en PF se escriben normalmente en formato acortado, pero la escritura de estas también es posible en formato detallado. Normalmente es poco práctico escribir las reglas de ese modo, pero para realizar pruebas puede ser útil.

Imprima el contenido de /etc/pf.conf usando pfctl con el siguiente comando:

  • sudo pfctl -nvf /etc/pf.conf

Este comando pfctl toma los indicadores -nvf, que imprimen el conjunto de reglas y lo prueba sin cargar nada; se conoce también como simulacro. Verá todo el contenido de /etc/pf.conf en su formato detallado.

Verá algo similar al siguiente resultado en la parte antispoofing:

Output
. . . block drop in quick on ! vtnet0 inet from your_server_ip/20 to any block drop in quick on ! vtnet0 inet from network_address/16 to any block drop in quick inet from your_server_ip to any block drop in quick inet from network_address to any block drop in quick on vtnet0 inet6 from your_IPv6_address to any . . .

Su regla antispoofing descubrió que es parte de la red your_server_ip/20. También detectó que (para el ejemplo de este tutorial) el servidor es parte de una red network_address/16, y tiene direcciones IPv6 adicionales. Antispoofing bloquea todas estas redes para que no se comuniquen con el sistema, a menos que su tráfico pase a través de la interfaz vtnet0.

Su regla de antispoofing es la última adición a su conjunto de reglas básico. En el siguiente paso, iniciará estos cambios y realizará algunas pruebas.

Paso 4: Probar su conjunto de reglas básico

En este paso revisará y probará su conjunto de reglas básico para garantizar que todo funciona adecuadamente. Es mejor evitar implementar demasiadas reglas a la vez sin probarlas. Una buena práctica es empezar con las esenciales, aumentar de forma incremental y realizar una copia de seguridad del trabajo cuando se realizan cambios en la configuración.

Este es su conjunto de reglas básico completo:

Base Ruleset /etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Asegúrese que su archivo /etc/pf.conf es idéntico al del conjunto de reglas básico completo aquí antes de continuar. Guarde el archivo y ciérrelo.

Su conjunto de reglas básico completo le ofrece:

  • Una colección de macros que pueden definir servicios y dispositivos clave.
  • Políticas de higiene de la red para abordar la fragmentación de paquetes y las direcciones IP ilógicas.
  • Una estructura de filtrado de default deny que bloquea todo y permite solo lo que usted especifique.
  • Acceso SSH entrante con límites sobre el número de conexiones simultáneas que puede realizar un host.
  • Políticas de tráfico saliente que le proporciona acceso a algunos servicios críticos de Internet.
  • Las políticas ICMP que proporciona acceso a la utilidad ping y el descubrimiento de ruta MTU.

Ejecute el siguiente comando pfctl para realizar un simulacro:

  • sudo pfctl -nf /etc/pf.conf

Se pasan los indicadores -nf que le solicitan a pfctl ejecutar el conjunto de reglas sin cargarlo, lo que generará errores si algo incorrecto.

Ahora, una vez que no se encuentren errores, cargue el conjunto de reglas:

  • sudo pfctl -f /etc/pf.conf

Si no hay errores, significa que su conjunto de reglas básico está activo y funciona correctamente. Como antes en el tutorial, realizará algunas pruebas en su conjunto de reglas.

Primero pruebe la conectividad a Internet y su servicio DNS:

  • ping -c 3 google.com

Verá lo siguiente:

Output
PING google.com (172.217.0.46): 56 data bytes 64 bytes from 172.217.0.46: icmp_seq=0 ttl=56 time=2.088 ms 64 bytes from 172.217.0.46: icmp_seq=1 ttl=56 time=1.469 ms 64 bytes from 172.217.0.46: icmp_seq=2 ttl=56 time=1.466 ms --- google.com ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 1.466/1.674/2.088/0.293 ms

A continuación, compruebe que puede llegar al repositorio pkgs:

  • sudo pkg upgrade

Una vez más, actualice los paquetes si es necesario.

Finalmente, reinicie su servidor:

  • sudo reboot

Dé unos minutos a su servidor para que se reinicie. Completó e implementó su conjunto de reglas básico, lo cual es un paso significativo en términos de su progreso. Ahora estará listo para explorar algunas de las funciones avanzadas de PF. En el siguiente paso impedirá ataques de fuerza bruta.

Paso 5: Gestionar su tabla de sobrecarga

Con el tiempo, la tabla de sobrecarga <bruteforce> se llenará de direcciones IP maliciosas deberá limpiarse periódicamente. Es improbable que un atacante siga usando la misma dirección IP, de forma que no merece la pena almacenarlas en la tabla de sobrecarga durante largos periodos de tiempo.

Usará pfctl para borrar manualmente todas las direcciones IP que hayan sido almacenadas en la tabla de sobrecarga durante 48 horas o más con el siguiente comando:

  • sudo pfctl -t bruteforce -T expire 172800

Verá un resultado similar a este:

Output
0/0 addresses expired.

Se pasan el indicador -t bruteforce, que significa fuerza bruta para tabla, y el indicador -T, que le permite ejecutar varios comandos integrados. En este caso, ejecuta el comando expire para borrar todas las entradas de -t bruteforce, con un valor de tiempo representado en segundos. Ya que está trabajando en un nuevo servidor, probablemente no haya direcciones IP en la tabla de sobrecarga aún.

Esta regla funciona para correcciones rápidas, pero una solución más robusta sería automatizar el proceso con el programador de trabajo cron, de FreeBSD. Vamos a crear una secuencia de comandos shell que ejecute esta secuencia de comandos.

Cree un archivo de secuencia de comandos shell en el directorio /usr/local/bin:

  • sudo vi /usr/local/bin/clear_overload.sh

Añada el siguiente contenido a su secuencia de comandos shel:

/usr/local/bin/clear_overload.sh
#!/bin/sh

pfctl -t bruteforce -T expire 172800

Haga que el archivo sea ejecutable con el siguiente comando:

  • sudo chmod 755 /usr/local/bin/clear_overload.sh

A continuación, creará un trabajo cron. Hay trabajos que se ejecutarán repetitivamente según el momento que especifique. Se utilizan comúnmente para las copias de seguridad o para cualquier proceso que deba ejecutarse al mismo tiempo cada día. Crea trabajos cron con los archivos crontab. Consulte las páginas principales para obtener más información sobre cron(8) y crontab(5).

Cree un archivo crontab con usuario root con el siguiente comando:

  • sudo crontab -e

Ahora añada el siguiente contenido al archivo crontab:

crontab
# minute    hour    mday    month   wday    command

  *             0     *       *     *     /usr/local/bin/clear_overload.sh

Guarde el archivo y ciérrelo.

Nota: Alinee todos los valores con su tabla correspondiente para mayor legibilidad si no se alinean adecuadamente cuando añada contenido.

Este trabajo cron ejecuta la secuencia de comandos clear_overload.sh cada día a medianoche, eliminando las direcciones UP que tienen una antigüedad de 48 horas de la tabla de sobrecarga <bruteforce>. A continuación, añadirá anclajes a su conjunto de reglas.

Paso 6: Introducir anclajes a sus conjuntos de reglas

En este paso, introducirá anclajes, que se usan para aprovisionar reglas al conjunto de reglas principal, ya sea manualmente o desde un archivo de texto externo. Los anclajes pueden contener fragmentos de reglas, tablas e incluso otros anclajes, conocidos como anclajes anidados. Demostraremos la forma en que funcionan los anclajes añadiendo una tabla a un archivo externo y proporcionándolo a su conjunto de reglas. Su tabla incluirá un grupo de hosts internos cuya conexión con el mundo exterior desee impedir.

Cree un archivo llamado /etc/blocked-hosts-anchor:

  • sudo vi /etc/blocked-hosts-anchor

Añada el siguiente contenido al archivo:

/etc/blocked-hosts-anchor
table <blocked-hosts> { 192.168.47.1 192.168.47.2 192.168.47.3 }

block return out quick on egress from <blocked-hosts>

Guarde el archivo y ciérrelo.

Estas reglas declaran y definen la tabla <blocked-hosts>, y luego impiden que todas las direcciones IP de la tabla <blocked-hosts> accedan a los servicios del mundo exterior. Utiliza la palabra egress como método preferido para encontrar la ruta predeterminada, o salida a Internet.

Aún deberá declarar el anclaje en su archivo /etc/pf.conf:

  • sudo vi /etc/pf.conf

Ahora, añada las siguientes reglas de anclajes después de la regla block all:

/etc/pf.conf
. . .
block all
anchor blocked_hosts
load anchor blocked_hosts from "/etc/blocked-hosts-anchor"
. . .

Guarde el archivo y ciérrelo.

Estas reglas declaran los blocked_hosts y cargan las reglas de anclajes en su conjunto de reglas principal desde el archivo /etc/blocked-hosts-anchor.

Ahora, inicie estos cambios volviendo a cargar su conjunto de reglas con pfctl:

  • sudo pfctl -f /etc/pf.conf

Si no hay errores, significa que no hay errores en su conjunto de reglas y sus cambios está activos.

Utilice pfctl para verificar que su anclaje se está ejecutando:

  • sudo pfctl -s Anchors

El indicador -s Anchors significa “mostrar anclajes ”. Verá el siguiente resultado:

Output
blocked_hosts

La utilidad pfctl puede también analizar las reglas específicas de su anclaje con los indicadores -a y -s:

  • sudo pfctl -a blocked_hosts -s rules

Verá lo siguiente:

Output
block return out quick on egress from <blocked-hosts> to any

Otra función de los anclajes es que permiten añadir reglas bajo demanda sin tener que volver a carga el conjunto de reglas. Esto puede ser útil para realizar pruebas, reparaciones rápidas, emergencias, etc. Por ejemplo, si un host interno está actuando de forma peculiar y desea impedir que realice conexiones salientes, tiene un anclaje puesto que le permite intervenir rápidamente desde la línea de comandos.

Vamos a abrir /etc/pf.conf y añadir otro anclaje:

  • sudo vi /etc/pf.conf

Llamará al delmitador rogue_hosts y lo dispondrá en la regla block all:

/etc/pf.conf
. . .
block all
anchor rogue_hosts
. . .

Guarde el archivo y ciérrelo.

Para iniciar estos cambios, vuelva a cargar el conjunto de reglas con pfctl:

  • sudo pfctl -f /etc/pf.conf

De nuevo, utilice pfctl para verificar que el anclaje se esté ejecutando:

  • sudo pfctl -s Anchors

Esto generará el siguiente resultado:

Output
blocked_hosts rogue_hosts

Ahora que el anclaje se está ejecutando, podrá añadirle reglas en cualquier momento. Pruebe esto añadiendo la siguiente regla:

  • sudo sh -c 'echo "block return out quick on egress from 192.168.47.4" | pfctl -a rogue_hosts -f -'

Esto invoca el comando echo y el contenido de su cadena, que luego se canaliza a la utilidad pfctl con el símbolo |, donde se procesa en otra regla de anclaje. Puede abrir otra sesión shell con el comando sh-c. Esto es porque establece un canal entre dos procesos, pero necesita privilegios sudo para que persistan en toda la secuencia de comandos. Existen varias formas de resolver esto; aquí abre un proceso shell adicional con privilegios sudo usando sudo sh -c.

Ahora, utilice pfctl de nuevo para verificar que estas reglas está activas:

  • sudo pfctl -a rogue_hosts -s rules

Esto generará el siguiente resultado:

Output
block return out quick on egress inet from 192.168.47.4 to any

El uso de anclajes es completamente circunstancial y a menudo subjetivo. Igual que cualquier otra función, existen pros y contras a la hora de usar los anclajes. Algunas aplicaciones, como blacklistd interactúan con anclajes debido a su diseño. A continuación, centrará la atención en el registro con PF, que es un aspecto crítico de seguridad de la red. Su firewall no es útil si no puede ver lo que hace.

Paso 7: Registro de la actividad de su firewall

En este paso, trabajará con el registro de PF, que se gestiona mediante una pseudo interfaz llamada pflog. El registro se habilita en el momento del inicio añadiendo pflog_enabled=YES al archivo /etc/rc.conf, procedimiento que completó en el paso 2. Esto habilita el demonio pflogd que abre una interfaz llamada pflog0 y escribe registros en formato binario en un archivo llamado /var/log/pflog. Los registros pueden analizarse en tiempo real desde la interfaz, o ser leídos desde el archivo /var/log/pflog con la utilidad tcpdump(8).

Primero acceda a algunos registros desde el archivo /var/log/pflog:

  • sudo tcpdump -ner /var/log/pflog

Pasa los indicadores -ner que formatean el resultado para mejorar la legibilidad, y también especifica un archivo desde el que leer, que en su caso es /var/log/pflog.

Verá lo siguiente:

Output
reading from file /var/log/pflog, link-type PFLOG (OpenBSD pflog file)

En estas etapas tempranas es posible que no haya datos en el archivo /var/log/pflog. En poco tiempo, el archivo de registro comenzará a ampliarse.

También puede ver los registros en tiempo real desde la interfaz pflog0 usando el siguiente comando:

  • sudo tcpdump -nei pflog0

Pasa los indicadores -nei, que también formatean el resultado para mejorar la legibilidad, pero esta vez especifica una interfaz, que en su caso es pflog0.

Verá lo siguiente:

Output
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 262144 bytes

Ahora verá las conexiones en tiempo real. Si es posible, haga ping a su servidor desde un equipo remoto y verá cómo se producen las conexiones. El servidor permanecerá en este estado hasta que salga de él.

Para salir de este estado y volver a la línea de comandos, pulse CTRL + Z.

Hay mucha información en Internet sobre tcpdump(8). También se puede acceder al sitio web oficial.

Acceder a los archivos de registro desde pftop

La utilidad pftop es una herramienta que permite ver rápidamente la actividad del firewall en tiempo real. Su nombre se ve influenciado por la conocida utilidad top de Unix.

Para usarlo, deberá instalar el paquete pftop:

  • sudo pkg install pftop

Ahora ejecute el binario pftop:

  • sudo pftop

Esto generará el siguiente resultado (sus IP serán diferentes):

Output
PR DIR SRC DEST STATE AGE EXP PKTS BYTES tcp In 251.155.237.90:27537 157.225.173.58:22 ESTABLISHED:ESTABLISHED 00:12:35 23:59:55 1890 265K tcp In 222.186.42.15:25884 157.225.173.58:22 TIME_WAIT:TIME_WAIT 00:01:25 00:00:06 22 3801 udp Out 157.245.171.59:4699 67.203.62.5:53 MULTIPLE:SINGLE 00:00:14 00:00:16 2 227

Crear interfaces de registro adicionales

Como cualquier otra interfaz, pueden crearse múltiples interfaces de registro y nombrarse con un archivo /etc/hostname. Es posible que encuentre esto útil con fines organizativos, por ejemplo, si desea registrar ciertos tipos de actividad por separado.

Cree una interfaz de registro adicional llamada pflog1:

  • sudo vi /etc/hostname.pflog1

Añada el siguiente contenido al archivo /etc/hostname.pflog1:

/etc/hostname.pflog1
up

Ahora, habilite el dispositivo en el momento del inicio en su archivo /etc/rc.conf:

  • sudo sysrc pflog1_enable="YES"

Puede monitorizar y registrar la actividad de su firewall. Esto le permite ver quién establece conexiones con su servidor y los tipos de conexiones establecidas.

A lo largo de este tutorial, ha incorporado algunos conceptos avanzados a su conjunto de reglas de PF. Solo es necesario implementar las funciones avanzadas a medida que las necesite. Dicho esto, en el siguiente paso volverá al conjunto de reglas básico.

Paso 8: Restablecer el conjunto de reglas básico

En esta sección final, restablecerá su conjunto de reglas básico. Este es un paso rápido que le llevará de nuevo a un estado minimalista de la funcionalidad.

Abra el conjunto de reglas básico con el siguiente comando:

  • sudo vi /etc/pf.conf

Elimine el conjunto de reglas actual en su archivo y sustitúyalo con el siguiente conjunto de reglas básico.

/etc/pf.conf
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Guarde el archivo y ciérrelo.

Vuelva a cargar el conjunto de reglas:

  • sudo pfctl -f /etc/pf.conf

Si no hay errores en el comando, significa que no hay errores en su conjunto de reglas y su firewall está funcionando correctamente.

También deberá desactivar la interfaz pflog1 que ha creado. Ya que es posible que no sepa si lo necesita aún, puede deshabilitar pflog1 con la utilidad sysrc:

  • sudo sysrc pflog1_enable="NO"

Ahora, elimine el archivo /etc/hostname.pflog1 del directorio /etc:

  • sudo rm /etc/hostname.pflog1

Antes de salir, reinicie el servidor una vez más para garantizar que todos sus cambios estén activos y sean persistentes:

  • sudo reboot

Espere unos minutos antes de iniciar sesión en su servidor.

Opcionalmente, si desea implementar PF con un servidor web, el siguiente es un conjunto de reglas para este escenario. Este conjunto de reglas es un punto de inicio suficiente para la mayoría de las aplicaciones web.

Simple Web Server Ruleset
vtnet0 = "vtnet0"
icmp_types = "{ echoreq unreach }"
table <bruteforce> persist
table <webcrawlers> persist
table <rfc6890> { 0.0.0.0/8 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16          \
                  172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.2.0/24 192.88.99.0/24    \
                  192.168.0.0/16 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24            \
                  240.0.0.0/4 255.255.255.255/32 }

set skip on lo0
scrub in all fragment reassemble max-mss 1440
antispoof quick for $vtnet0
block in quick on $vtnet0 from <rfc6890>
block return out quick on egress to <rfc6890>
block all
pass in on $vtnet0 proto tcp to port { 22 } \
    keep state (max-src-conn 15, max-src-conn-rate 3/1, \
        overload <bruteforce> flush global)
pass in on $vtnet0 proto tcp to port { 80 443 } \
    keep state (max-src-conn 45, max-src-conn-rate 9/1, \
        overload <webcrawlers> flush global)
pass out proto { tcp udp } to port { 22 53 80 123 443 }
pass inet proto icmp icmp-type $icmp_types

Esto crea una tabla de sobrecarga llamada <webcrawlers>, que tiene una política de sobrecarga más liberal que su puerto SSH según los valores de max-src-conn 45 y max-src-conn-rate. Esto es porque no todas las sobrecargas corresponden a agentes maliciosos. También pueden originarse de netbots no maliciosos, de forma que evite medidas de seguridad excesivas en los puertos 80 y 443. Si decide implementar el conjunto de reglas del servidor web, deberá añadir la tabla <webcrawlers> a /etc/pf.conf y borrar las IP de la tabla periódicamente. Consulte el Paso 5 para hacer esto.

Conclusión

A través de este tutorial, configuró PF en FreeBSD 12.1. Ahora dispondrá de un conjunto de reglas básico que puede servir como punto de inicio para todos sus proyectos de FreeBSD. Para obtener más información sobre PF, eche un vistazo a las páginas man de pf.conf(5).

Visite nuestra página sobre el tema FreeBSD para ver más tutoriales y Preguntas y respuestas.

Creative Commons License