El golpeo de puertos (del inglés port knocking) es un mecanismo para abrir puertos externamente en un sistema de control de acceso, normalmente un firewall, mediante una secuencia de “golpes”. Normalmente esos golpes son intentos de conexión a puertos que se encuentran cerrados en un orden determinado. Una vez que el sistema encargado de controlar ese port knocking recibe una secuencia de conexión correcta, las reglas del cortafuegos son modificadas para permitir algo, normalmente la conexión a un puerto que antes estaba cerrado.
El propósito principal del golpeo de puertos es prevenir mostrar puertos abiertos por razones de seguridad. Como los mismos solo se abren ante un golpeo de puertos correcto, normalmente los puertos donde se brindan los servicios se muestran aparentemente cerrados.
Por lo general este mecanismo de golpeo de puertos se implementa configurando un servicio para que revise la bitácora o log del firewall para detectar esta secuencia de intentos de conexión. Otra forma es tener un proceso examinando paquetes con alguna interfaz de captura de paquetes, pero esto tiene que hacerse en puertos TCP que se encuentren “abiertos”.
Ya hay software dedicado para estos fines en casi todos los sistemas operativos, pero vamos a ver una forma simple y de andar por casa para implementar un port knocking que de acceso a un puerto concreto. Este se basará en ofrecer un servicio de proxy socks5 en el puerto 534, el cual solo estará abierto a las IPs que realicen bien el golpeo, que en el caso del ejemplo no será propiamente un golpeo, si no enviar una determinada cadena de texto un puerto concreto (servicio de SSH).
Servidor proxy Socks5 (Mirror 2).
# Descargar el script. wget wget "https://sourceforge.net/p/ssspl/code/HEAD/tree/sss.pl?format=raw" -O sss.pl chmod 755 sss.pl # Ejecutar el script para que escuche en todos los interfaces en el puerto 534. ./sss.pl 0.0.0.0 534 Process (14761) has entered into background.
Script knoking.sh (Se ejecuta mediante crond).
#!/bin/bash ############# CONFIG ############## port=534 # Puerto del servidor socks5. service_log="sshd.service" # Logs de sshd donde se buscará la string. payload="stallmanissexy\|XXXX" # La cadena que dará acceso al puerto 534 a la IP que la envíe. logfile=/var/log/proxy_knock.log # Logs del script. cron="2 minutes ago" # Espacio de tiempo donde se buscará la cadena de tecto en los logs de sshd. # La tarea crontab debe estar configurada para ejecutarse cada 2 minutos en este ejemplo. ################################## # Se obtiene la IP de la persona que ingreso la cadena de texto pertinen, en este caso "stallmanissexy" o "XXXX" ips=$( journalctl -u $service_log --since "$cron" | grep -i "from" | grep -i "$payload" | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort | uniq | paste -d',' -s) # Si hay una IP que ha enviado dicha cadena de texto, se abrirá el puerto pertinente para dicha IP, si ya existe, no se hace nada. if [ -n "$ips" ]; then /usr/sbin/iptables -C INPUT -p tcp -s $ips --dport $port -j ACCEPT || (/usr/sbin/iptables -I INPUT -p tcp -s $ips --dport $port -j ACCEPT && echo "$(date "+%x %H:%M:%S") ips $ips added." >> $logfile) fi
Tarea crontab.
# Cada dos minutos se ejecuta el script (mirar variable cron del script). */2 * * * * /root/proxy.sh
Realizar el port knocking
# Opción 1. ssh stallmanissexy@dominio.com # Opción 2. nc dominio.com 22 SSH-2.0-OpenSSH_7.4 stallmanissexy Protocol mismatch. # Opción 3. telnet dominio.com 22 Trying X.X.X.X... Connected to dominio.com Escape character is '^]'. SSH-2.0-OpenSSH_7.4 stallmanissexy Protocol mismatch. Connection closed by foreign host
Si todo ha salido bien, en menos de dos minutos iptables habrá abierto el acceso al puerto 534 a la IP que envío la cadena de texto “stallmanissexy”.