Nuclei es un escáner de vulnerabilidades de ProjectDiscovery que funciona con plantillas YAML: cada plantilla describe una petición y las condiciones que indican un fallo (un CVE, un panel expuesto, una cabecera de seguridad ausente). La comunidad mantiene miles de plantillas y tú puedes escribir las tuyas en pocos minutos. En este tutorial instalarás Nuclei en Ubuntu 24.04, lanzarás escaneos filtrados sobre tus propios sistemas, crearás y probarás una plantilla personalizada contra un servidor de laboratorio y guardarás los resultados en JSON.
Importanteescanea solo sistemas que sean tuyos o para los que tengas autorización por escrito. Un escaneo no autorizado puede ser ilegal y, como mínimo, provocará que te bloqueen o que tu proveedor reciba una queja de abuso.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS (x86_64 o arm64), por ejemplo un VPS de CubePath.
- Un usuario no root con privilegios
sudo. - 1 GB de RAM como mínimo; los escaneos con miles de plantillas usan bastante memoria.
- Un objetivo propio para practicar, que en esta guía se llama your_domain.
Paso 1: Instalar el binario de Nuclei
Nuclei se distribuye como un binario estático en las releases de GitHub. Es la forma más sencilla de tener la última versión sin instalar Go.
Instala las herramientas necesarias:
sudo apt update
sudo apt install curl unzip jq
Obtén el número de la última versión y la arquitectura del servidor:
VERSION=$(curl -s https://api.github.com/repos/projectdiscovery/nuclei/releases/latest | jq -r .tag_name | sed 's/^v//')
ARCH=$(dpkg --print-architecture)
echo "$VERSION $ARCH"
3.x.x amd64
Descarga el binario y el fichero de sumas de comprobación, y verifica la integridad:
cd /tmp
curl -fsSLO "https://github.com/projectdiscovery/nuclei/releases/download/v${VERSION}/nuclei_${VERSION}_linux_${ARCH}.zip"
curl -fsSLO "https://github.com/projectdiscovery/nuclei/releases/download/v${VERSION}/nuclei_${VERSION}_checksums.txt"
sha256sum --check --ignore-missing "nuclei_${VERSION}_checksums.txt"
nuclei_3.x.x_linux_amd64.zip: OK
Descomprime e instala el binario en /usr/local/bin:
unzip -o "nuclei_${VERSION}_linux_${ARCH}.zip" nuclei
sudo install -m 0755 nuclei /usr/local/bin/nuclei
nuclei -version
[INF] Nuclei Engine Version: v3.x.x
Para actualizar el motor más adelante basta con nuclei -update.
Paso 2: Descargar las plantillas
Las plantillas de la comunidad se guardan en ~/nuclei-templates del usuario que ejecuta Nuclei. Descárgalas o actualízalas con:
nuclei -update-templates
Comprueba cuántas hay y cómo están organizadas:
ls ~/nuclei-templates
nuclei -tl | wc -l
cloud code dast dns file headless http javascript network ssl workflows ...
Las plantillas se agrupan por protocolo (http/, dns/, ssl/, network/) y dentro por tipo (http/cves/, http/exposed-panels/, http/misconfiguration/...). Además, cada una lleva etiquetas (cve, panel, tech, misconfig) y una severidad, que son la forma más práctica de filtrar.
Paso 3: Lanzar tu primer escaneo
Un escaneo sin filtros ejecuta miles de plantillas y envía miles de peticiones. Empieza por algo acotado: detectar las tecnologías del objetivo, que es rápido y no intrusivo.
nuclei -u https://your_domain -tags tech -rl 20
-rl 20 limita el escaneo a 20 peticiones por segundo (el valor por defecto es 150), algo recomendable contra servidores en producción. La salida muestra una línea por hallazgo:
[nginx-version] [http] [info] https://your_domain ["nginx/1.24.0"]
[tech-detect:nginx] [http] [info] https://your_domain
[http-missing-security-headers:content-security-policy] [http] [info] https://your_domain
El formato es [id-plantilla:matcher] [protocolo] [severidad] URL [datos extraídos].
Filtrar por severidad y etiqueta
Busca solo problemas de severidad media o superior:
nuclei -u https://your_domain -s medium,high,critical -rl 20
Combina etiquetas para centrarte en paneles expuestos, configuraciones incorrectas y ficheros sensibles publicados:
nuclei -u https://your_domain -tags panel,misconfig,exposure -rl 20
Escanear varios objetivos
Pon un objetivo por línea en un fichero:
nano ~/objetivos.txt
https://your_domain
https://api.your_domain
https://staging.your_domain
nuclei -l ~/objetivos.txt -s high,critical -rl 20 -c 10
-c fija cuántas plantillas se ejecutan en paralelo. Bájalo junto con -rl si el servidor objetivo es pequeño.
Paso 4: Guardar los resultados
Para revisar o procesar los hallazgos después, guárdalos en formato JSON Lines, un objeto JSON por línea:
nuclei -u https://your_domain -s medium,high,critical -rl 20 -jsonl -o ~/nuclei-$(date +%F).jsonl
Con jq puedes extraer un resumen tabulado:
jq -r '[.info.severity, .["template-id"], .["matched-at"]] | @tsv' ~/nuclei-$(date +%F).jsonl | sort
high git-config https://your_domain/.git/config
medium phpinfo-files https://your_domain/info.php
Si prefieres un informe legible, -me (-markdown-export) genera un fichero Markdown por hallazgo en el directorio que indiques.
Paso 5: Preparar un laboratorio para plantillas propias
Para probar una plantilla necesitas un objetivo donde el fallo exista de verdad. Crea uno local con el servidor HTTP de Python, que expone un repositorio Git publicado por error, un fallo real y habitual:
mkdir -p ~/lab/.git
printf '[core]\n\trepositoryformatversion = 0\n\tbare = false\n' > ~/lab/.git/config
python3 -m http.server 8000 --bind 127.0.0.1 --directory ~/lab
Deja esa terminal abierta y abre otra para los pasos siguientes. Comprueba que el fichero se sirve:
curl -s http://127.0.0.1:8000/.git/config
[core]
repositoryformatversion = 0
bare = false
Paso 6: Escribir una plantilla personalizada
Guarda tus plantillas fuera de ~/nuclei-templates para que las actualizaciones no las toquen:
mkdir -p ~/nuclei-custom
nano ~/nuclei-custom/git-config-expuesto.yaml
id: git-config-expuesto
info:
name: Repositorio Git expuesto
author: your_user
severity: high
description: El fichero .git/config es accesible por HTTP, lo que permite descargar el código fuente.
tags: exposure,git,custom
http:
- method: GET
path:
- "{{BaseURL}}/.git/config"
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
part: body
words:
- "[core]"
- "repositoryformatversion"
condition: and
- type: word
part: header
words:
- "text/html"
negative: true
La plantilla solo da positivo si se cumplen los tres matchers (matchers-condition: and): código 200, las dos cadenas típicas de un .git/config en el cuerpo, y que la respuesta no sea una página HTML. Este último matcher negativo evita falsos positivos en sitios que devuelven su página de inicio con código 200 para cualquier ruta.
Valida la sintaxis:
nuclei -validate -t ~/nuclei-custom/git-config-expuesto.yaml
[INF] All templates validated successfully
Ejecútala contra el laboratorio:
nuclei -u http://127.0.0.1:8000 -t ~/nuclei-custom/git-config-expuesto.yaml
[WRN] Loading 1 unsigned templates for scan. Use with caution.
[git-config-expuesto] [http] [high] http://127.0.0.1:8000/.git/config
El aviso sobre plantillas sin firmar es normal en plantillas propias de tipo HTTP. Para confirmar que no da falsos positivos, borra el fichero y repite el escaneo: no debe aparecer ningún resultado.
rm ~/lab/.git/config
nuclei -u http://127.0.0.1:8000 -t ~/nuclei-custom/git-config-expuesto.yaml
Extraer datos de la respuesta
Los extractores añaden información útil al hallazgo. Esta segunda plantilla informa de la cabecera Server si revela una versión:
nano ~/nuclei-custom/server-version.yaml
id: server-version
info:
name: Versión del servidor en la cabecera Server
author: your_user
severity: info
tags: tech,custom
http:
- method: GET
path:
- "{{BaseURL}}/"
matchers:
- type: regex
part: header
regex:
- "(?i)server: [a-z-]+/[0-9.]+"
extractors:
- type: kval
kval:
- server
nuclei -u https://your_domain -t ~/nuclei-custom/server-version.yaml
[server-version] [http] [info] https://your_domain/ ["nginx/1.24.0"]
Para ejecutar todas tus plantillas de una vez, pasa el directorio: nuclei -u https://your_domain -t ~/nuclei-custom/. Cuando termines, detén el servidor del laboratorio con Ctrl+C.
Solución de problemas
El escaneo tarda mucho o el objetivo empieza a dar errores 429 o 503. Baja -rl y -c, y acota con -tags o -s. Añade -stats para ver el progreso cada pocos segundos.
Un hallazgo parece un falso positivo. Repite solo esa plantilla con -debug para ver la petición y la respuesta completas: nuclei -u https://your_domain -id nombre-plantilla -debug. Si lo confirmas, exclúyela con -exclude-id nombre-plantilla.
Muchos errores de conexión o timeout. Sube el tiempo de espera con -timeout 15 y revisa que un WAF o un rate limit (por ejemplo de Cloudflare o CrowdSec) no esté bloqueando la IP desde la que escaneas.
Conclusión
Has instalado Nuclei verificando su suma de comprobación, has lanzado escaneos filtrados por etiqueta y severidad, has exportado los resultados a JSON y has escrito y probado dos plantillas propias. Como siguientes pasos, programa un escaneo semanal de tus dominios con un temporizador de systemd, integra la plantilla de severidad alta en tu pipeline de CI para que falle ante hallazgos críticos, y revisa las plantillas de ~/nuclei-templates/http/ para aprender los patrones que usa la comunidad.
