Comprueba la exposición externa de un servidor con curl

Comprueba la exposición externa de un servidor con curl

Una regla del firewall describe lo que debería permitirse; una conexión desde fuera comprueba qué responde de verdad. En un servidor con una IPv4 pública, puedes iniciar esa comprobación con curl -4 https://qsa.sh: qsa.sh detecta la IP de origen de la petición y escanea esa dirección desde su propia infraestructura.

El escaneo gratuito cubre los 1.000 puertos TCP principales, identifica servicios y versiones en los puertos abiertos y ejecuta comprobaciones de vulnerabilidades. No instala un agente ni requiere instalar herramientas en el servidor. El resultado es una primera lectura de la exposición, no una auditoría completa: compara sus hallazgos con las reglas de red y con lo que el servidor escucha localmente.

1. Ejecuta la orden desde el servidor

Conéctate al equipo que quieres revisar y ejecuta:

# Fuerza IPv4 para que qsa.sh acepte la conexión
curl -4 https://qsa.sh

La opción -4 fuerza IPv4. Es necesaria si el servidor también tiene IPv6: qsa.sh rechaza por ahora las conexiones de origen IPv6. El prefijo https:// cifra la petición; la variante HTTP también funciona, pero este tutorial usa HTTPS.

Antes de enviar paquetes, la herramienta muestra la IP detectada y empieza una cuenta atrás de 15 segundos para cancelar. Comprueba que la dirección corresponde al origen que pretendes revisar. Si no es la correcta, o no tienes autorización para escanearla, pulsa Ctrl-C: el escaneo no comienza.

El flujo es sencillo: la petición sale del servidor, qsa.sh identifica su IP pública y sus nodos de escaneo prueban esa dirección desde fuera. Los resultados vuelven a la terminal. No hay que introducir una IP de destino: se escanea la dirección desde la que llega la petición.

flowchart LR
    A["Servidor"] --> B["Petición curl por IPv4"]
    B --> C["qsa.sh detecta la IP"]
    C --> D["Cuenta atrás de 15 segundos"]
    D --> E["Escaneo externo autorizado"]
    E --> F["Resultados en la terminal"]

2. Guarda una copia legible del resultado

La salida predeterminada puede incluir colores. Para guardarla en un archivo de texto, solicita salida sin color y pásala a tee:

# Guarda la salida en un archivo fechado y también la muestra en pantalla
curl -4 -sN "https://qsa.sh/?nocolor=1" | tee "exposure-$(date +%F).txt"

-sN activa el modo silencioso de curl y desactiva el almacenamiento en búfer de la salida, de modo que los resultados transmitidos puedan mostrarse mientras llegan. El parámetro nocolor=1 evita los códigos de color en el archivo. La documentación de qsa.sh indica que los resultados del escaneo gratuito se transmiten y no se guardan en sus sistemas; este comando crea una copia local bajo tu control.

3. Lee qué cubre el escaneo

La salida gratuita reúne tres clases de resultados. Primero aparecen los puertos TCP que aceptaron una conexión desde la red de escaneo. Después, nmap intenta identificar el servicio y su versión, y el script vulners busca coincidencias con CVE conocidas a partir de esa cadena de versión. Por último, nuclei comprueba exposiciones y configuraciones, como rutas .env o .git, credenciales predeterminadas y problemas TLS.

Hay dos límites que conviene tener presentes al leerla. El escaneo gratuito prueba los 1.000 puertos TCP principales, no los 65.535; un servicio en un puerto que quede fuera de esa selección no aparecerá por ese motivo. Y una coincidencia de CVE basada en la versión detectada es una pista para verificar, no una confirmación de que el paquete instalado sea vulnerable: comprueba la versión corregida en el registro de seguridad de tu distribución antes de planificar una actualización.

La herramienta muestra los puertos, las versiones detectadas, un recuento por gravedad y los tres hallazgos principales completos. Si necesitas cubrir todos los puertos, qsa.sh ofrece opciones de pago con coberturas distintas; no hacen falta para la comprobación inicial de este tutorial.

4. Compara el resultado con los sockets locales

En el propio servidor, ejecuta ss para ver los sockets TCP en escucha:

# Muestra sockets TCP en escucha y el proceso asociado
sudo ss -tlnp

La lista local y el escaneo externo responden preguntas distintas. ss indica qué escucha en el equipo; el escaneo indica qué puertos TCP aceptaron conexiones desde la red externa de qsa.sh. Un socket enlazado a 0.0.0.0, [::] o * escucha en todas las interfaces, pero son las reglas de red y del host las que determinan si llega tráfico desde fuera.

Marca cada puerto abierto que no esperabas publicar y comprueba qué servicio lo ocupa. Si una regla del proveedor parece permitirlo o bloquearlo de forma distinta, revisa también dónde está aplicada y qué otras reglas actúan sobre el recurso. Por ejemplo, en AWS las reglas de los grupos de seguridad asociados se agregan; una regla antigua que permite el puerto puede seguir contando mientras ese grupo permanezca asociado.

5. Repite la comprobación desde otra máquina si hace falta

qsa.sh escanea únicamente la IP desde la que recibe la petición. No sirve para indicar otra dirección, revisar por separado un balanceador de carga ni comprobar la IPv6 de un servidor. Para esos casos, el artículo de qsa.sh propone ejecutar las herramientas de código abierto desde una máquina externa a la red del servidor y escanear solo direcciones que estés autorizado a probar.

En Debian o Ubuntu, instala las dependencias indicadas y las herramientas:

# Instala nmap y la dependencia libpcap
sudo apt install -y nmap libpcap-dev

# Instala naabu y nuclei con Go
 go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@latest
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

# Actualiza las plantillas de nuclei
nuclei -update-templates

El comando de instalación de Go presupone que tienes Go disponible y que los binarios instalados están en tu PATH. En el bloque anterior, elimina el espacio inicial antes de go install si tu terminal lo interpreta como parte de la orden.

Desde esa máquina externa, sustituye la dirección de ejemplo por la IPv4 pública que tienes autorización para revisar. Las tres órdenes reproducen las etapas de descubrimiento de puertos, identificación del servicio y comprobaciones de nuclei:

# Sustituye esta dirección de ejemplo por la IPv4 autorizada
TARGET=203.0.113.10

# Descubre los 1.000 puertos TCP principales
naabu -host "$TARGET" -top-ports 1000 -silent -o ports.txt

# Identifica los servicios y consulta coincidencias de CVE
nmap -Pn -sV --script vulners -p "$(cut -d: -f2 ports.txt | paste -sd, -)" "$TARGET"

# Ejecuta nuclei sobre los hosts y puertos encontrados
nuclei -l ports.txt -s critical,high,medium

La dirección 203.0.113.10 es un valor de ejemplo: cámbialo antes de ejecutar el bloque. Para intentar todos los puertos TCP con naabu, la referencia de qsa.sh indica cambiar -top-ports 1000 por -p -. La herramienta puede usar un escaneo SYN con privilegios de root y un escaneo CONNECT sin ellos.

Errores frecuentes al interpretar el resultado

La IP detectada es una pasarela NAT. Si el servidor sale a Internet por una pasarela NAT, qsa.sh ve la dirección pública de esa pasarela. En AWS, las instancias detrás de una pasarela NAT pública no reciben conexiones entrantes no solicitadas desde Internet. Por tanto, escanear esa IP describe la pasarela, no necesariamente la exposición entrante de la instancia. Identifica primero cuál es la dirección que recibe las conexiones que quieres revisar.

El servidor escucha, pero el puerto no aparece. Eso no demuestra por sí solo que no exista un servicio: la herramienta gratuita cubre los 1.000 puertos TCP principales, y las reglas de acceso pueden limitar quién llega al puerto. También pueden intervenir reglas del host, grupos o firewalls asociados al recurso y puertos publicados por contenedores. La discrepancia es una señal para revisar esas capas, no una razón para asumir que una de las dos vistas está equivocada.

Has comprobado IPv4, no IPv6. Las reglas para IPv4 e IPv6 pueden ser distintas; qsa.sh solo comprueba IPv4. Para revisar IPv6, averigua la dirección global del servidor y prueba desde otra máquina con conectividad IPv6. Un servidor cerrado en IPv4 puede tener una exposición distinta en IPv6.

El servicio está detrás de un balanceador. Un escaneo iniciado desde la instancia comprueba su dirección, no la dirección pública del balanceador. Revisa este último por separado desde otra máquina. Del mismo modo, si un puerto es accesible solo desde tu oficina o VPN, puede no aparecer desde la red de escaneo de qsa.sh: ese es el comportamiento esperado para una restricción de origen.

Después de encontrar un puerto inesperado

Decide si ese servicio debe ser público. Si no, la guía de qsa.sh recomienda cerrar el acceso en el firewall de la nube y en el del host, y enlazar el servicio a 127.0.0.1 o a una interfaz privada. Para una base de datos o una caché, plantea retirar la regla pública y acceder mediante la red privada, una VPN o un túnel SSH; si el puerto lo publica un contenedor, revisa también su mapeo.

Aplica el cambio y vuelve a escanear. Contrasta otra vez los puertos externos con los sockets locales y las reglas que esperabas tener activas. La siguiente comprobación útil es concreta: confirmar que el puerto que decidiste cerrar ya no acepta conexiones desde fuera.

Fuentes: DEV Community, qsa.sh, qsa.sh, Amazon Web Services