首页
社区
课程
招聘
[翻译]栈溢出、堆溢出与反射性XSS漏洞分析(SonicWall SMA100 CVE-2025-40596、CVE-2025-40597 和 CVE-2025-40598)
发表于: 2025-8-1 23:40 1532

[翻译]栈溢出、堆溢出与反射性XSS漏洞分析(SonicWall SMA100 CVE-2025-40596、CVE-2025-40597 和 CVE-2025-40598)

2025-8-1 23:40
1532

原文标题: Stack Overflows, Heap Overflows, and Existential Dread (SonicWall SMA100 CVE-2025-40596, CVE-2025-40597 and CVE-2025-40598)
原文链接: Stack Overflows, Heap Overflows, and Existential Dread (SonicWall SMA100 CVE-2025-40596, CVE-2025-40597 and CVE-2025-40598)

2025年,我们坚信行业内存在一项不言而喻的默契:每台网络设备都必须包含至少一个可轻易规避的HTTP头解析漏洞——最好是在认证前阶段。若涉及sscanf函数,则可额外加分。
若果真如此,那真是太棒了!SonicWall的SMA100系列已自豪地完成了配额——甚至可能符合额外奖励的条件。

我们最初的探索之旅始于分析 SonicWall N-day 漏洞(SonicBoom, From Stolen Tokens to Remote Shells - SonicWall SMA (CVE-2023-44221, CVE-2024-38475)),当时它正受到我们友好的 APT 团队的密切关注。然而,在漏洞百出的攻击头和反向代理的迷雾中,我们偶然发现了一些漏洞,它们仿佛是 C 语言编程早期的遗留物。

虽然我们理解(并认同)这些漏洞最终难以利用——甚至在某些情况下目前无法利用——但它们的存在本身,坦率地说,就令人失望。由畸形HTTP头部触发的认证前堆栈和堆溢出本不应再发生。然而……我们却遭遇了。

来吧,与我们一同感叹。我们将带您回顾我们是如何发现这些漏洞的,发现了什么,以及为什么网络安全工作让人感到如此有保障。

在这篇博客中,我们将详细介绍在SonicWall SMA100系列中发现的三个漏洞——所有漏洞均在固件版本10.2.1.15上得到确认:

CVE-2025-40596 - 基于栈的缓冲区溢出(认证前)
CVE-2025-40597 - 基于堆的缓冲区溢出(认证前)
CVE-2025-40598 - 反射型跨站脚本攻击(认证前,需用户交互)

SonicWall 的安全公告可在此处查看: Security Advisory

让我们深入探讨。

在审查负责处理 SonicWall SSLVPN 传入 HTTP 请求的 /usr/src/EasyAccess/bin/httpd 二进制文件时,我们发现了一个简单的基于堆栈的缓冲区溢出漏洞。值得注意的是,IDA无法反编译该漏洞函数。

httpd 二进制文件包含一系列条件检查,用于将传入请求映射到特定功能。如果请求 URI 以 /__api__/ 开头,则触发以下逻辑。

首先,二进制文件对传入 URI 与 /__api__/ 字符串进行 strncasecmp 比较:

如果请求的 URI 的前 9 个字节以 /__api__/ 开头,执行流程将跳转到 loc_444F0 块。让我们来仔细看看这个块。

loc_444F0 块的逻辑很简单——它调用著名的 sscanf 函数来解析用户输入。具体来说,它将用户提供的 URI 的一部分复制到存储在 rcx 寄存器中的内存地址中。该地址本身来自于 [rsp+898h+var_878] 的栈变量。

位于 [rsp+898h+var_878] 的堆栈变量大小为 0x800 字节,并在函数执行过程中被清零。

该函数的意图似乎很明确——它旨在解析以下格式的传入 URI:

sscanf 调用首先提取 2 个字节到 v1 中,然后将最后一个斜杠后面的所有字符复制到 0x800 字节的栈缓冲区中——当然,没有进行任何边界检查

...因为还能出什么问题呢?

重现此问题非常简单——只需使用以下一行代码即可触发:

如果远程连接断开,这强烈表明目标系统存在漏洞。然而,如果你发送一个较小的数据包——例如大约2000字节——服务器会返回400 Bad Request错误。

例如:

以下是在 gdb 中崩溃的具体表现:

由于SonicWall的/usr/src/EasyAccess/bin/httpd二进制文件启用了栈保护功能,使得此次溢出攻击的危害程度仅为中等。该溢出位置紧邻stack canary和返回地址,中间没有其他可被利用的变量。

然而,这仍然是一个发生在 2025 年 SSL-VPN 中认证前路径上的栈溢出漏洞。

一个已经令人沮丧,两个?唉……

在继续审查httpd二进制文件时,我们发现了一个名为mod_httprp.so的共享对象,该对象似乎处理了设备HTTP解析的大部分功能。其名称中的httprp可能代表“HTTP反向代理”——该库负责检查传入的HTTP请求,以实现各种SonicWall特定功能,包括内容过滤、远程桌面访问等。

该漏洞源于mod_httprp.so在解析Host:header时触发的越界堆写入操作。

这个漏洞很特别——不仅因为它涉及sprintf函数,还因为有人特意使用了“安全”版本,却依然突破了所有防护措施。

为了简单起见,我们将其分解开来——让我们来探究其根本原因。

首先,通过简单的 calloc(0x80) 调用分配一个堆块,返回一个已清零的内存区域。该块的指针存储在 v21 中,随后被传递给 __sprintf_chk 调用。

现在,你可能会想——__sprintf_chk 不是应该是个“安全”版本吗?这怎么可能存在漏洞?

确实会。但前提是你使用方式错误

虽然__sprintf_chk函数期望接收一个带边界检查的size参数,但SonicWall开发者却选择了传递-1(即0xFFFFFFFFFFFFFFFF)。

对于在家中尝试的读者——这不是进行边界检查的正确方式

SSL-VPN开发者们,你们离成功如此之近,却又如此之远……

这意味着该函数将继续从提供的Host:header的字节中复制到0x80大小的堆块中……直到遇到空字节。

让我们看看 v21 在复制前的内容:它指向我们刚刚通过 calloc 分配的 0x80 字节大小的堆块——正如预期的那样,完全是空的。紧接着它的是什么?额外的堆分配内存。

而这正是事情变得有趣的地方。

复制完成后,我们发现相邻堆块的元数据已被我们的控制数据覆盖。

这……不太理想。

重现此问题同样简单——只需执行以下一行命令即可触发:

关于利用此漏洞实现完全的认证前远程代码执行(RCE)——由于目标Web服务器上存在大量后台任务和脚本持续与之交互,我们在堆内存元数据操作过程中无法可靠地与服务器竞争。

更进一步的是,在审查可用CGI端点时,我们意外发现了一个经典的反射型XSS漏洞。

触发该漏洞极为简单——只需访问radiusChallengeLogin端点,并通过state参数注入XSS有效载荷。该值会直接反射到响应中,且未经过任何过滤。

值得注意的是,尽管SMA100 SSLVPN提供了WAF功能,但该功能在管理接口上似乎完全被禁用——这意味着即使是如下所示的基本有效载荷也足以触发该漏洞:

结果?就像 2005 年(或 2025 年的 Fortinet)发出的老式alert(1),它想要找回自己的漏洞。

一段令人怀念的往事——也是一个提醒,有些事情永远不会改变。

https://x.x.x.x/__api__/v1/login
https://x.x.x.x/__api__/v1/login
import requests; requests.get("1dcK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6^5i4K6u0W2P5q4)9J5k6i4S2Q4x3X3g2^5i4K6u0r3i4K6g2X3i4K6g2X3j5i4m8A6i4K6g2X3i4K6g2X3i4K6u0r3N6U0q4Q4x3V1j5`."+'A'*3000,verify=False)
import requests; requests.get("352K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6^5i4K6u0W2P5q4)9J5k6i4S2Q4x3X3g2^5i4K6u0r3i4K6g2X3i4K6g2X3j5i4m8A6i4K6g2X3i4K6g2X3i4K6u0r3N6U0q4Q4x3V1j5`."+'A'*3000,verify=False)
import requests; requests.get("14eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6^5i4K6u0W2P5q4)9J5k6i4S2Q4x3X3g2^5i4K6u0r3i4K6g2X3i4K6g2X3j5i4m8A6i4K6g2X3i4K6g2X3i4K6u0r3N6U0q4Q4x3V1j5`." + 'A'*2000, verify=False)
import requests; requests.get("6f0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6^5i4K6u0W2P5q4)9J5k6i4S2Q4x3X3g2^5i4K6u0r3i4K6g2X3i4K6g2X3j5i4m8A6i4K6g2X3i4K6g2X3i4K6u0r3N6U0q4Q4x3V1j5`." + 'A'*2000, verify=False)
v21 = calloc(0x80, 1);
 
.text:0000000000031DDE                 lea     rax, asc_43502+1 ; "/"
.text:0000000000031DE5                 lea     r8, aHttps+1    ; "https://"
.text:0000000000031DEC                 lea     rcx, aShostSSSSS+9 ; "%s%s%s%s"
.text:0000000000031DF3                 mov     r9, r15
.text:0000000000031DF6                 mov     esi, 1
.text:0000000000031DFB                 mov     [rsp+1220h+var_1218], rax
.text:0000000000031E00                 mov     rdx, [rbp+var_1108]
.text:0000000000031E07                 mov     rdi, r12
.text:0000000000031E0A                 xor     eax, eax
.text:0000000000031E0C                 mov     [rsp+1220h+var_1220], rdx
.text:0000000000031E10                 mov     rdx, 0FFFFFFFFFFFFFFFFh
.text:0000000000031E17                 call    ___sprintf_chk
v21 = calloc(0x80, 1);
 
.text:0000000000031DDE                 lea     rax, asc_43502+1 ; "/"

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

收藏
免费 9
支持
分享
最新回复 (4)
雪    币: 204
活跃值: (235)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2

为你点 赞!
2025-11-11 11:02
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
点赞
2025-11-22 22:58
0
雪    币: 200
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
点赞
2025-11-22 23:31
0
雪    币: 0
活跃值: (75)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
支持一下
2025-11-29 14:59
0
游客
登录 | 注册 方可回帖
返回