
Unsachgemäße Neutralisierung spezieller Elemente in einem SQL-Befehl („SQL Injection“) in SonicWall-SMA1000-Serienappliances ermöglicht es einem entfernten, authentifizierten Angreifer mit schreibgeschützten Administratorrechten, seine Privilegien auf primären Administrator auszuweiten.
Eine Blind-SQL-Injection-Schwachstelle nach der Authentifizierung in der Verwaltungskonsole der SonicWall SMA 8200v (Port 8443) ermöglicht jedem authentifizierten Administrator – einschließlich Konten mit niedrigen Rechten und Nur-Lese-Zugriff – den SHA-512-Passwort-Hash des Hauptadministrators aus der Konfigurationsdatei des Appliances zu extrahieren. Da SonicWall dieselben Anmeldedaten sowohl für den Administrator der Verwaltungskonsole als auch für das Root-Konto des Betriebssystems verwendet, führt das Knacken dieses Hashs zu vollem Root-Zugriff auf das Appliance.
Klassifizierung: Privilege Escalation (Administrator mit niedrigen Rechten zu Root) CVSS 3.1: 7.2 (Hoch) — AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H Angriffskomplexität: Niedrig (automatisierter PoC schließt die Extraktion in ca. 60–90 Minuten ab) Voraussetzungen: Jede gültige Anmeldedaten für die Verwaltungskonsole (einschließlich Nur-Lese-Konten)
| Komponente | Details |
|---|---|
| Plattform | SonicWall SMA 8200v (virtuelles Appliance) |
| Firmware | 12.5.0-02283 (bestätigt); wahrscheinlich alle 12.x |
| Dienst | Verwaltungskonsole — Jetty + Struts 2 (Port 8443) |
| Endpunkt | POST /activeUsers.action |
| Verwundbare Parameter | realmFilter, communityFilter (Cross-Parameter) |
| Ursachenklasse | com.aventail.mgmt.sql.Sql.safeParam() |
| Datenbank | MariaDB 10.11.14, Benutzer DbAdmin (ALLE RECHTE + FILE) |
| Zieldatei | /usr/local/app/mgmt-server/datastore/active/sysconf/avconfig.xml |
Die Verwaltungskonsole erstellt SQL-Abfragen für das Dashboard der aktiven Benutzer mithilfe einer Hilfsmethode safeParam() in der Klasse com.aventail.mgmt.sql.Sql. Diese Methode maskiert einfache Anführungszeichen (') und doppelte Anführungszeichen ("), indem sie diese verdoppelt, maskiert jedoch nicht Backslash-Zeichen (\).
In MySQL/MariaDB ist ein Backslash das Standard-Escape-Zeichen innerhalb von String-Literalen. Die Sequenz \' bewirkt, dass die Datenbank das einfache Anführungszeichen als literales Zeichen interpretiert und nicht als String-Abschluss. Das bedeutet, dass ein Backslash am Ende eines Parameterwerts das schließende Anführungszeichen maskiert, das die Anwendung anhängt, wodurch sich das SQL-String-Literal in die angrenzende Syntax ausdehnt.
Bereinigungslücke:```
Input: test
safeParam output: test\ (backslash NOT escaped)
In SQL: ... rt.name='test') AND (ct.name='...'
^^ backslash escapes the closing quote
Der abschließende `'` nach `test\` wird als wörtliches Anführungszeichen innerhalb des Strings konsumiert, sodass sich das SQL-String-Literal über die Grenze `) AND (ct.name='` hinweg und in den Wert des nächsten Parameters erstreckt, wo angreiferkontrolliertes SQL injiziert werden kann.
### 3.2 Injektionsmechanik: Parallele-Parameter-Technik
Der Endpunkt `activeUsers.action` akzeptiert mehrere Filterparameter, die in eine einzelne SQL-WHERE-Klausel interpoliert werden. Die relevanten Parameter sind `realmFilter` und `communityFilter`, die in einer Abfrage erscheinen, die ungefähr wie folgt strukturiert ist:```sql
SELECT ... FROM ...
WHERE ...
AND (rt.name='<realmFilter>')
AND (ct.name='<communityFilter>')
...
Angriffsparameter-Setup:
| Parameter | Wert | Zweck |
|---|---|---|
realmFilter | test\ | Nachgestellter Backslash escaped das schließende Anführungszeichen und erweitert das String-Literal über die AND-Grenze hinweg |
communityFilter | )) OR (SELECT IF(<condition>,SLEEP(N),0))-- x | Schließt die offenen Klammern, injiziert ein bedingtes SLEEP und kommentiert den Rest aus |
Resultierendes SQL nach der Interpolation:```sql WHERE ... AND (rt.name='test') AND (ct.name=' )) OR (SELECT IF(,SLEEP(N),0))-- x')
Aufschlüsselung:
1. `rt.name='test\')` — das `\` escaped das `'`, sodass der String hier nicht geschlossen wird
2. `AND (ct.name='` — wird Teil des String-Werts (wörtlicher Text)
3. Der String schließt schließlich beim nächsten `'` (vom Beginn von `communityFilter`)
4. `))` — schließt die zwei offenen Klammern aus der WHERE-Klausel-Struktur
5. `OR (SELECT IF(...))` — injiziert die blinde SQLi-Bedingung
6. `-- x` — kommentiert das restliche SQL aus (`')` und andere Klauseln)
### 3.3 Zeitbasierte Blind-Extraktion
Da die Struts-2-Fehlerbehandlung der Anwendung SQL-Ausnahmen elegant abfängt (immer HTTP 200 mit demselben Seiteninhalt zurückgibt, unabhängig davon, ob die Abfrage erfolgreich ist oder fehlschlägt), sind fehlerbasierte und UNION-basierte Extraktionsmethoden nicht praktikabel. Die Injektion wird mithilfe der zeitbasierten Blind-Technik ausgenutzt:
- **TRUE-Bedingung:** `IF(<condition>, SLEEP(N), 0)` — Antwort verzögert um die SLEEP-Dauer multipliziert mit der Zeilenanzahl des Ergebnissatzes
- **FALSE-Bedingung:** Kein SLEEP — Antwort erfolgt in ~200-500ms
Die SLEEP-Funktion wird pro Zeile bei der Auswertung der WHERE-Klausel ausgeführt. Bei einer typischen Überwachungstabelle mit 30-300+ Zeilen erzeugt selbst ein kleiner SLEEP-Wert (z. B. 0,3s) eine klar unterscheidbare Verzögerung (10-100s für TRUE vs. <1s für FALSE).
Jedes Zeichen der Zieldaten wird mittels binärer Suche über den ASCII-Bereich extrahiert:```sql
ORD(SUBSTRING((<extraction_expr>), <position>, 1)) > <midpoint>
Dies erfordert maximal 7 Anfragen pro Zeichen (log2(128) = 7), was insgesamt ~686 Anfragen für einen 98 Zeichen langen SHA-512-Hash ergibt.
PRIVILEGE ESCALATION CHAIN
============================================================================
[1] Authenticate Low-privilege admin (e.g., "readonly") | authenticates to management console on port 8443 | using "Local Authentication" realm v [2] SQL Injection Cross-parameter blind SQLi via activeUsers.action | realmFilter backslash + communityFilter payload | Condition: IF(, SLEEP(N), 0) v [3] LOAD_FILE() MariaDB DbAdmin user has FILE privilege | secure_file_priv=NULL does NOT block reads | avconfig.xml is group-readable (mode 664) v [4] Locate Hash LOCATE('consoleMode', file) anchors to admin section | LOCATE('', file, anchor) finds hash element | SUBSTRING + SUBSTRING_INDEX extracts hash value v [5] Extract Hash Binary search extracts hash char-by-char | ~98 chars * ~7 requests = ~686 requests | Output: $6$$ (SHA-512 crypt) v [6] Crack Hash hashcat -m 1800 / john --format=sha512crypt | Admin password = Root SSH password (by design) v [7] Full Compromise SSH as root, management console as admin Complete appliance takeover
### 4.2 Schritt 1: Authentifizierung
Die SMA-Verwaltungskonsole unterstützt zwei Authentifizierungsbereiche:
| Bereichs-ID | Anzeigename | Benutzer |
|----------|-------------|-------|
| *(leer)* | Verwaltungskonsole | Nur primäres Administratorkonto |
| `AMCAuthRealm` / `Lokale Authentifizierung` | Lokale Authentifizierung | Sekundäre Administratorkonten (readonly, custom) |