Portknocking para Windows: Instalación de sig2knock

Introduccion

El portknocking es un método por el que podemos establecer comunicación con un ordenador que no tenga ningún puerto abierto. Antes de establecer realmente la conexión, se contacta con una determinada cantidad de puertos (en un orden establecido) mediante una serie de llamadas (port knock), que no son otra cosa que intentos de conexión con puertos cerrados. El host remoto genera y envía una secuencia válida de llamadas con el objetivo de manipular (modificar) las reglas del firewall del servidor y así abrir uno, o más, puertos específicos. Estas manipulaciones (modificaciones) son realizadas por el demonio del port knock, que corre en el servidor, el cual monitoriza (vigila) el log del firewall a la búsqueda de intentos de conexión que puedan ser secuencias auténticas de port knock (llamadas). Una vez que los puertos deseados están abiertos, el host remoto puede establecer la conexión e iniciar sesión. El puerto, abierto de este modo, será cerrado posteriormente mediante otra secuencia de llamadas.

El uso de este método dependerá de la cantidad de usuarios que puedan concurrir en el uso del sistema. Un ejemplo ideal para implementar el portknocking es en la administración remota de un servidor mediante conexiones SSH. Por el contrario, su uso para limitar, controlar o el acceso a un servidor web no sería muy adecuado.

En este documento vamos a tratar la instalación y configuración de sig2knock, una de las implementaciones de PortKnocking que hay disponibles. ¿Y por qué esta? Pués porque la mayoría de ellas, esta incluida, están pensadas para los sistemas Linux/Unix y, a priori, la cantidad de información para instalarlo en estos sistemas es abundante, porque la documentación sobre cómo montarlo en Windows no lo es demasiado (o yo no la he encontrado) y, sobre todo, porque me apetecía 🙂 Quizás algunos hubierais tirado directamente por SAdoor pero mis conocimientos no llegan a tanto .

Debido a que:

  • durante el proceso de PortKnock, el servidor debe poder abrir el puerto asignado al cliente, añadiendo una nueva reglas a las existentes en la configuración del Firewal
  • sig2knock está pensado para interactuar con IPTables (Linux/Unix) y con PktFilter (Windows)
  • y que este manual está pensado para entornos Windows

el paso siguiente es instalar y configurar PktFilter en el servidor.

Instalación de PktFilter

Vamos a la web oficial, nos descargamos la útima versión de PktFilter y descomprimimos el fichero en una carpeta (paso[1]). Acto seguido, vamos a la web de sig2knock, descargamos el fichero del servidor y lo descomprimimos en otra carpeta (paso[2]).

A continuación, movemos el contenido de la carpeta del paso [1] a la carpeta del paso[2], esto es: movemos el pktfilter a la misma carpeta del servidor del sig2knock. Esto es así porque este último necesita añadir nuevas reglas al Firewall y ha de saber donde está este instalado. Otra opción sería no mover el PktFilter a la carpeta de Sig2knock y añadir la carpeta la carpeta de instalación del PktFilter al PATH del sistema.

Instalamos el pktfilter como servicio (por que queremos tener el Firewall siempre activo, no?) Para ello, abrimos la consola de Windows, nos movemos hasta la carpeta del PktFilter y escribimos:

pktfltsrv -i "ruta_al_fichero_de_reglas" "ruta_al_fichero_de_bloqueos_del_firewall"

donde ruta_al_fichero_de_reglas indica la ruta completa al fichero con contiene las reglas del firewall y ruta_al_fichero_de_bloqueos_del_firewall es la ruta completa al fichero log donde guardamos los eventos del firewall.

Siguiendo las indicaciones del manual de PktFilter, configuramos las reglas del firewall para lo cual nos vale con el fichero de ejemplo más esta línea añadida:

pass out on eth0 proto udp from 192.168.0.112 to any

para permitir el envio de paquetes UDP por parte del servidor a cualquier cliente (esta regla la puedes modificar para restringir que el cliente sea un único equipo, uno que forme parte de una red o cualquiera). La configuración minima del firewall debe ser, suponiendo de que sólo tengas una interfaz de red o, de tener varias, uses la primera (eth0):

option small_frags on eth0
block in on eth0 all
block out on eth0 all
pass out on eth0 proto udp from 192.168.0.112 to any

Ahora que ya tenemos configurado el firewall, arrancamos PktFilter bien mediante el panel de servicios (al que podemos acceder tecleando "services.msc" en la consola) o mediante la sentencia "net start pktfilter".

Nota: por favor, lee la documentación que viene con PktFilter para que entiendas bien cómo funciona este firewall.

Instalación de sig2knock

Esta implementación del portknocking funciona del siguiente modo

  1. el cliente manda un paquete UDP, P1, encriptado con el hash de la contraseña de usuario donde envía una secuencia adelatoria de puertos.
  2. el servidor recibe el paquete, lo desencripta (usando la contraseña de usuario que conoce, ya que dispone de un fichero de usuarios/contraseñas -debidamente protegido-) y se queda a la espera.
  3. el cliente manda la secuencia de llamadas confirmada
  4. el cliente envía un paquete UDP encriptado, P2, para confirmar el estado del port knock
  5. Después de recibir la secuencia correcta y el paquete P2, el servidor envía el paquete P3 (que no es otra cosa que un paquete UDP, encriptado con la contraseña del usuario, que contiene el puerto asignado para la comunicación).
  6. Después de recibir el paquete P3, el cliente puede conectarse al puerto asignado.

El servidor únicamente aceptará conexiones al puerto asignado para el cliente que ha solicitado el port knock (identificado por su IP) y las renviará a la IP y puerto especificado en el fichero de configuración del servidor de portknock. Cualquier otra llamada será bloqueada. Podéis ver un esquema en la Figura.1

Esquema del proceso
Figura.1 – Esquema del proceso de Port Knock en la implementación de sig2knock.

Ahora que ya entendemos cómo funciona sig2knock pasamos a configurarlo. Descargamos de la web de sig2knock el manual, el cliente, el servidor y descomprimimos el fichero que contiene el servidor. El proceso de configuración es rápido, ya que sólo hemos de modificar dos documentos: user.txt y sig2knockd.conf. El primero, user.txt, es el fichero que contiene los datos de los usuarios que podrán conectarse al servidor via portknock (está de más decir que este fichero ha de estar fuera del alcance de cualquiera, sólo los administradores deben tener acceso a él). El segundo, sig2knockd.conf contiene:

	
UDP_PORT = 1001	  
FORWARD_TO_IP = 192.168.0.112
FORWARD_TO_PORT = 2121
SINGLECONN_PORTOPEN_TIME = 190
PKTFILTER_INTERFACE = eth0

donde

  • UDP_PORT es el puerto UDP en el que el servidor quedará a la escucha
  • FORWARD_TO_IP es la IP a la que reenviará la comunicación una vez sea establecidad la conexión
  • FORWARD_TO_PORT es el puerto al que reenviará la comunicación una vez sea establecidad la conexión
  • SINGLECONN_PORTOPEN_TIME indica el tiempo que estará disponible el puerto abierto por el servidor en el caso de una secuencia de llamadas correcta (después de este tiempo, el puerto será cerrado de nuevo)
  • PKTFILTER_INTERFACE es el identificador de la tarjeta de red (parámetro opcional que hemos de indicar sólo si tenemos instalado PktFilter)

Después de haber configurado el servidor con nuestros datos, pasamos a crear los usuarios que podrán acceder. Para ello disponemos de la aplicación sig2knockd_useradd, en línea de comandos, que mediante la introduccción de un usuario, y su contraseña, nos generará una cadena que hemos de añadir al fichero "user.txt".
Sencillo, no? Pués ahora que ya tenemos un usuario arrancamos el servidor de portknocking, que desde la línea de comandos sería:

sig2knockd -i ID_TARJETA_RED

donde ID_TARJETA_RED es el identificador de la tarjeta de red. En nuestro caso la línea queda así:

sig2knockd -i 1

Ahora que ya tenemos el servidor a la espera de conexiones, Figura.2, vamos al host cliente y nos conectamos. Para ello escribimos:

sig2knockc IP_SERVIDOR PUERTO

donde

  • IP_SERVIDOR es la IP del Servidor
  • PUERTO es el puerto UDP del servidor al queremos conectarnos

Para nuestro ejemplo quedaría de esta manera:

sig2knockc 192.168.0.112 1001

La secuencia en imágenes de todo el proceso de conexión es la siguiente:

Servidor de portknocking a la espera de conexiones
Figura.2 – Servidor de Port Knocking a la espera de conexiones

Cliente de portknocking iniciando una conexion
Figura.3 – Cliente de portknocking iniciando y estableciendo una conexión.

Servidor de portknocking aceptando una conexión
Figura.4 – Servidor de Port Knocking aceptando la conexión

Como véis en las imágenes, el servidor ha abierto el puerto 30523 para el usuario kiu que se intenta conectar desde la IP 192.168.0.115. Desde este momento, kiu tiene 190 segundos para conectarse al servidor.

Un ejemplo práctico podría ser un servidor SSH aceptando únicamente conexiones en el puerto 22 de la interfaz local (127.0.0.1). Delante del Firewall podríamos tener el servidor de PortKnocking con esta configuración:

	
	UDP_PORT = 58085  
	FORWARD_TO_IP = 127.0.0.1
	FORWARD_TO_PORT = 22
	SINGLECONN_PORTOPEN_TIME = 30
	PKTFILTER_INTERFACE = eth0
	

Fallos y problemas

Para ser completamente sinceros os diré que este montaje fue entre dos máquinas con Windows 2000 Server Sp4 y funcionó en los dos sentidos (intercambiando quién hacía de cliente y quién de servidor). Pero cuando lo intenté sobre dos Windows Xp Prof. Sp2 las cosas no salieron tan bien. El cliente no conseguía iniciar la secuencia de llamada dando el error Error: RAW socket sendto() error Lo único que he encontrado en la web del sig2knock es donde hablan de bugs conocidos. En ella dicen:

After sending packet P2, the client expects to receive packet P3 back from the server. At this point, since the server is not listening on any UDP ports, its IP stack will send out a ICMP port unreachable packet to the client. As a result, the client will receive the ICMP port unreachable packet first before receiving P3. This will cause the recv() operation on the client to fail with -1. The consequence is that the client will not be able to receive P3 from the server and the user will not know the random port that the server assigns.
This will be fixed in the next version by modifying the client to receive P3 packets using RAW socket instead of normal sockets. In the meantime, the workaround is to install a packet filter on the server that prevents the IP stack from sending out the ICMP port unreachable packet.

Lo que viene a significar más o menos:

Después de mandar el paquete P2, el cliente espera recibir el paquete P3 desde el servidor. En este punto, si el servidor no está escuchando en ningún puerto UDP, su pila IP enviará un paquete saliente ICMP de puerto inalcanzable al cliente. Como resultado, el cliente recibe el paquete ICMP de puerto inalcanzable antes de recibir el P3. Esto provoca que la operación recv() falle con -1. Como consecuencia el cliente no recibirá P3 desde el servidor y el usuario no sabrá el puerto aleatorio que el servidor le ha asignado.

Todo esto será solventado en la próxima versión modificando el cliente para que reciba los paquetes P3 use sockets RAW en lugar de sockets normales. Mientras tanto, es conveniente instalar un filtro de paquetes en el servidor para prevenir el envío del paquete ICMP de puerto inalcanzable.

Pero en mi caso el error me lo daba después del envio del primer paquete de la secuencia de llamadas, antes de P2 no después de P2. Revisaré por si, a pesar de deshabilitar el Firewall Sygate que tenía instalado antes de montar todo el escenario e instalar PktFilter, realmente el puerto UDP no estubiera disponible en el servidor.