
Divulgation et PoC d'une faille de lecture/écriture de fichiers root dans le canal de débogage du TP-Link Deco XE75 Pro V3 (opcodes tmpsvr 0xC456/0xF0), avec analyse CVSS et décompilation du gestionnaire.
Projet VLAN associé : alpha expérimental de source à VLAN 30 fixe pour le firmware/profil exact du XE75 Pro V3. Il nécessite des fichiers d'origine fournis par l'opérateur et ne dispose d'aucun installateur général ni d'image flashable. Le VLAN invité 591 reste non résolu ; l'acceptation finale de démarrage à froid sur trois unités, de l'interface utilisateur et de l'isolation des clients est incomplète. Voir l'état actuel.
Divulgation de recherche, TP-Link Deco XE75 Pro V3, firmware 1.5.0 Build
20260603 Rel.15804. Préparée pour [email protected] et publication publique parallèlement à notre implémentation VLAN IoT 802.1Q (deco-iot-vlan).
Le canal SSH de débogage authentifié par le propriétaire du Deco (Dropbear sur TCP 20001,
transfert direct-tcpip uniquement, authentification par mot de passe) atteint un
service interne tmpsvr sur 127.0.0.1:20002. L'un de ses gestionnaires Lua,
inner_file_push (opcode 0xC456), ouvre params.file en mode "w" et
écrit params.content tel quel en tant que root, sans liste blanche de chemins, sans limite
de taille et sans abandon de privilèges. Un opcode frère (0xF0) fournit une
lecture de fichier root correspondante. Ensemble : lecture + écriture authentifiées de l'intégralité
du système de fichiers root, ce qui, sur un routeur, représente l'appareil entier.
SSH :20001 (username = SHA1(owner_email), password = TP-Link account password)
-> direct-tcpip -> 127.0.0.1:20002 (TMPv2)
-> 0xC456 inner_file_push : io.open(file,"w"); write(content); close() [root]
-> 0x00F0 root file read : byte-exact file read [root]
/etc/config est un ramfs inscriptible actif → modifiez une clé, le routeur l'applique./www est servi via HTTPS par uhttpd → les fichiers poussés sont immédiatement accessibles./tp_data/user_data est une mémoire flash ubifs persistante → survit au redémarrage.GET /cgi-bin/luci → exécution de Lua en root → io.popen → exécution arbitraire de binaires
en root.Les quatre étapes ont été exécutées puis annulées sur l'unité principale appartenant au propriétaire.
tmpsvr n'est toujours pas corrigé 2 ans après CCS'24 / Black Hat '24L'équipe UCR SecLab a documenté publiquement le canal de débogage :20001 -> 127.0.0.1:20002 (tmpsvr) il y a deux ans dans CCS 2024 — « Untangling the Knot: Breaking Access Control in Home Wireless Mesh Networks » (et Black Hat USA 2024 — « Fallen Tower of Babel »). Leur point d'entrée sur les anciens modèles Deco (X55, FW 1.2.2) consistait à factoriser des clés d'hôte RSA de 512 bits et à abuser de gestionnaires tmpsvr non validés.
Différences observées et gestionnaires restants sur ce firmware exact :
ssh-rsa de 512 bits à 2048 bits (une clé partagée observée sur les trois unités mesh, SHA256:9feb3ac4...932a36, plus une clé ecdsa-sha2-nistp521 par unité), fermant ainsi la voie de factorisation 512 bits de la présentation de 2024.1.5.0 :
:20001 (svr_auth_uci) reste active en utilisant SHA1(owner_email) + le mot de passe partagé du compte TP-Link ID.0xC456 (inner_file_push) ouvre toujours n'importe quel chemin fourni par l'appelant en mode "w" en tant que root, sans aucune validation du chemin.0x00F0 lit toujours n'importe quel fichier du système de fichiers en tant que root.0xC505 (tty2tcp/start) — le gestionnaire d'injection de commandes /bin/sh -c non échappé exact mis en évidence dans l'article de 2024 — est toujours présent dans le firmware de juin 2026 (1.5.0), totalement non corrigé.luci/controller/admin/mobile_app/iot_device,
inner_file_push).Seule l'accessibilité depuis le LAN a été démontrée. Pour le profil observé limité au LAN, nous utilisons les variantes AV:A : v3.1 6.8 / v4.0 8.5. Les scores AV:N ci-dessous sont conditionnels à la démonstration d'un chemin réseau ; l'accessibilité depuis le cloud n'est pas vérifiée.
Il s'agit d'une escalade vers root post-authentification, avec les privilèges du propriétaire — et non d'une
RCE non authentifiée — les scores du profil observé ci-dessous sont 6.8 (v3.1) et 8.5 (v4.0). La justification complète et les
surestimations rejetées figurent dans docs/cvss-analysis.md.
CVSS v3.1 — évaluation limitée au LAN 6.8 (Moyen) ; variante distante conditionnelle 7.2 (Élevé) :
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H = 7.2 (High)
CVSS:3.1/AV:A/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H = 6.8 (Medium) # if LAN-only
Appels décisifs : PR:H (le propriétaire / compte TP-Link-ID est le principal administratif de l'appareil) et S:U (le gestionnaire s'exécute déjà en tant que root — aucune frontière d'autorité n'est franchie). Une version antérieure avait obtenu 9.9 via PR:L + S:C ; les deux sont rejetés.
CVSS v4.0 — évaluation LAN uniquement 8.5 (Élevé) ; variante distante conditionnelle 8.6 (Élevé) :
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N = 8.6 (High)
CVSS:4.0/AV:A/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N = 8.5 (High) # if LAN-only
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:L = 9.3 (Critical) # with Subsequent-System LAN/mesh impact
Le risque réel — un mot de passe TP-Link-ID volé/réutilisé se transformant en
root persistant sur l'ensemble du maillage, plus un MITM du trafic client — relève de la
narration (et des métriques v4.0 SC:H/SI:H/SA:L Subsequent-System), et non d'un
vecteur de base v3.1 gonflé.
poc/deco_filepush_poc.py — autonome (stdlib + paramiko). Identifiants
uniquement via les variables d'environnement DECO_EMAIL / DECO_PASSWORD. Les modes live nécessitent
DECO_HOSTKEY, vérifié indépendamment : base64 brut, une ligne de clé publique, ou une
ligne de clé ssh-keyscan (commentaires pris en charge). Un simple scan n'authentifie pas
l'appareil. La vérification HTTPS compare les octets servis mais ne vérifie pas son certificat.
Un seul mode est requis ; une vérification échouée se termine avec un code non nul.
python3 poc/deco_filepush_poc.py --selftest # offline framing sanity
[email protected] DECO_PASSWORD=*** DECO_HOSTKEY="$TRUSTED_DECO_HOSTKEY" \
python3 poc/deco_filepush_poc.py --run # write marker + readback + HTTPS check
[email protected] DECO_PASSWORD=*** DECO_HOSTKEY="$TRUSTED_DECO_HOSTKEY" \
python3 poc/deco_filepush_poc.py --cleanup <nonce> # overwrite marker with empty content
Le PoC écrit un unique marqueur inerte dans /www/log_export (ramfs ; également
effacé au redémarrage), puis exige une relecture octet pour octet via l'opcode
de lecture root propre à l'appareil et un service HTTPS non modifié avant de
signaler le succès.