CVE-2025-32756 Fortinet RCE 野外利用

CVE-2025-32756:低腰牛仔裤回来了,缓冲区溢出也回来了

2025年5月13日,FortiGuard Labs 发布了一份公告,详细说明了 CVE-2025-32756,该漏洞影响了多种 Fortinet 产品:

  • FortiCamera
  • FortiMail
  • FortiNDR
  • FortiRecorder
  • FortiVoice

FortiGuard Labs 在其公告中指出,Fortinet 已经观察到该问题在野外被利用。第二天,即5月14日,该漏洞被添加到 CISA KEV 目录中。

该漏洞在公告中被描述为管理 API 中的一个基于堆栈的缓冲区溢出,可能导致未经身份验证的远程代码执行。鉴于它正在野外被利用,我们决定仔细研究一下。如果您不想阅读这篇分析报告,而是想直接进行测试,那么 NodeZero 中已经提供了相关覆盖。

寻找线索

对于我们的逆向工作,我们选择了查看 FortiMail 的已修补和未修补版本。公告中列出的失陷指标(IOC)为我们从哪里开始提供了一些线索。

https://fortiguard.fortinet.com/psirt/FG-IR-25-254

这里显示的日志输出告诉我们几个重要的事情:

  • 我们正在寻找一种执行 admin.fe cgi 二进制文件的方法
  • Web 服务器正在使用 mod_fcgid,这使得我们在尝试利用目标时生活变得更轻松一些,因为失败的尝试不太可能导致整个 httpd 进程崩溃并将我们锁定在应用程序之外。

从 Web 服务器配置文件 (httpd.conf) 中,我们找到了我们的入口点:

ScriptAlias /module/ "/migadmin/www/fcgi/"

一个快速的 curl 请求验证了我们可以访问 admin.fe 端点:

# curl -k -L -v https://REDACTED/module/admin.fe

< HTTP/1.1 200 OK
< Date: Tue, 20 May 2025 23:17:44 GMT
< Cache-Control: no-cache
< Strict-Transport-Security: max-age=31536000; includeSubDomains
< Set-Cookie: APSCOOKIE_ffbe3e4d0e3350075e9c91f574e799cc=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: ParamStr=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: mTime=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: logLevel=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: logType=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: logStartline=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: logDomain=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: totalLineNumber=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Set-Cookie: SearchResultFile=; Expires=Fri, 01-Jan-1971 01:00:00 GMT;; Path=/; Version=1; Secure; HttpOnly
< Vary: Accept-Encoding
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< Content-Security-Policy: script-src 'self'; object-src 'none'; frame-ancestors 'self' https://*.fortimailcloud.com/ https://fortimail.forticloud.com/
< Transfer-Encoding: chunked
< Content-Type: text/plain
<

{"errorType": 7,"errorMsg": "Failed: Access denied","reqAction": 0,"totalRemoteCount": 0,"collection": "[]"}

不幸的是,当尝试在已修补和未修补版本之间对 admin.fe 进行 diff 时……我们发现二进制文件是相同的。这意味着漏洞可能存在于一个共享库中,所以是时候深入挖掘了。

动手实践

Ghidra 导入视图

哦。恶心。一个 boost 库……这很可能意味着是 C++……为了不在接下来的几个小时里碰壁,我们通过 Ghidra-MCP 桥和 Github Copilot 向 ChatGPT 寻求了一些帮助。

在仔细查看了向我们推荐的函数后,我们发现了一个熟悉的字符串:APSCOOKIE。如果您回顾一下我们之前用 curl 进行的测试,您会注意到返回的 cookie 中有一个正是这个值。

如果您在管理 Web 界面上玩一会儿,您会开始看到偶尔会有包含此 APSCOOKIE 值的对 admin.fe 端点的请求,该值似乎用于会话管理。

解码此 cookie 值后,我们得到:

Era=0&Payload=qCStu1vT3v+Y++5pCCs9M/CxxddCRrC8SHg+9cfRCA42GU7Cf+8p3iBFSl/4vHteSGePZgk7KGMb8kzRR5c2boDUfiiD65jkByiD3DuRCj1NJR7ESpZQIZlOffSxykRbCTp5l3InoU+q6psG+ve+IRDk9za5K0No9T5RNxCwZxM=&AuthHash=kz4cHPsgudYxy4PPp123FUto=&

APSCOOKIE 具有以下 URL 编码的字段:

  • Era
  • Payload
  • AuthHash

这些听起来是开始进行 grep 的好值。

$ grep -rl "Era" ./762 | xargs grep -rl "Payload" | xargs grep -rl "AuthHash"
rootfs/lib/libhttputil.so

$ diff 762/rootfs/lib/libhttputil.so 763/rootfs/lib/libhttputil.so
Binary files 762/rootfs/lib/libhttputil.so and 763/rootfs/lib/libhttputil.so differ

鉴于只有一个文件包含这些值,并且它在产品的已修补和易受攻击版本之间有所不同,我们很可能已经找到了罪魁祸首。

在 Ghidra 中加载两个版本后,我们可以看到这些字符串都在函数 cookieval_unwrap() 中被引用。我们决定让大脑休息一下,看看我们的小 AI 助手能帮我们走多远。

对于第一次响应来说还不错。我们继续。

不幸的是,在此之后响应开始变得越来越不可靠,所以让我们以 ChatGPT 的观察为起点,专注于一些传统的手动分析。

粗略地浏览函数,cookieval_unwrap() 似乎专门用于执行每个 ASPCOOKIE 字段的 base64 解码并将其写回输入缓冲区。由于 Era 预计是一个单位数,让我们将精力集中在 Payload 和 AuthHash 上。我们将浏览该函数的已修补和未修补版本的反编译代码,以追踪对这些值的引用。

----------
未修补:
----------
size_t input_size;
size_t __size;
uchar *AuthHash;
uchar *Payload;
long output_buffer [2];
out_00 = (uchar *)malloc(__size);

iVar2 = __isoc99_sscanf(param_1,"Era=%1d&Payload=%m[^&]&AuthHash=%m[^&]&",&Era,&Payload, &AuthHash);

input_size = strlen((char *)AuthHash);
__size = strlen((char *)Payload);


iVar3 = EVP_DecodeUpdate(ctx,(uchar *)output_buffer,&output_size,AuthHash,(int)input_size);

iVar2 = EVP_DecodeUpdate(ctx,out_00,&local_94,Payload,iVar2);


----------
已修补:
----------
size_t input_size;
size_t __size;
uchar *AuthHash;
uchar *Payload;
long output_buffer [2];
out_00 = (uchar *)malloc(__size);

iVar2 = __isoc99_sscanf(param_1,"Era=%1d&Payload=%m[^&]&AuthHash=%m[^&]&",&Era,&Payload, &AuthHash);

input_size = strlen((char *)AuthHash);
__size = strlen((char *)Payload);

input_size = strlen((char *)AuthHash);
if (input_size < 0x1e) {

iVar3 = EVP_DecodeUpdate(ctx,(uchar *)output_buffer,&output_size,AuthHash,(int)input_size);

iVar2 = EVP_DecodeUpdate(ctx,out_00,&local_94,Payload,iVar2);

已修补和未修补函数之间的关键区别似乎是对用户提供的 AuthHash 值大小的大小检查。在原始版本中,我们可以看到 AuthHash 被解码并写入输出缓冲区,而该缓冲区只够容纳 16 个字节。在已修补版本中,我们可以看到添加的大小检查限制了用户可以在此值中发送的数据量。基本上,我们现在知道 ChatGPT 指出的 memcpy() 并不完全正确,真正的溢出是由于调用 EVP_DecodeUpdate(),它写入了为解码的 AuthHash 值分配的边界之外。

现在我们知道溢出发生在哪里,但它给了我们多少控制权呢?让我们从输出缓冲区开始看一下堆栈分配:

RSP+0x50 : local_78 (16 字节)        <- 溢出开始
RSP+0x60 : local_68 (4 字节)         <- 被覆盖
RSP+0x70 : local_58 (16 字节)        <- 被覆盖
RSP+0x80 : local_48 (16 字节)        <- 被覆盖
RSP+0x90 : 已保存的 RBX                  <- 被覆盖 ---v
RSP+0x98 : 已保存的 RBP                  <- 被覆盖
RSP+0xA0 : 已保存的 R12                  <- 被覆盖   这些在函数序言中保存
RSP+0xA8 : 已保存的 R13                  <- 被覆盖
RSP+0xB0 : 已保存的 R14                  <- 被覆盖
RSP+0xB8 : 已保存的 R15                  <- 被覆盖 ---^
RSP+0xC0 : 返回地址 (RIP)       <- 被覆盖

随着执行的继续,这些堆栈值保持不变,直到它们再次被 memcpy() 调用使用。memcpy() 的调用恰好使用了我们已经控制的值,这可能对制作一个有效的漏洞利用很有用,但现在没有必要深入研究,因为我们已经控制了将在函数尾声中写入 RIP 的值。

让我们开始发送一些垃圾数据,看看会发生什么!由于 AuthHashl 需要是有效的 base64,让我们发送一堆正确编码的 NULL 字符。

AuthHash%3DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%3D%3D

看起来很有希望。经过一些循环有效载荷的反复试验后,我们能够确定以下内容:

💥 鉴于像这样的简单内存损坏问题在现代已经变得多么罕见和过时,重温一些上世纪 90 年代的老式黑客技术是一种不错的改变。

<think>好的,我需要处理用户关于CVE-2025-29775和CVE-2025-29774漏洞的查询。首先,我应该检查提供的四个引用,看看是否有提到这两个CVE编号。根据用户提供的引用,引用[1]到[4]分别提到了不同的CVE编号,比如CVE-2025-0411、CVE-2021-41617、CVE-2020-15778、CVE-2019-16905、CVE-2002-20001、CVE-2025-24813和CVE-2025-1094,但没有直接提到CVE-2025-29775和CVE-2025-29774。这说明用户提到的这两个漏洞可能不在用户提供的参考信息中。 接下来,我需要考虑如何处理这种情况。首先,我应该如实告知用户,根据现有的引用资料,没有找到这两个CVE的具体信息。这可能是因为提供的引用中没有涵盖这些漏洞,或者这些漏洞是较新的,尚未被广泛记录或收录到公开的漏洞数据库中。 然后,我应该提供一些通用的建议,帮助用户自行查找这些漏洞的详细信息。例如,建议他们访问权威的漏洞数据库如NVD(National Vulnerability Database)、CVE官方网站,或者相关的安全公告平台。此外,提醒他们检查受影响软件的官方安全公告,以及及时应用供应商提供的补丁和更新。 同时,我需要确保回答符合用户的要求,即结构清晰,分步骤解决问题,并尽量真实可靠。需要避免猜测或提供不准确的信息,特别是在涉及安全漏洞的情况下,错误的信息可能导致用户采取不恰当的措施,增加风险。 最后,根据用户提供的示例,需要生成相关问题。这些问题应该围绕如何进一步查找漏洞信息、验证系统是否受影响以及常规的漏洞管理措施展开。 总结来说,回答的结构应包括: 1. 指出现有引用中未找到相关信息。 2. 提供通用的漏洞查询建议。 3. 给出通用的漏洞处理建议。 4. 生成相关问题。 需要确保语言简洁明了,使用中文,并正确应用LaTeX格式(如果有数学内容的话,但这里可能不需要)。同时,注意引用标识的正确使用,但根据现有引用,可能不需要添加新的引用,因为没有对应的信息。</think>根据当前提供的参考信息,未找到关于 **CVE-2025-29775** 和 **CVE-2025-29774** 的具体漏洞详情。以下是针对此类漏洞的通用分析框架和建议: --- ### 1. **漏洞查询建议** - **权威数据库检索** 访问美国国家标准与技术研究院(NIST)的[国家漏洞数据库(NVD)](https://nvd.nist.gov/)或[CVE官方网站](https://cve.mitre.org/),输入CVE编号查询漏洞详情。 - **厂商安全公告** 若漏洞与特定软件相关(如Apache、Microsoft等),需直接查看对应厂商的安全公告页面。 --- ### 2. **通用漏洞处理流程** 1. **影响范围分析** 漏洞可能涉及特定软件版本、协议或依赖库。例如: - 若漏洞与网络协议相关,需检查是否使用受影响的协议(如SSH、HTTP/2等)。 - 若涉及开源组件,需通过依赖管理工具(如Maven、npm)排查版本号。 2. **修复方案** - **补丁升级**:优先应用厂商发布的官方补丁。 - **缓解措施**:若无法立即升级,可临时禁用相关功能或配置防火墙规则限制访问。 - **输入验证与过滤**:对用户输入实施严格的校验(如正则表达式匹配)以防止注入攻击[^4]。 --- ### 3. **参考案例分析** 根据已有引用中类似漏洞的特征(如CVE-2025-24813的远程命令执行漏洞[^3]),推测 **CVE-2025-29775/29774** 可能涉及以下风险: - **远程代码执行(RCE)**:攻击者通过构造恶意请求在目标系统执行任意命令。 - **权限提升或数据泄露**:漏洞可能绕过身份验证或加密机制。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值