Utilisation de Python avec Nmap
Mise à jour :
Nmap est un outil de scan réseau puissant et flexible, qui peut être utilisé pour découvrir des hôtes et des services sur un réseau. Pouvoir l’utiliser avec Python permet d’automatiser et de personnaliser les scans facilement. Voyons comment cela fonctionne.
Présentation de python3‑nmap
python3‑nmap est une bibliothèque Python développée pour offrir une interface simple avec Nmap, l’un des outils de scan réseau les plus puissants et populaires. Contrairement à d’autres wrappers comme python-nmap, qui repose sur l’analyse de fichiers XML générés par Nmap, python3‑nmap permet une interaction directe avec l’outil via des appels systèmes et un retour structuré en JSON.
Cela le rend particulièrement adapté pour des scripts modernes utilisant Python 3, car il élimine les étapes de parsing XML souvent sources de bugs et de lenteur.
Fonctionnalités principales
- Scan de ports (par défaut les 1000 plus courants)
- Détection de services et de leurs versions
- Identification de l’OS de la machine distante
- Support des scripts NSE, notamment vulners pour lister les vulnérabilités
- Résultats directement en JSON, facile à parser et intégrer
Installation
Avant de pouvoir utiliser python3‑nmap, vous devez vous assurer que Nmap
est installé sur votre système, car la bibliothèque agit comme un wrapper autour
de l’exécutable Nmap. Ensuite, vous pourrez installer le module Python via
pip
.
Installation de Nmap
Selon votre système d’exploitation, voici les commandes pour installer Nmap :
-
Sous Debian/Ubuntu :
Terminal window sudo apt updatesudo apt install nmap -
Sous RedHat/CentOS :
Terminal window sudo yum install nmap -
Sous macOS (via Homebrew) :
Terminal window brew install nmap -
Sous Windows :
Téléchargez le binaire depuis le site officiel :
nmap.org/download.html ↗. Ajoutez le chemin
d’installation (ex. C:\Program Files (x86)\Nmap
) à la variable d’environnement
PATH
.
Installation de python3-nmap
Une fois Nmap installé et accessible depuis la ligne de commande (nmap -v
doit
fonctionner), installez le module Python :
uv venv test-nmapsource test-nmap/bin/activate # Sous Linux/macOStest-nmap\Scripts\activate # Sous Windowsuv pip install python3-nmap
Ici, nous utilisons uv
pour créer
un environnement virtuel nommé test-nmap
et installer le module python3-nmap
à l’intérieur. Cela permet d’éviter les conflits de dépendances avec d’autres
projets Python. Pour les utilisateurs de pip
, la commande serait :
pip install python3-nmap
Résolution des problèmes courants
- Erreur “nmap: command not found” : Nmap n’est pas installé ou mal référencé dans le PATH.
- Permission denied : Certains types de scan (détection OS, scripts NSE)
nécessitent les droits root. Utilisez
sudo
sous Linux/macOS. - ModuleNotFoundError: No module named ‘nmap3’ : Assurez-vous d’avoir bien
utilisé
pip3 install python3-nmap
et non un autre paquet similaire.
Bonnes pratiques & éthique
Avant de plonger dans les scripts, il est important de rappeler que l’utilisation de python3-nmap et, par extension, de Nmap, doit toujours respecter un cadre légal et technique rigoureux. Les scans de réseau, bien qu’utiles pour la sécurité, peuvent être intrusifs, voire perçus comme hostiles s’ils ne sont pas encadrés.
Respect de la législation
- N’effectuez jamais de scan sur des systèmes qui ne vous appartiennent pas ou sans l’accord explicite de leur propriétaire.
- Dans le cadre d’une entreprise, assurez-vous que le périmètre scanné est validé par les responsables réseau et sécurité.
- Certaines juridictions (notamment en Europe) considèrent les scans sans autorisation comme une tentative d’intrusion.
Utilisation responsable de la bande passante
- Évitez de scanner de larges plages d’adresses sans throttling ou limitation de vitesse.
- Privilégiez les scans ciblés avec un nombre limité de ports pour éviter d’engorger le réseau.
Exemple d’ajout d’un délai entre les requêtes :
--scan-delay 1s --max-rate 50
Premier script
Une fois python3-nmap et Nmap installés, vous pouvez créer un premier script pour scanner un hôte. Ce script exécutera un scan des ports les plus courants (top 1000) et retournera les résultats au format JSON.
#!/usr/bin/env python3# -*- coding: utf-8 -*-
"""Exemple de script pour scanner les ports les plus courants sur un hôte"""
import nmap3import json
nmap = nmap3.Nmap()result = nmap.scan_top_ports("scanme.nmap.org")
print(json.dumps(result))
Ce script scanne l’hôte scanme.nmap.org
, un serveur public maintenu par
l’équipe de Nmap pour les tests. Il retourne un dictionnaire JSON contenant
les informations sur les ports ouverts, les services détectés, les états de
ports, etc.
Structure du résultat JSON
Voici un exemple simplifié du type de sortie renvoyée :
{ "45.33.32.156": { "osmatch": {}, "ports": [ { "protocol": "tcp", "portid": "21", "state": "closed", "reason": "conn-refused", "reason_ttl": "0", "service": { "name": "ftp", "method": "table", "conf": "3" }, "cpe": [], "scripts": [] } ], "hostname": [ { "name": "scanme.nmap.org", "type": "user" }, { "name": "scanme.nmap.org", "type": "PTR" } ], "macaddress": null, "state": { "state": "up", "reason": "conn-refused", "reason_ttl": "0" } },}
Explication des éléments clés
- portid : numéro de port détecté
- state : état du port (open, closed, filtered)
- protocol : protocole utilisé (tcp, udp)
- service : nom du service détecté (ex. ssh, http)
- hostname : nom d’hôte scanné
- macaddress : adresse MAC si détectée (généralement vide sauf scan local)
Scans avancés
python3-nmap permet d’aller bien au-delà d’un simple scan de ports sur une cible. Grâce à son interface avec Nmap, vous pouvez effectuer des scans enrichis : détection de version, identification du système d’exploitation, et utilisation de scripts NSE pour explorer les vulnérabilités et les services exposés.
Les scans avancés sont puissants mais souvent plus longs et intrusifs. Utilisez-les avec précaution et uniquement sur des cibles autorisées.
Scan de version des services
Pour identifier les versions des services associés aux ports ouverts :
#!/usr/bin/env python3# -*- coding: utf-8 -*-
"""Exemple de script pour détecter les versions des services sur un hôte"""
import jsonimport nmap3
nmap = nmap3.Nmap()result = nmap.nmap_version_detection("scanme.nmap.org")print(json.dumps(result, indent=2))
Cette méthode utilise l’option -sV
de Nmap, qui interroge les services pour
tenter d’en identifier la version exacte (ex. Apache 2.4.51, OpenSSH 7.9p1,
etc.).
Exemple de sortie :
"data": { "cpe:/a:apache:http_server:2.4.7": { "children": [ { "id": "C94CBDE1-4CC5-5C06-9D18-23CAB216705E", "type": "githubexploit", "is_exploit": "true", "cvss": "10.0" },
Ajouter des options personnalisées
Vous pouvez transmettre n’importe quel argument Nmap via le paramètre args
:
result = nmap.nmap_version_detection( "scanme.nmap.org", args="-sV -O --script vulners")
Scan avec détection d’OS
Pour essayer de déterminer le système d’exploitation distant :
#!/usr/bin/env python3# -*- coding: utf-8 -*-
"""Exemple de script pour détecter le système d'exploitation d'un hôte"""import jsonimport nmap3
nmap = nmap3.Nmap()result = nmap.nmap_os_detection("scanme.nmap.org")print(json.dumps(result, indent=2))
Voici un exemple de sortie pour la détection d’OS :
"45.33.32.156": { "osmatch": [ { "name": "Linux 2.6.32 - 3.13", "accuracy": "96", "line": "56411", "osclass": { "type": "general purpose", "vendor": "Linux", "osfamily": "Linux", "osgen": "3.X", "accuracy": "96" }, "cpe": "cpe:/o:linux:linux_kernel:3" }, ... { "name": "HP P2000 G3 NAS device", "accuracy": "93", "line": "34647", "osclass": { "type": "storage-misc", "vendor": "HP", "osfamily": "embedded", "accuracy": "93" }, "cpe": "cpe:/h:hp:p2000_g3" }, ],
Les résultats incluent des probabilités d’OS détectés, souvent accompagnés de signatures. Dans cet exemple, Nmap a identifié plusieurs versions du noyau Linux et un appareil NAS HP P2000 G3. Chaque correspondance inclut une précision donnée en pourcentage, indiquant la confiance de Nmap dans cette identification.
Exécution de scripts NSE
Les scripts Nmap Scripting Engine (NSE) permettent d’aller encore plus loin
: recherche de vulnérabilités (via vulners
), détection de malware, brute
force, etc.
Voici un exemple d’appel avec le script vulners
:
#!/usr/bin/env python3# -*- coding: utf-8 -*-
"""Exemple de script pour détecter les vulnérabilités des services sur un hôte"""
import jsonimport nmap3
nmap = nmap3.Nmap()result = nmap.nmap_version_detection( "scanme.nmap.org", args="--script vulners")print(json.dumps(result, indent=2))
Le script vulners
interroge la base CVE publique pour chaque service détecté,
en fonction de sa version. On obtient une liste d’ID CVE avec leur score de
criticité (CVSS).
Pour la liste complète des scripts NSE disponibles, consultez nmap.org/nsedoc/ ↗.
Scan de sous-réseau
Pour scanner un sous-réseau complet, vous pouvez utiliser la méthode nmap_subnet_scan
:
#!/usr/bin/env python3# -*- coding: utf-8 -*-
"""Exemple de script pour scanner un sous-réseau"""
import nmap3
nmap = nmap3.Nmap()result = nmap.nmap_subnet_scan("192.168.1.0/29")print(result)
Ce script scanne tous les hôtes du sous-réseau 192.168.1.0/29
. C’est à dire
les adresses de 192.168.1.1
à 192.168.1.6
.
Analyse & parsing des résultats
L’un des grands avantages de python3‑nmap est que les résultats des scans sont retournés directement au format JSON, ce qui facilite grandement leur exploitation dans un script Python. Contrairement à l’approche traditionnelle qui nécessite d’analyser un fichier XML, ici vous avez un objet Python prêt à l’emploi.
Structure des résultats
Si vous avez exécuté un scan sur une plage d’adresses ou un hôte, le résultat sera un dictionnaire où chaque clé est l’adresse IP de l’hôte scanné.
Les résultats sont organisés par hôte, avec des informations sur les ports, services, états, et autres métadonnées. Voici un exemple de structure :
{ "192.168.1.17": { "osmatch": {}, "ports": [ { "protocol": "tcp", "portid": "53", "state": "open", "reason": "syn-ack", "reason_ttl": "127", "service": { "name": "domain", "method": "table", "conf": "3" }, "cpe": [], "scripts": [] }, ], "hostname": [], "macaddress": null, "state": { "state": "up", "reason": "echo-reply", "reason_ttl": "62" } },}
Accès aux données d’un scan de sous-réseau
Pour accéder aux données, vous pouvez parcourir le dictionnaire comme suit :
#!/usr/bin/env python3# -*- coding: utf-8 -*-
"""Exemple de script pour analyser les résultats d'un scan"""import nmap3import json
nmap = nmap3.Nmap()result = nmap.nmap_subnet_scan("192.168.1.92/32")
for ip, data in result.items(): # Ignorer les clés qui ne sont pas des adresses IP (métadonnées) if ip in ["runtime", "stats", "task_results"]: continue
print(f"IP: {ip}")
# Vérifier que data est un dictionnaire avant d'utiliser .get() if isinstance(data, dict): for port in data.get("ports", []): if port["state"] == "open": service_name = port.get('service', {}).get('name', 'Unknown') print(f" Port {port['portid']} ({port['protocol']}) - {service_name}") else: print(f" Données non analysables pour {ip}")
Cela affichera les ports ouverts pour chaque hôte scanné, avec le nom du service si disponible.
Exemple de sortie :
IP: 192.168.1.92 Port 22 (tcp) - ssh Port 53 (tcp) - domain Port 443 (tcp) - https
Vous pouvez adapter ce code pour extraire d’autres informations comme les adresses MAC, les noms d’hôte, ou les systèmes d’exploitation détectés.
Accès aux données d’un scan vulners
Pour accéder aux données d’un scan utilisant le script vulners
, vous pouvez
utiliser le même principe. Voici un exemple de script qui affiche les
vulnérabilités détectées pour chaque service :
#!/usr/bin/env python3# -*- coding: utf-8 -*-
"""Exemple de script pour scanner les ports les plus courants sur un hôte"""
import nmap3import json
nmap = nmap3.Nmap()result = nmap.nmap_version_detection( "192.168.1.92", args="--script vulners")
# print(json.dumps(result, indent=2))
for ip, data in result.items(): # Ignorer les clés qui ne sont pas des adresses IP (métadonnées) if ip in ["runtime", "stats", "task_results"]: continue
print(f"\n=== IP: {ip} ===")
# Vérifier que data est un dictionnaire avant d'utiliser .get() if isinstance(data, dict): for port in data.get("ports", []): if port["state"] == "open": service_name = port.get('service', {}).get('name', 'Unknown') service_product = port.get('service', {}).get('product', 'Unknown') service_version = port.get('service', {}).get('version', 'Unknown')
print(f"\n Port {port['portid']} ({port['protocol']}) - {service_name}") print(f" Service: {service_product} {service_version}")
# Extraire les vulnérabilités du script vulners scripts = port.get('scripts', []) for script in scripts: if script.get('name') == 'vulners': print(f" VULNÉRABILITÉS DÉTECTÉES:")
# Analyser les données structurées des vulnérabilités script_data = script.get('data', {}) for cpe, vuln_info in script_data.items(): print(f" CPE: {cpe}")
# Trier les vulnérabilités par score CVSS (décroissant) vulnerabilities = vuln_info.get('children', []) vulnerabilities.sort(key=lambda x: float(x.get('cvss', 0)), reverse=True)
# Afficher les 5 vulnérabilités les plus critiques for vuln in vulnerabilities[:5]: cvss_score = vuln.get('cvss', 'N/A') vuln_id = vuln.get('id', 'N/A') vuln_type = vuln.get('type', 'N/A') is_exploit = vuln.get('is_exploit', 'false')
exploit_flag = " [EXPLOIT]" if is_exploit == "true" else "" print(f" - {vuln_id} (CVSS: {cvss_score}) [{vuln_type}]{exploit_flag}")
if len(vulnerabilities) > 5: print(f" ... et {len(vulnerabilities) - 5} autres vulnérabilités")
if not script_data: print(" Aucune vulnérabilité structurée trouvée") else: print(f" Données non analysables pour {ip}")
Exemple de sortie :
=== IP: 192.168.1.92 ===
Port 22 (tcp) - ssh Service: OpenSSH 9.2p1 Debian 2+deb12u6 VULNÉRABILITÉS DÉTECTÉES: CPE: cpe:/a:openbsd:openssh:9.2p1 - PACKETSTORM:179290 (CVSS: 10.0) [packetstorm] [EXPLOIT] - 95499236-C9FE-56A6-9D7D-E943A24B633A (CVSS: 10.0) [githubexploit] [EXPLOIT] - 5E6968B4-DBD6-57FA-BF6E-D9B2219DB27A (CVSS: 10.0) [githubexploit] [EXPLOIT] - 56F97BB2-3DF6-5588-82AF-1D7B77F9AD45 (CVSS: 10.0) [githubexploit] [EXPLOIT] - 2C119FFA-ECE0-5E14-A4A4-354A2C38071A (CVSS: 10.0) [githubexploit] [EXPLOIT] ... et 100 autres vulnérabilités
Port 53 (tcp) - domain Service: ISC BIND 9.18.33-1~deb12u2
Port 443 (tcp) - http Service: Golang net/http server Unknown
Ici, nous voyons que le port 22 (SSH) est ouvert, avec une version précise du
service. Le script vulners
a détecté plusieurs vulnérabilités critiques,
chacune avec un score CVSS et une indication si un exploit est disponible.
Utilisation dans des outils
D’ici peu, nous verrons comment intégrer python3‑nmap dans des outils plus complexes, comme des systèmes de gestion de vulnérabilités, des plateformes de pentesting, ou des systèmes d’alerte en temps réel. L’objectif est de montrer comment automatiser les scans et les analyses pour gagner en efficacité et en réactivité face aux menaces.
Conclusion
python3-nmap offre une solution simple et puissante pour automatiser les scans réseau avec Python 3. Grâce à son interface JSON, sa compatibilité avec les scripts NSE, et sa facilité d’intégration dans des outils ou pipelines, il devient un atout essentiel pour tout administrateur ou analyste sécurité souhaitant gagner du temps et améliorer la visibilité de son infrastructure.
N’oubliez pas de toujours respecter les bonnes pratiques éthiques et légales lors de l’utilisation de Nmap et de ses bibliothèques associées. Les scans réseau peuvent être intrusifs et doivent être effectués avec prudence et autorisation.