
Script NSE de Nmap que consulta la API de Vulners para identificar vulnerabilidades conocidas (CVE) en los servicios de red detectados, mejorando el escaneo de puertos estándar con búsqueda automatizada de CVE y puntuación CVSS.
Convierte un escaneo de servicios de nmap en una lista clasificada de CVEs, exploits y qué se está atacando en la naturaleza.
Un script NSE que toma el software que nmap ya identificó, consulta a la base de datos de Vulners qué se sabe al respecto, e imprime la respuesta dentro del informe del escaneo: primero lo peor, según lo que realmente es explotable.
Escaneos reales de hosts publicados para escanear. Sin clave, luego con clave, y luego un puerto web: el de nmap reporta un banner de Coyote y el barrido identifica el Tomcat y el jQuery detrás de él.
-sVPara cada puerto abierto, busca el software que nmap identificó — los CPEs que produjo -sV — e imprime lo que Vulners sabe al respecto: primero lo peor según lo que se está explotando en lugar de solo por puntuación, y cada fila es un enlace a la página detrás de ella.
En un puerto HTTP también identifica la propia pila web, lo que nombra software que -sV no puede ver — un framework de aplicación, un CMS, la versión de PHP detrás de un proxy inverso. 721 reglas leen las partes de una respuesta que llevan una versión: la cabecera Server, X-Powered-By, cookies, el título de la página, etiquetas <meta>, nombres de archivo <script src> y el cuerpo. Esas identidades también se buscan y se publican en el puerto para que el resto del escaneo pueda usarlas.
Dos cosas que hace más allá del barrido:
-sV no pudo nombrar un servicio, el banner sin procesar se compara con reglas para FTP, SMTP, SSH, MySQL, DNS, NTP, LDAP y más. Eso no cuesta ninguna solicitud extra, y es el caso en el que un puerto de otro modo no reportaría nada en absoluto./CHANGELOG.txt para Drupal, /administrator/manifests/files/joomla.xml para Joomla. A un host que no ejecuta ninguno de los seis productos sondeados no se le envía nada extra.```sh
nmap -sV --script vulners Esa es toda la interfaz. Funciona sin una clave de API; con una te proporciona más información. No hay cambio de modo.```
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.7 ((Ubuntu))
| vulners: cpe:/a:apache:http_server:2.4.7 272 findings, 56 exploitable
| SEVERITY CVSS AI FLAGS LINK
| ======== ==== ==== ======= ==============================================================
| CRITICAL 10.0 8.8 EXP https://vulners.com/gitee/3E6BA608-776F-5B1F-9BA5-589CD2A5A351
| CRITICAL 9.8 9.9 EXP https://vulners.com/zdt/1337DAY-ID-39214
| CRITICAL 9.8 9.6 EXP https://vulners.com/packetstorm/PACKETSTORM:171631
| CRITICAL 9.8 9.9 https://vulners.com/cve/CVE-2021-44790
| CRITICAL 9.8 9.8 https://vulners.com/cve/CVE-2023-25690
|_ 262 more not shown; -v shows all, -vv adds where each was found
Con una clave, el mismo escaneo del mismo host responde de manera diferente: KEV significa que CISA ha registrado la vulnerabilidad como explotada en la naturaleza, y EPSS es la probabilidad publicada de que lo sea:```
| vulners: cpe:/a:apache:http_server:2.4.7 272 findings, 78 exploitable
| SEVERITY CVSS EPSS FLAGS LINK
| ======== ==== ==== ======= ==============================================================
| CRITICAL 9.1 >99% KEV EXP https://vulners.com/cve/CVE-2024-38475
| CRITICAL 9.0 >99% KEV EXP https://vulners.com/cve/CVE-2021-40438
| CRITICAL 9.1 >99% KEV https://vulners.com/cnvd/CNVD-2024-36387
| CRITICAL 10.0 71% EXP https://vulners.com/gitee/3E6BA608-776F-5B1F-9BA5-589CD2A5A351
| CRITICAL 9.8 97% EXP https://vulners.com/cve/CVE-2021-44790
|_ 262 more not shown; -v shows all, -vv adds where each was found
Mismos 272 hallazgos, un orden distinto, una fila superior diferente - y 22 más de ellos
conocidos como explotables, porque una clave vincula cada exploit con los CVE que
explota. Ambas son respuestas reales de vulners.com, capturadas contra un
servidor local que presenta ese banner.
## Clasificación
Los hechos superan a las predicciones. Los hallazgos se ordenan:
1. **CISA KEV** - registrado como explotado en la naturaleza
2. **SSVC `active`** - el juicio de un coordinador de que la explotación está ocurriendo
3. **existe un exploit** - el código está publicado, para este o para un CVE que nombra
4. **EPSS alto** - un modelo espera explotación
5. todo lo demás
CVSS desempata dentro de una banda, no entre bandas: un 7.5 explotado es un peor
problema que un 9.8 no explotado, y este es el orden que lo dice.
Las columnas siguen los datos. Una señal que la respuesta no aportó pierde su
columna en lugar de mostrar una celda vacía, porque un EPSS en blanco se lee como
"tranquilo", y eso es una afirmación que un campo ausente no puede respaldar.
## Qué añade una clave de API
| | |
|---|---|
| **Sin clave** | Cada CPE que nmap encontró se consulta en el endpoint gratuito. Hallazgos, puntuaciones, indicadores de exploit y la propia puntuación de IA de Vulners. Sin créditos, sin cuenta |
| **Una clave, sin créditos** | Cada hallazgo gana lo que el endpoint de id conoce: títulos, fechas, la página del aviso o exploit upstream, el vínculo exploit-a-CVE, CISA KEV y - según la licencia - EPSS y SSVC |
| **Una clave, un crédito** | El software que la ruta gratuita no pudo nombrar en absoluto se identifica desde su banner crudo. Esto es lo único aquí que cuesta algo, y solo para un servicio sin CPE |
Un puerto que ya lleva un CPE nunca cuesta un crédito: medido en cuatro
productos, la consulta gratuita devuelve los **mismos CVE** que la de pago para un CPE.
Lo que compra un crédito es identificación, no más vulnerabilidades.
Las claves gratuitas están en [vulners.com/userinfo](https://vulners.com/userinfo).
## Instalación
**macOS, Linux, Kali, WSL** - una línea, sin argumentos:```sh
curl -fsSL https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.sh | sh
Windows - PowerShell como Administrador:```powershell irm https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.ps1 | iex
El instalador le pregunta a nmap dónde guarda sus datos, copia los scripts y sus archivos de datos allí, reconstruye la base de datos de scripts y luego verifica que `--script vulners` realmente resuelva a lo que acaba de instalar: nmap incluye un `vulners.nse` propio, y este lo reemplaza.
<details>
<summary><b>Sin root y otras opciones</b></summary>```sh
# into ~/.nmap, no sudo; the installer prints the NMAPDIR line to add to your profile
curl -fsSL https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.sh | sh -s -- --user
# a specific directory
./install.sh --prefix /usr/local/share/nmap
# a specific release
./install.sh --ref v2.0
# remove everything it installed
./install.sh --uninstall
PowerShell acepta las mismas opciones: -User, -Prefix, -Ref, -Uninstall.
Un solo archivo: copia vulners.nse en <nmap data dir>/scripts/ y ejecuta
sudo nmap --script-updatedb. No hay nada más que colocar: el script
descarga sus diccionarios en el momento del escaneo y no escribe nada en el
disco, por lo que no hay nada que olvidar, lo que solía producir un script que
se ejecutaba, no encontraba nada y no decía nada sobre el porqué.
Si estás actualizando desde 1.x, elimina también vulners_enterprise.nse y
http-vulners-regex.nse de ese directorio. Un http-vulners-regex.nse
sobrante aún lleva la categoría default y sigue barriendo objetivos bajo un
simple -sC. El instalador hace esto por ti.
El directorio de datos de nmap suele ser /usr/share/nmap (Debian, Ubuntu,
Kali), /usr/local/share/nmap (compilado desde el código fuente),
/opt/homebrew/share/nmap (Homebrew) o C:\Program Files (x86)\Nmap
(Windows). Para estar seguro, pregúntale a nmap:```sh
nmap -d2 --script-help probe 2>&1 | grep nse_main.lua
El directorio que contiene `nse_main.lua` es el que usa este nmap.
</details>
## Argumentos del script
| Argumento | Valor por defecto | Significado |
|---|---|---|
| `vulners.mincvss` | `0` | Oculta hallazgos puntuados por debajo de este valor. Los boletines sin puntuación y cualquier cosa con un exploit conocido se muestran sin importar el umbral |
| `vulners.paths` | las 939 rutas publicadas | Rutas para el barrido web: una lista Lua, una cadena que nombre un archivo con una ruta por línea, o `none` para desactivar el barrido. Un archivo que nombres y no pueda leerse detiene el barrido y lo indica, en lugar de recurrir a la lista publicada |
| `vulners.width` | `80` | Ancho de terminal para el que se diseña la tabla |
| `vulners.max_items` | `32` | Límite máximo de elementos facturados para todo el escaneo |
| `vulners.api_key` | - | Token de API. Con fugas: nmap copia su propia línea de comandos en `-oX` |
| `vulners.api_key_file` | - | Ruta absoluta a un archivo cuya primera línea es el token |
| `vulners.api_host` | `vulners.com` | Nombre de host de la API |
| `vulners.api_port` | `443` | Puerto en `api_host` |
Un nombre simple también funciona, así que `--script-args mincvss=7` es suficiente.
Los prefijos de argumentos 1.x - `vulners_enterprise.*` y
`http-vulners-regex.paths` - se aceptan durante una versión e imprimen un
aviso de obsolescencia.
## Dónde guardar la clave de API
En orden de preferencia:
1. `~/.nmap/vulners.key`, una línea, modo 600 - el instalador ofrece escribirla
2. `VULNERS_API_KEY` en el entorno
3. `--script-args vulners.api_key_file=/absolute/path`
4. `--script-args vulners.api_key=<token>`
La última es conveniente y tiene fugas: nmap copia su propia línea de comandos en cada
informe, así que el token termina en el atributo `args` de la salida `-oX` y en tu
historial de shell. El script en sí nunca escribe el token en ningún lugar, incluida su
salida de depuración - hay una prueba de regresión que lo confirma.
Un archivo de clave que nombres explícitamente y que no pueda leerse detiene la ejecución en lugar
de recurrir silenciosamente a otro - un operador que nombra un archivo quiere decir ese archivo - y
el informe indica qué archivo era. Una ruta mal escrita no puede parecer un escaneo limpio.
## De dónde provienen las huellas dactilares
El script no las lleva consigo. Descarga tres diccionarios una vez por escaneo,
antes de tocar el primer host:```
https://raw.githubusercontent.com/vulnersCom/nmap-vulners/catalog/
index.json what exists, at which serial
fingerprints.json 721 product and version rules
paths.json 939 paths the sweep requests
probes.json targeted version probes
Eso son cuatro solicitudes por escaneo: una por archivo, no por host ni por puerto, para 40 KB comprimidos de 250 KB de JSON, en la fase previa al escaneo de nmap. Medido frente a la rama publicada. Por lo tanto, un script instalado recoge nuevas huellas sin necesidad de actualizarse.
No escribe nada en tu sistema de archivos. Los diccionarios se mantienen durante la duración del escaneo y se descartan, que es como se comporta cada script que nmap incluye: de los 611, 26 abren un archivo para escritura y cada uno escribe solo donde un argumento de script le indicó. Ninguno mantiene una caché, y este tampoco.
Si no se pueden descargar, el escaneo igualmente se ejecuta. Los diccionarios alimentan la identificación web de huellas y nada más, así que una máquina sin ruta a GitHub pierde eso y conserva todo lo demás: el software que el propio nmap identificó sigue consultándose, y el informe indica qué capacidad faltaba en lugar de dejarte leer un resultado vacío como si fuera una red limpia.
| argumento | qué hace |
|---|---|
vulners.catalog_url=<url> | obtener desde un espejo en su lugar, para una red aislada. Un nombre de host o una dirección IPv6 entre corchetes, http://[fd00::1]/catalog/ |
vulners.catalog=none | no obtener nada; consultar solo lo que nmap nombró |
En un puerto HTTP, el script solicita cada ruta que publica el catálogo: 939
rutas, y compara las 721 reglas contra cada respuesta. Las rutas provienen de
WhatWeb, nuclei y FingerprintHub: lugares donde se reconoce un producto, en lugar de
suposiciones. Incluso una ruta perteneciente a software que no estás ejecutando vale la
solicitud, porque la respuesta igualmente lleva Server, X-Powered-By, una cookie y
un título, y ahí es donde las reglas encuentran la pila que hay delante.
La rapidez con que avanza depende de tu -T, no de una configuración nuestra. La lista
nunca se reduce; la tasa sí:
Los seis medidos en una sola ejecución contra el mismo servidor local. Solo -sV contra
él es 6.1 s, así que el barrido cuesta un segundo y medio en la configuración predeterminada. Las dos filas
lentas son -T0 y -T1 haciendo su trabajo: 188 y 94 lotes, con una espera
deliberada entre cada uno.
Las solicitudes se canalizan a través de 34-48 conexiones con como máximo cuatro abiertas a la
vez, que es pipeline_go de nselib: el mismo mecanismo que usa el propio http-enum
de nmap, respetando el Keep-Alive: max= del servidor y
--script-args http.max-pipeline=N.
--script-args vulners.paths=none desactiva el barrido por completo.
nmap -sV | +-- service fingerprint --> port.version.cpe --------------+ | | +-- vulners.nse | reads nmap's banner for services -sV could not name | on an HTTP port: requests the path list in one | pipeline, matches 721 rules against the header, the | title, the meta tags, the scripts and the body | probes for a version when a product hid it | publishes everything it recognised ------------------+ | v GET /api/v3/burp/software/ per identity free, no key, CDN-cached | POST /api/v3/search/id/ per 100 findings free, needs a key: enrichment | POST /api/v4/audit/smart only for a service with no CPE: 1 credit | ranked, filtered, printed
Las respuestas se almacenan en caché para todo el escaneo, con clave por identidad, de modo que cien servidores idénticos cuestan una sola consulta. El enriquecimiento se almacena en caché por id de hallazgo, de modo que dos puertos web que ejecutan software superpuesto obtienen cada documento una sola vez.
## Salida legible por máquina
Todo lo que se imprime también está estructurado, por lo que `-oX` se puede analizar sin tocar el texto legible. El id del script, los dos niveles de tabla y las cinco claves originales de elementos no cambian respecto a 1.x, que es lo que leen DefectDojo, Faraday, nmap2csv y raven:```xml
<script id="vulners">
<elem key="schema">2.0</elem>
<elem key="mode">keyed</elem>
<table key="cpe:/a:apache:http_server:2.4.7">
<table>
<elem key="id">CVE-2021-40438</elem>
<elem key="type">cve</elem>
<elem key="severity">CRITICAL</elem>
<elem key="cvss">9.0</elem>
<elem key="cvss_type">cvss3.1</elem>
<elem key="is_exploit">false</elem>
<elem key="exploit_known">true</elem>
<elem key="kev">true</elem>
<elem key="epss">0.99612</elem>
<elem key="exploitation">active</elem>
<elem key="title">Apache HTTP Server SSRF in mod_proxy</elem>
<elem key="href">https://vulners.com/cve/CVE-2021-40438</elem>
<elem key="source_href">https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2021-40438</elem>
</table>
</table>
</script>
Novedades en 2.0: schema, mode, severity, exploit_known, kev, epss,
epss_percentile, exploitation, ai_score, title, published, href,
source_href y found_on. Cada uno está presente o ausente, nunca vacío.
Nada está anidado más profundamente que antes, porque un tercer nivel de tabla
es invisible para todos los importadores examinados.
href es siempre la página de vulners.com para el hallazgo, en ambos modos. El
href propio del endpoint es la dirección ascendente - nvd.nist.gov para un CVE,
github.com para un exploit extraído - y esa viaja por separado, como
source_href, de modo que el significado de ningún campo depende del modo que lo produjo.
La salida estructurada siempre incluye todos los hallazgos que superaron mincvss,
incluso los que la escalera de verbosidad oculta del texto - así ninguna automatización
pierde hallazgos por no pasar -v.
El texto renderizado es un cambio. Los tokens *EXPLOIT* y *HAS EXPLOIT*
y el diseño separado por tabulaciones han desaparecido, reemplazados por la tabla
alineada de arriba. El enlace a vulners.com por fila se mantuvo: es la última columna,
y es la única celda que el diseño no acortará, porque media URL no es una URL. Los
consumidores que extraen texto necesitan actualizarse; los consumidores de -oX no.
Un escaneo de una red pide a la API mucho menos de lo que parece:
Las pruebas, la puerta de higiene y CONTRIBUTING.md están solo en el repositorio
git; el archivo de lanzamiento incluye los scripts y sus datos. Ocho puertas, todas
sin conexión salvo donde se indica, y CI ejecuta exactamente estas:```sh
nmap -sn -Pn --script ./tests/run.nse --script-args testdir=tests,root=. 127.0.0.1
python3 tests/e2e/run_e2e.py
python3 tools/check.py
python3 tools/catalog.py --check
python3 tools/xml_contract.py --selftest
python3 tools/fingerprints/selftest.py
python3 tools/catalog_diff.py --selftest
python3 tools/nmap_style.py
270 casos de unidades ejecutados dentro de nmap contra las librerías NSE reales; 64 casos de extremo a extremo
ejecutan el binario real de nmap contra un servidor web local y una API Vulners simulada
que aplica lo mismo que aplica la real; la compuerta de higiene mantiene secretos,
salida de escaneo y desorden del editor fuera del árbol y rechaza una lectura global
que NSE convertiría en un resultado perdido; y los últimos cuatro contienen los datos y
las herramientas que los publican: la forma del catálogo, el contrato XML que lee cada
importador, el traductor de patrones y la compuerta que decide que una reconstrucción
es segura de publicar. El último mantiene todo el repositorio conforme a los
[Estándares de Código de Nmap](https://secwiki.org/w/Nmap/Code_Standards), que
`HACKING` nombra como la autoridad para un script que quiera vivir en el árbol de
nmap: sin tabuladores, sin espacios finales, líneas de menos de 80 columnas, sin punto y coma,
documentación NSEdoc privada que abre con `--;`, PEP 8 para el Python.
`python3 tests/e2e/run_e2e.py --live` añade comprobaciones contra el servicio real.
Consulta [CONTRIBUTING.md](https://github.com/vulnerscom/nmap-vulners/blob/master/CONTRIBUTING.md).
## FAQ
**¿Explota algo?** No. Lee banners y páginas y consulta una
base de datos: no envía ningún payload ni prueba ninguna credencial. Está categorizado
`discovery, intrusive, vuln, external` en lugar de `safe`, por una razón: el
barrido de rutas solicita 939 rutas de un puerto web, y la definición de `safe` de nmap
excluye scripts que usan grandes cantidades de ancho de banda. El propio `http-enum` de nmap
solicita 2 204 y lleva la misma etiqueta. Tu `-T` define la velocidad a la que salen
y nunca cuántas, y `--script-args vulners.paths=none` desactiva el barrido por completo.
**¿Funciona sin una clave de API?** Sí, completamente. Sin una, usa el endpoint
gratuito, que devuelve las mismas vulnerabilidades para un CPE que el de pago. Una
clave añade detalle por hallazgo y puede nombrar software que la ruta gratuita no puede.
**¿Por qué `-sC` dejó de encontrar software web?** Porque `vulners` ya no está en la
categoría `default` de nmap, y tampoco lo está el barrido de huellas que solía
vivir en `http-vulners-regex.nse`. Enviar la identidad del software de un objetivo a
un tercero debería ser algo que pidieras: ejecuta `--script vulners`.
**¿Por qué una vulnerabilidad muestra `cvss2.0` mientras otra muestra `cvss3.1`?** La
etiqueta nombra la escala en la que está la puntuación. Vulners devuelve la que haya
publicado la fuente; una puntuación v2 de 9.3 no es una puntuación v3 de 9.3.
**¿Por qué se muestra una entrada con puntuación baja cuando configuro `mincvss`?** Porque
tiene un exploit conocido, o porque la fuente nunca la puntuó. Ambas son deliberadas.
**El informe dice que el catálogo no pudo descargarse.** Entonces el reconocimiento web
no se ejecutó y todo lo demás sí: el software que el propio nmap nombró
aún se consultó. Se dice en voz alta por esa razón: una capacidad que no se
ejecutó se lee como una capacidad que no encontró nada. Las dos causas tienen
redacción separada: "no pudo descargarse" es la red, y "respondió, pero
uno de sus diccionarios no pudo leerse" es el espejo al que lo apuntaste.
**No encontró nada en un host que sé que es vulnerable.** Ejecuta con `-d2`: registra
cada identidad sobre la que preguntó. Normalmente nmap nombró el servicio pero no su
versión, y no hay versión que consultar.
## Licencia
Los scripts tienen la misma licencia que el propio Nmap: consulta [LICENSE](https://github.com/vulnerscom/nmap-vulners/blob/master/LICENSE) para la
Nmap Public Source License, y
[nmap.org/npsl](https://nmap.org/npsl/) para saber qué significa.
Los datos de vulnerabilidades provienen de [Vulners](https://vulners.com) y están sujetos a
sus términos.
## Relacionado
* [vulners.com](https://vulners.com) - la base de datos detrás de estos scripts
* [vulnersCom/api](https://github.com/vulnersCom/api) - el cliente Python
* [vulnersCom/burp-vulners-scanner](https://github.com/vulnersCom/burp-vulners-scanner) - los mismos datos dentro de Burp Suite
* [nmap.org/book/nse.html](https://nmap.org/book/nse.html) - cómo funcionan los scripts NSE
---
<div align="center">
Mantenido por el Equipo Vulners <[email protected]>
`#nmap` `#nse` `#vulnerability-scanner` `#cve` `#cvss` `#cpe` `#vulners`
`#security-tools` `#pentest` `#infosec` `#network-scanner` `#exploit-database`
`#lua` `#vulnerability-detection` `#security-automation`
</div>
| lotes | espera entre ellos | medido, un puerto web |
|---|
-T0 paranoico | 188 x 5 | 2 s | 11 m 22 s |
-T1 sigiloso | 94 x 10 | 1 s | 1 m 56 s |
-T2 cortés | 38 x 25 | 0.5 s | 26.2 s |
-T3 normal | 10 x 100 | 0.1 s | 7.6 s |
-T4 agresivo | 4 x 250 | ninguna | 6.7 s |
-T5 insensato | 1 | ninguna | 6.6 s |