
Script NSE pour Nmap qui interroge l'API Vulners pour identifier les vulnérabilités connues (CVE) des services réseau détectés, améliorant le scan de ports standard avec une recherche automatisée de CVE et un score CVSS.
Transformez un scan de services nmap en une liste classée de CVE, d'exploits et de ce qui est attaqué dans la nature.
Un script NSE qui prend le logiciel déjà identifié par nmap, interroge la base de données Vulners pour savoir ce qui est connu à son sujet, et affiche la réponse dans le rapport de scan — du pire au meilleur, selon ce qui est réellement exploitable.
De vrais scans d'hôtes publiés pour être scannés. Sans clé, puis avec une clé, puis un port web : le de nmap signale une bannière Coyote et le balayage identifie le Tomcat et le jQuery qui se cachent derrière.
-sVPour chaque port ouvert, il recherche le logiciel identifié par nmap — les CPE produits par -sV — et affiche ce que Vulners sait à son sujet : du pire au meilleur selon ce qui est exploité plutôt qu'uniquement selon le score, et chaque ligne est un lien vers la page correspondante.
Sur un port HTTP, il identifie également la pile web elle-même, ce qui nomme les logiciels que -sV ne peut pas voir — un framework applicatif, un CMS, la version de PHP derrière un reverse proxy. 721 règles lisent les parties d'une réponse qui portent une version : l'en-tête Server, X-Powered-By, les cookies, le titre de la page, les balises <meta>, les noms de fichiers <script src> et le corps. Ces identités sont également recherchées et publiées sur le port afin que le reste du scan puisse les utiliser.
Deux choses qu'il fait au-delà du balayage :
-sV n'a pas pu nommer un service, la bannière brute est comparée à des règles pour FTP, SMTP, SSH, MySQL, DNS, NTP, LDAP et plus encore. Cela ne coûte aucune requête supplémentaire, et c'est le cas où un port ne signalerait sinon rien du tout./CHANGELOG.txt pour Drupal, /administrator/manifests/files/joomla.xml pour Joomla. Un hôte qui n'exécute aucun des six produits sondés ne reçoit rien de plus.```sh
nmap -sV --script vulners Voilà toute l'interface. Elle fonctionne sans clé API ; avec une, elle vous en dit
davantage. Il n'y a pas de changement de mode.```
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
Avec une clé, le même scan du même hôte répond différemment - KEV signifie que la CISA a enregistré la vulnérabilité comme exploitée dans la nature, et EPSS est la probabilité publiée qu'elle le soit :```
| 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
Mêmes 272 résultats, un ordre différent, une première ligne différente — et 22 de plus
connus comme exploitables, car une clé relie chaque exploit aux CVE qu'il
exploite. Ces deux réponses sont de vraies réponses de vulners.com, capturées contre un
serveur local présentant cette bannière.
## Classement
Les faits priment sur les prédictions. Les résultats sont ordonnés :
1. **CISA KEV** — enregistré comme exploité dans la nature
2. **SSVC `active`** — le jugement d'un coordinateur selon lequel l'exploitation est en cours
3. **un exploit existe** — le code est publié, pour celui-ci ou pour une CVE qu'il nomme
4. **EPSS élevé** — un modèle s'attend à une exploitation
5. tout le reste
Le CVSS départage les égalités au sein d'une bande, pas entre elles : un 7,5 exploité est un
problème plus grave qu'un 9,8 non exploité, et c'est l'ordre qui le dit.
Les colonnes suivent les données. Un signal que la réponse n'a pas porté perd sa colonne
plutôt que d'afficher une cellule vide, car un EPSS vierge se lit comme « calme », et
c'est une affirmation qu'un champ absent ne peut pas étayer.
## Ce qu'une clé API ajoute
| | |
|---|---|
| **Sans clé** | Chaque CPE trouvé par nmap est recherché sur le point de terminaison gratuit. Résultats, scores, indicateurs d'exploit et le propre score IA de Vulners. Aucun crédit, aucun compte |
| **Une clé, sans crédits** | Chaque résultat gagne ce que le point de terminaison id connaît : titres, dates, la page d'avis ou d'exploit en amont, le lien exploit-vers-CVE, CISA KEV et — selon la licence — EPSS et SSVC |
| **Une clé, un crédit** | Les logiciels que le chemin gratuit ne pouvait pas nommer du tout sont identifiés à partir de leur bannière brute. C'est la seule chose ici qui coûte quoi que ce soit, et uniquement pour un service sans CPE |
Un port qui porte déjà un CPE ne coûte jamais de crédit : mesuré sur quatre
produits, la recherche gratuite renvoie les **mêmes CVE** que la recherche payante pour un CPE.
Ce qu'un crédit achète, c'est l'identification, pas davantage de vulnérabilités.
Les clés gratuites se trouvent sur [vulners.com/userinfo](https://vulners.com/userinfo).
## Installation
**macOS, Linux, Kali, WSL** — une ligne, sans arguments :```sh
curl -fsSL https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.sh | sh
Windows - PowerShell en tant qu'administrateur :```powershell irm https://raw.githubusercontent.com/vulnersCom/nmap-vulners/master/install.ps1 | iex
L’installateur demande à nmap où il conserve ses données, y copie les scripts et leurs fichiers de données, reconstruit la base de données des scripts, puis vérifie que `--script vulners` pointe bien vers ce qu’il vient d’installer — nmap fournit son propre `vulners.nse`, et celui-ci le remplace.
<details>
<summary><b>Sans root, et autres options</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 accepte les mêmes options : -User, -Prefix, -Ref, -Uninstall.
Un seul fichier : copiez vulners.nse dans <nmap data dir>/scripts/ et exécutez
sudo nmap --script-updatedb. Il n'y a rien d'autre à placer — le script
télécharge ses dictionnaires au moment de l'analyse et n'écrit rien sur le disque — et donc
rien à oublier, ce qui produisait auparavant un script qui s'exécutait, ne trouvait rien, et
ne disait rien sur la raison.
Si vous effectuez une mise à niveau depuis la version 1.x, supprimez également vulners_enterprise.nse et
http-vulners-regex.nse de ce répertoire. Un http-vulners-regex.nse résiduel
conserve toujours la catégorie default et continue de balayer les
cibles sous un simple -sC. L'installateur le fait pour vous.
Le répertoire de données nmap est généralement /usr/share/nmap (Debian, Ubuntu, Kali),
/usr/local/share/nmap (compilé depuis les sources), /opt/homebrew/share/nmap
(Homebrew) ou C:\Program Files (x86)\Nmap (Windows). Pour en être certain, demandez à nmap :```sh
nmap -d2 --script-help probe 2>&1 | grep nse_main.lua
Le répertoire contenant `nse_main.lua` est celui que ce nmap utilise.
</details>
## Arguments du script
| Argument | Défaut | Signification |
|---|---|---|
| `vulners.mincvss` | `0` | Masque les résultats dont le score est inférieur à celui-ci. Les bulletins sans score et tout ce qui a un exploit connu sont affichés quel que soit le seuil |
| `vulners.paths` | les 939 chemins publiés | Chemins pour le balayage web : une liste Lua, une chaîne nommant un fichier avec un chemin par ligne, ou `none` pour désactiver le balayage. Un fichier que vous nommez et qui ne peut pas être lu arrête le balayage et le signale, plutôt que de revenir à la liste publiée |
| `vulners.width` | `80` | Largeur du terminal pour laquelle le tableau est mis en forme |
| `vulners.max_items` | `32` | Plafond des éléments facturés pour l'ensemble du scan |
| `vulners.api_key` | - | Jeton API. Fuit : nmap copie sa propre ligne de commande dans `-oX` |
| `vulners.api_key_file` | - | Chemin absolu vers un fichier dont la première ligne est le jeton |
| `vulners.api_host` | `vulners.com` | Nom d'hôte de l'API |
| `vulners.api_port` | `443` | Port sur `api_host` |
Un nom seul fonctionne aussi, donc `--script-args mincvss=7` suffit.
Les préfixes d'arguments de la version 1.x - `vulners_enterprise.*` et
`http-vulners-regex.paths` - sont acceptés pendant une version et affichent un
avis de dépréciation.
## Où conserver la clé API
Par ordre de préférence :
1. `~/.nmap/vulners.key`, une ligne, mode 600 - l'installateur propose de l'écrire
2. `VULNERS_API_KEY` dans l'environnement
3. `--script-args vulners.api_key_file=/chemin/absolu`
4. `--script-args vulners.api_key=<jeton>`
La dernière option est pratique et fuit : nmap copie sa propre ligne de commande dans chaque
rapport, donc le jeton se retrouve dans l'attribut `args` de la sortie `-oX` et dans votre
historique de shell. Le script lui-même n'écrit jamais le jeton nulle part, y compris dans sa
sortie de débogage - il existe un test de régression qui le confirme.
Un fichier de clé que vous nommez explicitement et qui ne peut pas être lu arrête l'exécution
plutôt que de revenir silencieusement en arrière - un opérateur qui nomme un fichier veut dire ce fichier - et
le rapport indique de quel fichier il s'agissait. Un chemin mal saisi ne peut pas ressembler à un
scan propre.
## D'où viennent les empreintes
Le script ne les transporte pas. Il télécharge trois dictionnaires une fois par scan,
avant que le premier hôte ne soit touché :```
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
C'est quatre requêtes par scan — une par fichier, pas par hôte ni par port — pour 40 Ko compressés sur 250 Ko de JSON, dans la phase de pré-scan de nmap. Mesuré par rapport à la branche publiée. Un script installé récupère donc de nouvelles empreintes sans être mis à jour.
Il n'écrit rien sur votre système de fichiers. Les dictionnaires sont conservés pendant la durée du scan puis supprimés, ce qui est le comportement de chaque script fourni avec nmap : sur les 611, 26 ouvrent un fichier en écriture et chacun écrit uniquement là où un argument de script le lui a indiqué. Aucun ne conserve de cache, et celui-ci non plus.
S'ils ne peuvent pas être téléchargés, le scan s'exécute quand même. Les dictionnaires alimentent la reconnaissance web et rien d'autre, donc une machine sans route vers GitHub perd cette fonctionnalité et conserve tout le reste : le logiciel identifié par nmap lui-même est toujours recherché, et le rapport indique quelle capacité manquait plutôt que de vous laisser lire un résultat vide comme un réseau propre.
| argument | ce qu'il fait |
|---|---|
vulners.catalog_url=<url> | récupérer depuis un miroir à la place — pour un réseau isolé. Un nom d'hôte ou une adresse IPv6 entre crochets, http://[fd00::1]/catalog/ |
vulners.catalog=none | ne pas récupérer du tout ; rechercher uniquement ce que nmap a nommé |
Sur un port HTTP, le script demande chaque chemin publié par le catalogue — 939
chemins — et fait correspondre les 721 règles à chaque réponse. Les chemins
proviennent de WhatWeb, nuclei et FingerprintHub : des endroits où un produit est
reconnu, plutôt que des suppositions. Même un chemin appartenant à un logiciel que
vous n'exécutez pas vaut la requête, car la réponse contient toujours Server,
X-Powered-By, un cookie et un titre, et c'est là que les règles trouvent la pile
qui se trouve devant.
La vitesse dépend de votre -T, pas d'un réglage de notre part. La liste ne
diminue jamais ; c'est le débit qui change :
Les six mesures ont été effectuées en une seule exécution contre le même serveur
local. -sV seul contre lui prend 6,1 s, donc le balayage coûte une seconde et
demie par défaut. Les deux lignes lentes sont -T0 et -T1 qui font leur travail :
188 et 94 lots, avec une attente délibérée entre chacun.
Les requêtes sont mises en pipeline sur 34 à 48 connexions avec au plus quatre
ouvertes à la fois, ce qui est pipeline_go de nselib — le même mécanisme que
http-enum de nmap utilise, respectant Keep-Alive: max= du serveur et
--script-args http.max-pipeline=N.
--script-args vulners.paths=none désactive complètement le balayage.
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
Les réponses sont mises en cache pour l'ensemble du scan, indexées par identité, donc une centaine
de serveurs identiques ne coûtent qu'une seule recherche. L'enrichissement est mis en cache par identifiant de résultat, donc deux
ports web exécutant des logiciels qui se chevauchent ne récupèrent chaque document qu'une seule fois.
## Sortie lisible par machine
Tout ce qui est imprimé est également structuré, donc `-oX` peut être analysé sans toucher au
texte lisible par l'humain. L'identifiant du script, les deux niveaux de tableau et les cinq clés
d'élément d'origine sont inchangés depuis la version 1.x, ce qui est ce que DefectDojo, Faraday,
nmap2csv et raven lisent :```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>
Nouveautés de la 2.0 : schema, mode, severity, exploit_known, kev, epss,
epss_percentile, exploitation, ai_score, title, published, href,
source_href et found_on. Chacun est présent ou absent, jamais vide.
Rien n'est imbriqué plus profondément qu'avant, car un troisième niveau de
tableau est invisible pour tous les importateurs examinés.
href est toujours la page vulners.com du résultat, dans les deux modes. Le
href propre au point de terminaison est l'adresse en amont - nvd.nist.gov
pour une CVE, github.com pour un exploit récupéré - et celle-ci circule
séparément, sous le nom de source_href, de sorte que la signification d'aucun
champ ne dépend du mode qui l'a produit.
La sortie structurée contient toujours chaque résultat ayant franchi le seuil
mincvss, même ceux que l'échelle de verbosité masque dans le texte - ainsi
aucune automatisation ne perd de résultats en ne passant pas -v.
Le texte rendu est une rupture. Les jetons *EXPLOIT* et *HAS EXPLOIT*
ainsi que la mise en page à tabulations ont disparu, remplacés par le tableau
aligné ci-dessus. Le lien vulners.com par ligne est conservé : c'est la dernière
colonne, et c'est la seule cellule que la mise en page ne raccourcira pas, car
une demi-URL n'est pas une URL. Les consommateurs qui analysent le texte doivent
être mis à jour ; les consommateurs de -oX ne le sont pas.
Une analyse d'un réseau sollicite l'API bien moins qu'il n'y paraît :
Les tests, le portail d'hygiène et CONTRIBUTING.md se trouvent uniquement dans
le dépôt git ; l'archive de publication contient les scripts et leurs données.
Huit portails, tous hors ligne sauf mention contraire, et CI exécute exactement
ceux-ci :```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 cas unitaires sont exécutés dans nmap contre les vraies bibliothèques NSE ; 64 cas de bout en bout pilotent le vrai binaire nmap contre un serveur web local et une API Vulners de substitution qui applique ce que la vraie applique ; la porte d'hygiène garde les secrets, la sortie de scan et le désordre d'éditeur hors de l'arborescence et refuse une lecture globale que NSE transformerait en résultat perdu ; et les quatre derniers contiennent les données et les outils qui les publient - la forme du catalogue, le contrat XML que chaque importateur lit, le traducteur de motifs, et la porte qui décide qu'une reconstruction peut être publiée sans risque. Le dernier contient l'intégralité du dépôt aux [propres normes de code de Nmap](https://secwiki.org/w/Nmap/Code_Standards), que `HACKING` désigne comme l'autorité pour un script qui veut vivre dans l'arborescence de nmap : pas de tabulations, pas d'espaces de fin de ligne, des lignes de moins de 80 colonnes, pas de points-virgules, une documentation NSEdoc privée commençant par `--;`, PEP 8 pour le Python.
`python3 tests/e2e/run_e2e.py --live` ajoute des vérifications contre le vrai service.
Voir [CONTRIBUTING.md](https://github.com/vulnerscom/nmap-vulners/blob/master/CONTRIBUTING.md).
## FAQ
**Est-ce que ça exploite quelque chose ?** Non. Ça lit des bannières et des pages et interroge une base de données - ça n'envoie aucune charge utile et n'essaie aucun identifiant. C'est catégorisé `discovery, intrusive, vuln, external` plutôt que `safe`, pour une seule raison : le balayage de chemins demande 939 chemins d'un port web, et la définition de `safe` par nmap exclut les scripts qui utilisent de grandes quantités de bande passante. Le propre `http-enum` de nmap demande 2 204 et porte la même étiquette. Votre `-T` définit la vitesse à laquelle ils partent et jamais combien, et `--script-args vulners.paths=none` désactive complètement le balayage.
**Est-ce que ça fonctionne sans clé API ?** Oui, entièrement. Sans clé, il utilise le point de terminaison gratuit, qui renvoie les mêmes vulnérabilités pour un CPE que celui payant. Une clé ajoute des détails par résultat et peut nommer des logiciels que le chemin gratuit ne peut pas.
**Pourquoi `-sC` a-t-il cessé de trouver des logiciels web ?** Parce que `vulners` n'est plus dans la catégorie `default` de nmap, et le balayage d'empreintes qui vivait dans `http-vulners-regex.nse` non plus. Envoyer l'identité du logiciel d'une cible à un tiers devrait être quelque chose que vous avez demandé : exécutez `--script vulners`.
**Pourquoi une vulnérabilité affiche-t-elle `cvss2.0` alors qu'une autre affiche `cvss3.1` ?** L'étiquette nomme l'échelle sur laquelle se trouve le score. Vulners renvoie celui que la source a publié ; un score v2 de 9,3 n'est pas un score v3 de 9,3.
**Pourquoi une entrée à faible score est-elle affichée quand je définis `mincvss` ?** Parce qu'elle a un exploit connu, ou parce que la source ne l'a jamais notée. Les deux sont délibérés.
**Le rapport dit que le catalogue n'a pas pu être téléchargé.** Alors l'empreinte web n'a pas été exécutée et tout le reste l'a été : le logiciel nommé par nmap lui-même a quand même été recherché. C'est dit à voix haute pour cette raison - une capacité qui ne s'est pas exécutée se lit comme une capacité qui n'a rien trouvé. Les deux causes ont une formulation distincte : « n'a pas pu être téléchargé » concerne le réseau, et « a répondu, mais l'un de ses dictionnaires n'a pas pu être lu » concerne le miroir vers lequel vous l'avez pointé.
**Ça n'a rien trouvé sur un hôte que je sais vulnérable.** Exécutez avec `-d2` : il journalise chaque identité demandée. En général, nmap a nommé le service mais pas sa version, et il n'y a pas de version à rechercher.
## Licence
Les scripts sont sous la même licence que Nmap lui-même - voir [LICENSE](https://github.com/vulnerscom/nmap-vulners/blob/master/LICENSE) pour la Nmap Public Source License, et
[nmap.org/npsl](https://nmap.org/npsl/) pour ce que cela signifie.
Les données de vulnérabilité proviennent de [Vulners](https://vulners.com) et sont soumises à leurs conditions.
## Liens connexes
* [vulners.com](https://vulners.com) - la base de données derrière ces scripts
* [vulnersCom/api](https://github.com/vulnersCom/api) - le client Python
* [vulnersCom/burp-vulners-scanner](https://github.com/vulnersCom/burp-vulners-scanner) - les mêmes données dans Burp Suite
* [nmap.org/book/nse.html](https://nmap.org/book/nse.html) - comment fonctionnent les scripts NSE
---
<div align="center">
Maintenu par l'équipe 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>
| lots | attente entre eux | mesuré, un port web |
|---|
-T0 paranoïaque | 188 x 5 | 2 s | 11 m 22 s |
-T1 furtif | 94 x 10 | 1 s | 1 m 56 s |
-T2 poli | 38 x 25 | 0,5 s | 26,2 s |
-T3 normal | 10 x 100 | 0,1 s | 7,6 s |
-T4 agressif | 4 x 250 | aucun | 6,7 s |
-T5 insensé | 1 | aucun | 6,6 s |