
Scanner de détection Modbus/TCP multithreadé écrit en C utilisant libmodbus.
Un scanner C multithreadé pour détecter les services Modbus/TCP utilisant libmodbus.
Le scanner ne se fie pas uniquement à l'ouverture du port TCP 502. Au lieu de cela, il établit une connexion Modbus/TCP et envoie une requête Modbus au niveau de la couche application. Une réponse Modbus valide est utilisée comme indicateur principal de la présence d'un service Modbus.
Modbus est un protocole de communication industrielle couramment utilisé par les automates programmables (PLC), les unités terminales distantes (RTU), les interfaces homme-machine (HMI), les systèmes SCADA, les capteurs, les compteurs et autres dispositifs industriels.
Modbus/TCP transporte le protocole applicatif Modbus sur TCP.
Le port Modbus/TCP standard est :
TCP/502
Un flux de communication typique est :
Scanner
|
| Connexion TCP → 502
|
| Requête Modbus/TCP
v
Dispositif Modbus
|
| Réponse Modbus/TCP
v
Scanner
Contrairement aux protocoles qui fournissent une bannière immédiatement après la connexion, Modbus/TCP exige généralement que le client envoie une requête Modbus valide avant que le dispositif ne produise une réponse au niveau de la couche application.
Le scanner effectue la détection en deux étapes.
Le scanner tente d'établir une connexion TCP vers :
<cible>:502
Si la connexion ne peut pas être établie, la cible est considérée comme ne répondant pas à Modbus/TCP.
Cependant, un port TCP/502 ouvert en soi n'est pas considéré comme une preuve suffisante de la présence de Modbus.
Après la connexion, le scanner envoie une requête Modbus en utilisant libmodbus.
La sonde principale est :
modbus_read_input_registers(ctx, 0, 1, ®);
Cela génère un code de fonction Modbus :
0x04 - Lecture des registres d'entrée
La requête demande à la cible un registre d'entrée commençant à l'adresse 0.
Si la cible renvoie une réponse Modbus valide, le scanner considère le service comme détecté.
Un paquet Modbus/TCP se compose de :
+----------------------+----------------------+
| En-tête MBAP | PDU |
+----------------------+----------------------+
En-tête MBAP :
+------------------+
| Identifiant de transaction | 2 octets
| Identifiant de protocole | 2 octets
| Longueur | 2 octets
| Identifiant d'unité | 1 octet
+------------------+
PDU :
+------------------+
| Code de fonction | 1 octet
| Données | N octets
+------------------+
L'en-tête MBAP est spécifique à Modbus/TCP.
La première sonde du scanner utilise le code de fonction 0x04.
Une requête représentative est :
00 01 00 00 00 06 01 04 00 00 00 01
Décomposition :
00 01 Identifiant de transaction
00 00 Identifiant de protocole
00 06 Longueur
01 Identifiant d'unité
04 Code de fonction
00 00 Adresse de départ
00 01 Quantité
00 01
Identifie la transaction.
La valeur peut varier car l'identifiant de transaction est normalement géré par la bibliothèque cliente Modbus.
00 00
Une valeur de 0 identifie Modbus.
00 06
Spécifie le nombre d'octets suivant le champ de longueur.
01
Identifie l'unité Modbus cible.
04
Le code de fonction 0x04 signifie :
Lecture des registres d'entrée
00 00
Le scanner commence à l'adresse de registre 0.
00 01
Le scanner demande un registre.
Une réponse réussie à la requête contient le code de fonction 0x04 et les données du registre demandé.
Une réponse représentative pourrait ressembler à :
00 01 00 00 00 05 01 04 02 00 00
Décomposition :
00 01 Identifiant de transaction
00 00 Identifiant de protocole
00 05 Longueur
01 Identifiant d'unité
04 Code de fonction
02 Nombre d'octets
00 00 Valeur du registre
L'élément important pour la détection est que la cible traite avec succès la requête Modbus et renvoie une réponse Modbus valide au niveau de la couche application.
La valeur réelle du registre dépend du dispositif.
Vérifier simplement :
TCP/502 = OUVERT
ne prouve pas nécessairement que le service est Modbus.
Les numéros de port sont des conventions. Une application différente peut écouter sur TCP/502, et un dispositif Modbus peut également se comporter différemment selon sa configuration.
Le scanner utilise donc :
Connectivité TCP
+
Réponse au protocole Modbus
=
Détection Modbus
Cela rend la détection au niveau de la couche application plus significative qu'un simple scan de port.
Certains dispositifs peuvent ne pas répondre à la requête initiale 0x04 en raison de leur configuration de registres ou des codes de fonction pris en charge.
Le scanner tente donc une seconde requête si la première échoue :
modbus_read_bits(ctx, 0, 1, bits);
Cela utilise le code de fonction :
0x01 - Lecture des bobines
Une requête représentative est :
00 02 00 00 00 06 01 01 00 00 00 01
Décomposition :
00 02 Identifiant de transaction
00 00 Identifiant de protocole
00 06 Longueur
01 Identifiant d'unité
01 Code de fonction
00 00 Adresse de départ
00 01 Quantité
Le scanner considère la cible comme détectée lorsque l'une ou l'autre des opérations Modbus reçoit une réponse réussie.
IP cible
|
v
Connexion TCP
port 502
|
+------+------+
| |
Échec Connecté
| |
v v
Ignorer Fonction 0x04
|
+------+------+
| |
Valide Échec
| |
v v
MODBUS TROUVÉ Fonction 0x01
|
+------+------+
| |
Valide Échec
| |
v v
MODBUS TROUVÉ Aucune détection
Le scanner utilise libmodbus pour construire et analyser les paquets Modbus/TCP plutôt que de construire manuellement les trames du protocole.
L'opération principale est :
modbus_read_input_registers(ctx, 0, 1, ®);
Si cela échoue :
modbus_read_bits(ctx, 0, 1, bits);
La connexion est ensuite fermée et le contexte libmodbus est libéré.
Cela maintient la gestion du protocole dans la bibliothèque Modbus tandis que le scanner gère :
Le scanner utilise des délais d'attente courts pour la connexion et la réponse :
#define TIMEOUT_SEC 2
Cela empêche qu'un hôte unique injoignable ou non réactif ne bloque un worker pendant une durée excessive.
Les réseaux industriels peuvent contenir des dispositifs avec des réponses relativement lentes, donc les valeurs de délai d'attente peuvent devoir être ajustées selon l'environnement.
Les cibles sont réparties entre plusieurs threads workers.
Par exemple :
Thread 1 → cibles 1–64
Thread 2 → cibles 65–128
Thread 3 → cibles 129–192
Thread 4 → cibles 193–254
Chaque worker tente indépendamment la détection Modbus/TCP.
Cela permet de tester plusieurs hôtes simultanément plutôt que d'attendre séquentiellement chaque cible.
Un résultat positif signifie que la cible a répondu avec succès à une requête Modbus comprise par le scanner.
Cela n'identifie pas nécessairement :
Ce sont des tâches distinctes d'empreinte numérique ou d'évaluation.
Le scanner est principalement un outil de détection de services Modbus/TCP.
La méthode de détection est volontairement prudente.
Un dispositif peut être compatible Modbus mais échouer à la détection si :
Par conséquent :
Aucune réponse ≠ Définitivement pas Modbus
Cela signifie que le scanner n'a pas pu obtenir une réponse réussie en utilisant les sondes qu'il a tentées.
Installez les dépendances requises et compilez avec :
make
Ou directement :
gcc -Wall -Wextra -O2 -o modbus modbus.c -lmodbus -lpthread
Exécutez :
./modbus -i 192.168.1.0 -s /24 -t 10 -o results.txt
Exemple :
[+] Modbus détecté : 192.168.1.20:502
[+] Modbus détecté : 192.168.1.42:502
[+] Scannés : 254 | Trouvés : 2 Modbus
[+] Résultats enregistrés dans : results.txt
Le scanner détecte les services Modbus/TCP en effectuant une interaction réelle avec le protocole plutôt qu'en se fiant exclusivement à la détection du port TCP.
Le processus de détection est :
Connexion à TCP/502
↓
Envoi du code de fonction Modbus 0x04
↓
Réception d'une réponse Modbus valide ?
↓
OUI → Modbus détecté
|
NON
↓
Envoi du code de fonction Modbus 0x01
↓
Réception d'une réponse Modbus valide ?
↓
OUI → Modbus détecté
|
NON
↓
Aucune détection
Le principe clé est simple :
Détectez le protocole, pas seulement le port.