
Neutralisation inappropriée d'éléments spéciaux utilisés dans une commande SQL (« injection SQL ») dans les appliances de la série SonicWall SMA1000, permettant à un attaquant distant authentifié disposant de privilèges d'administrateur en lecture seule d'élever ses privilèges jusqu'à ceux d'administrateur principal.
Une vulnérabilité d'injection SQL aveugle post-authentification dans la console de gestion SonicWall SMA 8200v (port 8443) permet à tout administrateur authentifié — y compris les comptes en lecture seule à faibles privilèges — d'extraire le hash SHA-512 du mot de passe de l'administrateur principal à partir du fichier de configuration de l'appliance. Étant donné que SonicWall utilise les mêmes identifiants pour l'administrateur de la console de gestion et le compte root du système d'exploitation, le craquage de ce hash permet un accès root complet à l'appliance.
Classification : Élévation de privilèges (administrateur à faibles privilèges vers Root) CVSS 3.1 : 7,2 (Élevé) — AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H Complexité de l'attaque : Faible (le PoC automatisé termine l'extraction en ~60-90 minutes) Prérequis : Tout identifiant valide de console de gestion (y compris les comptes en lecture seule)
| Composant | Détails |
|---|---|
| Plateforme | SonicWall SMA 8200v (appliance virtuelle) |
| Firmware | 12.5.0-02283 (confirmé) ; probablement toutes les versions 12.x |
| Service | Console de gestion — Jetty + Struts 2 (port 8443) |
| Point de terminaison | POST /activeUsers.action |
| Paramètres vulnérables | realmFilter, communityFilter (inter-paramètres) |
| Classe de cause racine | com.aventail.mgmt.sql.Sql.safeParam() |
| Base de données | MariaDB 10.11.14, utilisateur DbAdmin (TOUS LES PRIVILÈGES + FILE) |
| Fichier cible | /usr/local/app/mgmt-server/datastore/active/sysconf/avconfig.xml |
La console de gestion construit les requêtes SQL pour le tableau de bord des utilisateurs actifs à l'aide d'une méthode utilitaire safeParam() dans la classe com.aventail.mgmt.sql.Sql. Cette méthode échappe les guillemets simples (') et les guillemets doubles (") en les doublant, mais elle n'échappe pas les caractères antislash (\).
Dans MySQL/MariaDB, un antislash est le caractère d'échappement par défaut à l'intérieur des littéraux de chaîne. La séquence \' amène la base de données à interpréter le guillemet simple comme un caractère littéral plutôt que comme un terminateur de chaîne. Cela signifie qu'un antislash à la fin d'une valeur de paramètre échappera le guillemet fermant que l'application ajoute, ce qui étend le littéral de chaîne SQL dans la syntaxe adjacente.
Faille d'assainissement :```
Input: test
safeParam output: test\ (backslash NOT escaped)
In SQL: ... rt.name='test') AND (ct.name='...'
^^ backslash escapes the closing quote
Le `'` de fermeture après `test\` est consommé comme un caractère de guillemet littéral dans la chaîne, de sorte que le littéral de chaîne SQL s'étend à travers la limite `) AND (ct.name='` et dans la valeur du paramètre suivant, où du SQL contrôlé par l'attaquant peut être injecté.
### 3.2 Mécanique d'injection : technique inter-paramètres
Le point de terminaison `activeUsers.action` accepte plusieurs paramètres de filtre qui sont interpolés dans une seule clause SQL WHERE. Les paramètres concernés sont `realmFilter` et `communityFilter`, qui apparaissent dans une requête structurée approximativement comme suit :```sql
SELECT ... FROM ...
WHERE ...
AND (rt.name='<realmFilter>')
AND (ct.name='<communityFilter>')
...
Configuration des paramètres d'attaque :
| Paramètre | Valeur | Objectif |
|---|---|---|
realmFilter | test\ | La barre oblique inversée finale échappe le guillemet fermant, étendant le littéral de chaîne au-delà de la limite AND |
communityFilter | )) OR (SELECT IF(<condition>,SLEEP(N),0))-- x | Ferme les parenthèses ouvertes, injecte un SLEEP conditionnel, commente le reste |
SQL résultant après interpolation :```sql WHERE ... AND (rt.name='test') AND (ct.name=' )) OR (SELECT IF(,SLEEP(N),0))-- x')
Décomposition :
1. `rt.name='test\')` — le `\` échappe le `'`, donc la chaîne ne se ferme pas ici
2. `AND (ct.name='` — fait partie de la valeur de la chaîne (texte littéral)
3. La chaîne se ferme finalement au `'` suivant (au début de `communityFilter`)
4. `))` — ferme les deux parenthèses ouvertes de la structure de la clause WHERE
5. `OR (SELECT IF(...))` — injecte la condition d'injection SQL aveugle
6. `-- x` — commente le reste du SQL (`')` et les autres clauses)
### 3.3 Extraction aveugle basée sur le temps
Étant donné que la gestion des erreurs Struts 2 de l'application intercepte les exceptions SQL avec élégance (renvoyant toujours une réponse HTTP 200 avec le même contenu de page, quel que soit le succès ou l'échec de la requête), les méthodes d'extraction basées sur les erreurs et sur UNION ne sont pas viables. L'injection est exploitée à l'aide de la technique aveugle basée sur le temps :
- **Condition VRAIE :** `IF(<condition>, SLEEP(N), 0)` — réponse retardée par la durée de SLEEP multipliée par le nombre de lignes du jeu de résultats
- **Condition FAUSSE :** Pas de SLEEP — réponse renvoyée en ~200-500 ms
La fonction SLEEP s'exécute par ligne lors de l'évaluation de la clause WHERE. Avec une table de surveillance typique contenant 30 à 300+ lignes, même une petite valeur de SLEEP (par exemple, 0,3 s) produit un délai clairement distinguable (10-100 s pour VRAI contre <1 s pour FAUX).
Chaque caractère des données cibles est extrait via une recherche binaire sur la plage ASCII :```sql
ORD(SUBSTRING((<extraction_expr>), <position>, 1)) > <midpoint>
Cela nécessite un maximum de 7 requêtes par caractère (log2(128) = 7), soit environ 686 requêtes au total pour un hash SHA-512 de 98 caractères.
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 Étape 1 : Authentification
La console de gestion SMA prend en charge deux domaines d’authentification :