
Divulgación y PoC de una vulnerabilidad de lectura/escritura de archivos root en el canal de depuración del TP-Link Deco XE75 Pro V3 (opcodes tmpsvr 0xC456/0xF0), con análisis CVSS y descompilación del handler.
Proyecto VLAN complementario: alpha experimental de código fuente con VLAN 30 fija para el firmware/perfil exacto del XE75 Pro V3. Requiere archivos originales (stock) proporcionados por el operador y no dispone de instalador general ni de imagen flasheable. La VLAN de invitados 591 sigue sin resolverse; la aceptación final de arranque en frío, interfaz de usuario y aislamiento de clientes con tres unidades está incompleta. Consulte el estado actual.
Divulgación de investigación, TP-Link Deco XE75 Pro V3, firmware 1.5.0 Build
20260603 Rel.15804. Preparado para [email protected] y publicación pública junto con nuestra implementación de VLAN IoT 802.1Q (deco-iot-vlan).
El canal SSH de depuración autenticado por el propietario del Deco (Dropbear en TCP 20001, solo reenvío direct-tcpip, autenticación por contraseña) alcanza un servicio interno tmpsvr en 127.0.0.1:20002. Uno de sus manejadores Lua, inner_file_push (opcode 0xC456), abre params.file en modo "w" y escribe params.content tal cual como root, sin lista de rutas permitidas, sin límite de tamaño y sin reducción de privilegios. Un opcode hermano (0xF0) proporciona una lectura de archivos como root equivalente. En conjunto: lectura + escritura autenticadas de todo el sistema de archivos raíz, que en un router es el dispositivo completo.
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 es un ramfs escribible en vivo → cambia una clave y el router la respeta./www se sirve a través de HTTPS por uhttpd → los archivos subidos son accesibles de inmediato./tp_data/user_data es flash ubifs persistente → sobrevive al reinicio.GET /cgi-bin/luci → ejecución de Lua como root → io.popen → ejecución arbitraria de
binarios como root.Los cuatro pasos se ejecutaron y se revirtieron en la unidad principal del propio propietario.
tmpsvr sigue sin corregir 2 años después de CCS'24 / Black Hat '24El equipo de UCR SecLab documentó públicamente el canal de depuración :20001 -> 127.0.0.1:20002 (tmpsvr) hace dos años en CCS 2024 — "Untangling the Knot: Breaking Access Control in Home Wireless Mesh Networks" (y Black Hat USA 2024 — "Fallen Tower of Babel"). Su punto de entrada en modelos Deco más antiguos (X55, FW 1.2.2) fue la factorización de hostkeys RSA de 512 bits y el abuso de manejadores tmpsvr no validados.
Diferencias observadas y manejadores restantes en este firmware exacto:
ssh-rsa de 512 bits a 2048 bits (una clave compartida observada en las tres unidades de malla, SHA256:9feb3ac4...932a36, más ecdsa-sha2-nistp521 por unidad), cerrando la ruta de factorización de 512 bits de la charla de 2024.1.5.0:
:20001 (svr_auth_uci) sigue activa usando SHA1(owner_email) + la contraseña compartida de TP-Link ID.0xC456 (inner_file_push) todavía abre cualquier ruta proporcionada por el llamador en modo "w" como root sin ninguna validación de ruta.0x00F0 todavía lee cualquier archivo del sistema de archivos como root.0xC505 (tty2tcp/start) — el manejador exacto de inyección de comandos /bin/sh -c sin comillas destacado en el artículo de 2024 — sigue presente en el firmware de junio de 2026 (1.5.0) completamente sin corregir.luci/controller/admin/mobile_app/iot_device,
inner_file_push).Solo se ha demostrado la accesibilidad desde la LAN. Para el perfil observado de solo LAN usamos las variantes AV:A: v3.1 6.8 / v4.0 8.5. Las puntuaciones AV:N a continuación son condicionales a una ruta de red demostrada; la accesibilidad desde la nube no está verificada.
Esta es una escalada a root post-autenticación, con privilegios del propietario — no un
RCE sin autenticación — las puntuaciones del perfil observado a continuación son 6.8 (v3.1) y 8.5 (v4.0). La justificación completa y las
inflaciones rechazadas están en docs/cvss-analysis.md.
CVSS v3.1 — evaluación de solo LAN 6.8 (Medio); variante remota condicional 7.2 (Alto):
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
Llamadas decisivas: PR:H (el propietario / la cuenta TP-Link-ID es el principal administrativo del dispositivo) y S:U (el manejador ya se ejecuta como root — no se cruza ningún límite de autoridad). Un borrador anterior obtuvo 9.9 mediante PR:L + S:C; ambos son rechazados.
CVSS v4.0 — evaluación solo LAN 8.5 (Alta); variante remota condicional 8.6 (Alta):
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
El riesgo del mundo real —una contraseña de TP-Link-ID robada o reutilizada que se convierte en root persistente en toda la malla, además de MITM del tráfico de clientes— pertenece a la narrativa (y a las métricas Subsequent-System SC:H/SI:H/SA:L de la v4.0), no a un vector base v3.1 inflado.
poc/deco_filepush_poc.py — autocontenido (stdlib + paramiko). Credenciales
solo mediante las variables de entorno DECO_EMAIL / DECO_PASSWORD. Los modos en vivo requieren
DECO_HOSTKEY, verificado de forma independiente: base64 sin procesar, una línea de clave pública o una
línea de clave de ssh-keyscan (se admiten comentarios). Un escaneo por sí solo no autentica
el dispositivo. La comprobación HTTPS compara los bytes servidos pero no verifica su certificado.
Se requiere exactamente un modo; si la verificación falla, la salida es distinta de cero.
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
El PoC escribe un único marcador inerte en /www/log_export (ramfs; también
se borra al reiniciar), luego requiere lectura de vuelta byte a byte a través del
propio opcode de lectura de root del dispositivo y servicio HTTPS sin modificaciones antes de reportar
éxito.