
Escáner de detección Modbus/TCP multihilo escrito en C usando libmodbus.
Un escáner C multihilo para detectar servicios Modbus/TCP utilizando libmodbus.
El escáner no se basa únicamente en que el puerto TCP 502 esté abierto. En su lugar, establece una conexión Modbus/TCP y envía una solicitud Modbus a nivel de aplicación. Una respuesta Modbus válida se utiliza como indicador principal de que un servicio Modbus está presente.
Modbus es un protocolo de comunicación industrial comúnmente utilizado por PLCs, RTUs, HMIs, sistemas SCADA, sensores, medidores y otros dispositivos industriales.
Modbus/TCP transporta el protocolo de aplicación Modbus sobre TCP.
El puerto estándar de Modbus/TCP es:
TCP/502
Un flujo de comunicación típico es:
Escáner
|
| Conexión TCP → 502
|
| Solicitud Modbus/TCP
v
Dispositivo Modbus
|
| Respuesta Modbus/TCP
v
Escáner
A diferencia de los protocolos que proporcionan un banner inmediatamente después de conectarse, Modbus/TCP generalmente requiere que el cliente envíe una solicitud Modbus válida antes de que el dispositivo produzca una respuesta a nivel de aplicación.
El escáner realiza la detección en dos etapas.
El escáner intenta establecer una conexión TCP con:
<objetivo>:502
Si la conexión no se puede establecer, el objetivo se trata como que no responde a Modbus/TCP.
Sin embargo, un puerto TCP/502 abierto por sí solo no se considera evidencia suficiente de Modbus.
Después de conectarse, el escáner envía una solicitud Modbus utilizando libmodbus.
La sonda principal es:
modbus_read_input_registers(ctx, 0, 1, ®);
Esto genera un Código de Función Modbus:
0x04 - Leer Registros de Entrada
La solicitud pide al objetivo un registro de entrada comenzando en la dirección 0.
Si el objetivo devuelve una respuesta Modbus válida, el escáner considera que el servicio ha sido detectado.
Un paquete Modbus/TCP consiste en:
+----------------------+----------------------+
| Cabecera MBAP | PDU |
+----------------------+----------------------+
Cabecera MBAP:
+------------------+
| ID de Transacción | 2 bytes
| ID de Protocolo | 2 bytes
| Longitud | 2 bytes
| ID de Unidad | 1 byte
+------------------+
PDU:
+------------------+
| Código de Función | 1 byte
| Datos | N bytes
+------------------+
La cabecera MBAP es específica de Modbus/TCP.
La primera sonda del escáner utiliza el Código de Función 0x04.
Una solicitud representativa es:
00 01 00 00 00 06 01 04 00 00 00 01
Desglosando esto:
00 01 Identificador de Transacción
00 00 Identificador de Protocolo
00 06 Longitud
01 Identificador de Unidad
04 Código de Función
00 00 Dirección de Inicio
00 01 Cantidad
00 01
Identifica la transacción.
El valor puede variar porque el identificador de transacción normalmente es gestionado por la librería cliente Modbus.
00 00
Un valor de 0 identifica Modbus.
00 06
Especifica el número de bytes que siguen al campo de longitud.
01
Identifica la unidad Modbus objetivo.
04
El Código de Función 0x04 significa:
Leer Registros de Entrada
00 00
El escáner comienza en la dirección de registro 0.
00 01
El escáner solicita un registro.
Una respuesta exitosa a la solicitud contiene el Código de Función 0x04 y los datos del registro solicitado.
Una respuesta representativa podría verse así:
00 01 00 00 00 05 01 04 02 00 00
Desglosándola:
00 01 Identificador de Transacción
00 00 Identificador de Protocolo
00 05 Longitud
01 Identificador de Unidad
04 Código de Función
02 Conteo de Bytes
00 00 Valor del Registro
La parte importante para la detección es que el objetivo procesa exitosamente la solicitud Modbus y devuelve una respuesta Modbus válida a nivel de aplicación.
El valor real del registro depende del dispositivo.
Simplemente comprobar:
TCP/502 = ABIERTO
no prueba necesariamente que el servicio sea Modbus.
Los números de puerto son convenciones. Una aplicación diferente puede escuchar en TCP/502, y un dispositivo Modbus también puede comportarse de manera diferente dependiendo de su configuración.
Por lo tanto, el escáner utiliza:
Conectividad TCP
+
Respuesta del protocolo Modbus
=
Detección de Modbus
Esto hace que la detección a nivel de aplicación sea más significativa que un simple escaneo de puertos.
Algunos dispositivos pueden no responder a la solicitud inicial 0x04 debido a su configuración de registros o a los códigos de función soportados.
Por lo tanto, el escáner intenta una segunda solicitud si la primera falla:
modbus_read_bits(ctx, 0, 1, bits);
Esto utiliza el Código de Función:
0x01 - Leer Bobinas
Una solicitud representativa es:
00 02 00 00 00 06 01 01 00 00 00 01
Desglose:
00 02 Identificador de Transacción
00 00 Identificador de Protocolo
00 06 Longitud
01 Identificador de Unidad
01 Código de Función
00 00 Dirección de Inicio
00 01 Cantidad
El escáner considera que el objetivo ha sido detectado cuando cualquiera de las operaciones Modbus recibe una respuesta exitosa.
IP Objetivo
|
v
Conexión TCP
puerto 502
|
+------+------+
| |
Fallida Conectada
| |
v v
Ignorar Función 0x04
|
+------+------+
| |
Válida Fallida
| |
v v
MODBUS ENCONTRADO Función 0x01
|
+------+------+
| |
Válida Fallida
| |
v v
MODBUS ENCONTRADO Sin detección
El escáner utiliza libmodbus para construir y analizar paquetes Modbus/TCP en lugar de construir manualmente las tramas del protocolo.
La operación principal es:
modbus_read_input_registers(ctx, 0, 1, ®);
Si esto falla:
modbus_read_bits(ctx, 0, 1, bits);
La conexión se cierra y el contexto de libmodbus se libera.
Esto mantiene el manejo del protocolo dentro de la librería Modbus mientras que el escáner se encarga de:
El escáner utiliza tiempos de espera cortos para la conexión y la respuesta:
#define TIMEOUT_SEC 2
Esto evita que un host inalcanzable o que no responde bloquee a un trabajador durante un tiempo excesivo.
Las redes industriales pueden contener dispositivos con respuestas relativamente lentas, por lo que los valores de tiempo de espera pueden necesitar ajustes dependiendo del entorno.
Los objetivos se dividen entre múltiples hilos de trabajo.
Por ejemplo:
Hilo 1 → objetivos 1–64
Hilo 2 → objetivos 65–128
Hilo 3 → objetivos 129–192
Hilo 4 → objetivos 193–254
Cada trabajador intenta de forma independiente la detección Modbus/TCP.
Esto permite probar múltiples hosts de forma concurrente en lugar de esperar secuencialmente por cada objetivo.
Un resultado positivo significa que el objetivo respondió exitosamente a una solicitud Modbus entendida por el escáner.
No identifica necesariamente:
Esas son tareas separadas de identificación o evaluación.
El escáner es principalmente una herramienta de detección de servicios Modbus/TCP.
El método de detección es intencionalmente conservador.
Un dispositivo puede ser capaz de Modbus pero fallar en la detección si:
Por lo tanto:
Sin respuesta ≠ Definitivamente no es Modbus
Significa que el escáner no pudo obtener una respuesta exitosa utilizando las sondas que intentó.
Instale las dependencias requeridas y compile con:
make
O directamente:
gcc -Wall -Wextra -O2 -o modbus modbus.c -lmodbus -lpthread
Ejecute:
./modbus -i 192.168.1.0 -s /24 -t 10 -o results.txt
Ejemplo:
[+] Modbus detectado: 192.168.1.20:502
[+] Modbus detectado: 192.168.1.42:502
[+] Escaneados: 254 | Encontrados: 2 Modbus
[+] Resultados guardados en: results.txt
El escáner detecta servicios Modbus/TCP realizando una interacción real con el protocolo en lugar de depender exclusivamente de la detección del puerto TCP.
El proceso de detección es:
Conectar a TCP/502
↓
Enviar Código de Función Modbus 0x04
↓
¿Recibir respuesta Modbus válida?
↓
SÍ → Modbus detectado
|
NO
↓
Enviar Código de Función Modbus 0x01
↓
¿Recibir respuesta Modbus válida?
↓
SÍ → Modbus detectado
|
NO
↓
Sin detección
El principio clave es simple:
Detecta el protocolo, no solo el puerto.