
Sicher erkennen, ob ein UniFi OS Server anfällig für CVE-2026-34908 ist.
Ein sicherer Detektor für die unauthentifizierte Remote-Codeausführungskette in UniFi OS Server ≤ 5.0.6, veröffentlicht in Ubiquitis Security Advisory Bulletin 064:
| CVE | Klasse | Rolle in der Kette |
|---|---|---|
| CVE-2026-34908 / CVE-2026-34909 | Unzureichende Zugriffskontrolle / Pfad-Traversal | Auth-Gateway-Bypass (der Einstieg) |
| CVE-2026-34910 | Unzureichende Eingabevalidierung → Befehlsinjektion | Unauthentifizierte RCE via Bypass erreicht |
Behoben in UniFi OS Server 5.0.8.
Ja. Der Detektor ist für den Produktions- und Bewertungseinsatz ausgelegt:
GET.VULNERABLE-Urteil erfordert sowohl, dass der Auth-Bypass den verwundbaren Handler erreicht hat, als auch, dass eine Basislinien-Anfrage (gleicher Endpunkt, kein Bypass) korrekt mit 401 abgewiesen wurde.UniFi OS schaltet seinen Diensten ein nginx vor, das die Authentifizierung über eine Subanfrage erzwingt. Diese Authentifizierungsprüfung behandelt jede Anfrage, deren roher URI mit /api/auth/validate-sso/ beginnt, als öffentlich, aber nginx leitet an das Backend mit dem normalisierten URI weiter (es dekodiert %2f→/ und kürzt ../). Eine Anfrage wie:
GET /api/auth/validate-sso/..%2f..%2f..%2fproxy/users/api/v2/ucs/update/latest_package
wird daher als öffentlich behandelt (roher Präfix), aber an den authentifizierten internen Paketaktualisierungs-Endpunkt weitergeleitet (normalisierter Pfad). Ohne pkg_name antwortet dieser Endpunkt mit query param pkg_name required – ein Beweis, dass der Bypass funktioniert und der verwundbare Handler erreichbar ist.
| Sondenantwort | Urteil |
|---|---|
200 + Handler-Fehlermarker | VULNERABLE |
400 (nginx lehnt die Abweichung ab) | PATCHED (5.0.8+) |
401, UniFi-OS-Fingerabdruck vorhanden | INCONCLUSIVE (Authentifizierung erzwungen / Bypass blockiert) |
401, kein UniFi-OS-Fingerabdruck | UNAFFECTED (kein UniFi OS Server) |
| Sonstiges, kein UniFi-OS-Fingerabdruck | UNAFFECTED (kein UniFi OS Server) |
| Sonstiges, UniFi-OS-Fingerabdruck vorhanden | INCONCLUSIVE (unerwartete Antwort) |
Der Detektor sendet außerdem eine Basislinien-Anfrage an denselben Endpunkt ohne den Bypass und fordert, dass diese 401 zurückgibt, bevor ein Host als verwundbar deklariert wird. Die Prüfung testet das verwundbare Verhalten direkt – ein VULNERABLE-Urteil bedeutet, dass der Bypass tatsächlich die Senke erreicht hat.
Immer wenn die Sonde nicht positiv VULNERABLE oder PATCHED bestätigt, ruft der Detektor die Stammseite ab und sucht nach dem UniFi-OS-Managementportal-Fingerabdruck (<title>UniFi OS</title>, window.UNIFI_OS_MANIFEST, id="portal-root", id="site-manager_portal-container"). Dies gilt auch für eine 401-Antwort: Ein UniFi-OS-Host, der die Authentifizierung für den Bypass erzwingt, ist INCONCLUSIVE, aber ein Nicht-UniFi-Proxy, der einfach alles mit 401 beantwortet, trägt keinen Fingerabdruck und wird als UNAFFECTED gemeldet. Also ist jedes "nicht verwundbare" Ergebnis durch den Fingerabdruck fundiert: Marker vorhanden → INCONCLUSIVE; Marker fehlen → UNAFFECTED (die CVE trifft nicht zu).
# einzelner Host (Standardport 11443)
./cve_2026_34908_check.py 192.168.1.10
# expliziter Port / URL-Formate
./cve_2026_34908_check.py host-a:11443 https://host-b
# Liste scannen, ein Ziel pro Zeile ('#'-Kommentare erlaubt), kompakte Ausgabe
./cve_2026_34908_check.py -f targets.txt --brief
# maschinenlesbare Ausgabe für Pipelines
./cve_2026_34908_check.py -f targets.txt --json > results.json
| Flag | Beschreibung |
|---|---|
targets | Ein oder mehrere host, host:port oder https://host:port |
-f, --targets-file DATEI | Ziele aus einer Datei einlesen (eines pro Zeile; #-Kommentare) |
--brief | Einzelne ausgerichtete Zeile pro Ziel – ideal zum Scannen vieler Hosts |
--json | Strukturierte JSON-Ergebnisse ausgeben |
--timeout SEK | Timeout pro Anfrage (Standard: 10) |
--no-color | Farbige Ausgabe deaktivieren (beachtet auch NO_COLOR und Nicht-TTY) |
Eine verwundbare Konsole (ausführlich, Standard). Die zweite Zeile enthält die Details zum Urteil; der Marker [!] und VULNERABLE werden auf einem TTY in Rot dargestellt:
$ ./cve_2026_34908_check.py 192.168.1.10
[!] 192.168.1.10:11443: VULNERABLE
auth bypass reached the vulnerable handler (no command executed); baseline correctly 401
Eine gepatchte Konsole (5.0.8+):
$ ./cve_2026_34908_check.py 192.168.1.11
[+] 192.168.1.11:11443: PATCHED
nginx rejected the normalized-path divergence (HTTP 400) — 5.0.8+ behavior
Ein bestätigter UniFi OS Host, den die Sonde nicht klassifizieren konnte → INCONCLUSIVE. Die Detailzeile unterscheidet die beiden Fälle (Auth erzwungen vs. unerwartete Antwort):
$ ./cve_2026_34908_check.py 192.168.1.12 192.168.1.13
[?] 192.168.1.12:11443: INCONCLUSIVE
bypass blocked / auth enforced (HTTP 401) on a confirmed UniFi OS host — not confirmed vulnerable
[?] 192.168.1.13:11443: INCONCLUSIVE
UniFi OS detected, but probe returned an unexpected response: HTTP 302 text/html
Ein Host, der überhaupt kein UniFi OS ist → UNAFFECTED (das Advisory trifft nicht zu):
$ ./cve_2026_34908_check.py 203.0.113.9:443
[-] 203.0.113.9:443: UNAFFECTED
no UniFi OS web fingerprint on / (probe HTTP 404) — target is not a UniFi OS Server
Liste scannen, eine ausgerichtete Zeile pro Host (--brief). Exit-Status ist 1, wenn irgendein Host VULNERABLE ist, sonst 0 – praktisch in Skripten:
$ ./cve_2026_34908_check.py -f targets.txt --brief; echo "exit: $?"
VULNERABLE 192.168.1.10:11443
PATCHED 192.168.1.11:11443
INCONCLUSIVE 192.168.1.12:11443
UNAFFECTED 203.0.113.9:443
ERROR 10.0.0.1:11443 timeout
exit: 1
Maschinenlesbare Ausgabe für Pipelines (--json). Jedes Ergebnis enthält das verdict sowie den zugrundeliegenden bypass.state/bypass.detail; ERROR-Ergebnisse enthalten ein error-Feld anstelle von bypass:
$ ./cve_2026_34908_check.py 192.168.1.10 192.168.1.11 10.0.0.1 --json
[
{
"target": "192.168.1.10:11443",
"bypass": {
"state": "vulnerable",
"detail": "auth bypass reached the vulnerable handler (no command executed); baseline correctly 401"
},
"verdict": "VULNERABLE"
},
{
"target": "192.168.1.11:11443",
"bypass": {
"state": "patched",
"detail": "nginx rejected the normalized-path divergence (HTTP 400) — 5.0.8+ behavior"
},
"verdict": "PATCHED"
},
{
"target": "10.0.0.1:11443",
"verdict": "ERROR",
"error": "timeout"
}
]