漏洞

NetScaler:握手分片怎样写出了内存边界

员工还没登录 VPN,网关就要先处理建立连接的请求。NetScaler 的 CVE-2026-88772 出在这一步:分片拼接时,实际复制的数据可能超过缓冲区容量。漏洞已遭利用,启用 DTLS 的旧设备需要尽快修补,并检查升级前的入侵迹象。

浅暖纸手绘:网关送来的纸片不断进入固定大小的分拣槽,最终越过右侧边界。
文章导航

公司把 VPN 放在互联网入口,是为了让员工从外面安全地连回来。可是在核对员工身份之前,网关已经做了不少工作:接收数据包、协商加密方式、把分开到达的握手消息拼起来。发起这些请求的人还没有登录。这个阶段一旦出错,后面的密码和多因素认证就来不及保护设备本身。

NetScaler 的 CVE-2026-88772 就发生在握手消息的拼接过程中。9 月 27 日,Citrix 确认漏洞已遭利用,CISA 同日将其加入 KEV 已知遭利用漏洞目录。29 日公开的补丁分析进一步解释了问题:程序判断一条消息已经收齐之后,还要把保存的内容复制到一块连续内存;这次复制缺少容量约束。前一项检查通过,后一项操作仍可能写出边界。

我们的判断是,互联网可达、仍运行旧固件的 DTLS 服务应立即进入应急修补流程。强密码、登录限速和 MFA 都守在更后面。前一天我们分析的 88771 日志命令注入走的是后台脚本路径;今天这项漏洞直接涉及网关接收网络数据的内存处理,两项需要分别检查。

1 为什么没登录也能走到这里

DTLS 可以理解为运行在 UDP 上的加密通信协议。UDP 数据包可能丢失、乱序,一条较长的握手消息也可能被拆成多片。接收端因此要记住每片属于哪条消息、应该放在哪里,等缺少的部分到齐后继续协商。RFC 6347 的握手格式分别设置了完整消息长度 length、消息编号 message_seq、分片位置 fragment_offset 和本片长度 fragment_length。这些字段回答的是不同问题。

例如,一条 8 字节的消息分成两片,第一片覆盖位置 0 到 3,第二片覆盖 4 到 7,接收端便能判断内容是否收齐。但在实现里,收到的数据通常还带着记录头、内部缓冲结构或暂存内容。“这条消息有多长”和“内存里已经存了多少字节”需要分别计算。把前一个数当成后一个数的保证,会把风险留到下一次复制时才暴露。

DTLS 还有一层 cookie 往返:服务器发回一个值,请客户端带着它再来。协议对这一步的用途说得很清楚,它帮助确认请求方能接收到该地址上的响应,减少伪造源地址造成的资源消耗。一个能正常收发网络包的人也能完成往返;员工账号验证仍在后面。排查时应沿着数据包到达的路径找入口。

Citrix 的 正式公告给出的前提是启用 DTLS,VPN 虚拟服务器默认开启。配置里没出现大写的 DTLS,也可能满足这个条件:一条普通的 SSL VPN 虚拟服务器配置,如果没有显式关闭 DTLS,就仍使用默认值。还有独立的 DTLS 类型虚拟服务器和负载均衡服务。因此,简单搜索一个关键词容易漏掉默认配置,应该逐个核对虚拟服务器的实际状态和网络可达范围。

2 消息收齐以后,复制量却失去了约束

watchTowr 比较了 14.1-73.30 与 14.1-73.37:Packet Engine 的 nsppe 会把链式 NetScaler Buffer(NSB)中的内容汇入一块 0x8c00 字节缓冲区;分片声明的长度与 NSB 保留的内容长度可以分离,旧复制循环没有逐项检查剩余空间。补丁在每次复制前加入容量判断。厂商未公开这段源码的函数名或行号,本文依据研究者的公开差异解释;SOSEC 未取得固件,也未独立复现设备上的代码执行。

这个差别怎样形成?公开研究给出的例子里,完整消息声明只有 120 字节,每次分片只给重组进度增加 1 字节;相应的 NSB 节点却保留了远多于 1 字节的记录内容。等 120 个位置被填满,程序进入合并阶段,沿链复制的是各节点保留的内容。累计搬运量于是可以远超消息声明的 120 字节。这里需要同时追踪报文对“本片有效内容”的声明,以及内部节点实际保存、随后交给复制操作的长度。

0x8c00 换成十进制是 35,840。这个数字本身并不小,问题在于谁来保证放进去的总量不超过它。如果收集分片的阶段依据报文里声明的长度判断进度,而复制阶段依据内部节点实际保存的长度搬运数据,两段代码就可能对同一批输入得出不同的大小。前一段已经宣布“收齐了”,后一段仍会沿着链继续搬运。

理解这里的错误,最好盯住两项彼此独立的检查。第一项是覆盖范围:需要的消息字节是否已经齐全。第二项是空间预算:接下来将写入的实际字节数是否还装得下。一个完全合法的分片也需要第二项检查;对不一致输入,它尤其重要。协议还要求处理因重传产生的重叠分片,直接拒绝所有重叠也会伤到正常通信。

上排按分片位置判断消息是否完整;下排按实际字节数判断复制会不会超出固定容量,每次复制前都要检查剩余空间。
两项检查面对同一批数据,回答不同的问题。图中纸片和方框只表示完整性与容量关系,不表示真实报文数量、设备内存布局或按比例大小。

越界写入之后会发生什么,取决于旁边是什么内存、写进去的内容能否控制,以及后续代码怎样使用被破坏的状态。崩溃是其中一种结果;厂商确认的影响还包括远程代码执行。对运营者,这意味着不能把一次异常重启只归为可用性故障,也不能从一次重启直接推定已经执行了攻击者代码。需要保留现场,再把异常时间与连接、进程及文件变化关联起来。

3 修补应守住每一次写入

下面用一个独立的小模型说明容量检查应放在哪里。它只处理整数,没有网络请求,也不模拟 NetScaler 报文。假定目标容量为 64 字节,已经保存的头部占 8 字节,余下空间必须容纳每个待复制块。所有长度都是已验证的非负整数:

def fits(capacity, header_size, chunks):
    if header_size > capacity:
        return False
    remaining = capacity - header_size
    for size in chunks:
        if size > remaining:
            return False
        remaining -= size
    return True

assert fits(64, 8, [20, 20, 16])
assert not fits(64, 8, [20, 20, 17])
assert not fits(64, 65, [])

第一组刚好用满:8 + 20 + 20 + 16 = 64。第二组只多一个字节,就应在第三次复制开始前拒绝。第三组连头部都装不下,应在处理内容之前拒绝。SOSEC 在本地运行了这三项断言,结果均通过;这验证的是模型里的预算关系,设备补丁是否正确还需要厂商实现和设备测试。

这个写法还有一个容易忽略的好处:先比较当前块与剩余空间,再做减法。用固定宽度整数编写底层代码时,如果先累加多个外部长度,再拿总和比较容量,总和本身可能已经回绕。实现者还要保证长度没有负值、指针范围有效、失败路径能释放暂存状态,以及检查使用的长度与最终复制使用的长度完全相同。只要两处又各取一个数字,同类错误就可能留下来。

回归测试也应围绕这些关系展开:正常单片与多片消息能够完成;恰好装满仍能通过;多一个字节在写入前被拒绝;重复、乱序和重叠分片按协议处理;中断或拒绝后可以建立下一条正常连接。这样的测试能解释补丁保护了什么。用一个会让旧设备崩溃的样例去碰生产网关,既会影响业务,也不能覆盖这些不同的失败路径。

4 管理员现在该改哪一处

先找出自行管理的 NetScaler 实例,包括备用节点和 Secure Private Access Hybrid 中的实例;Citrix 管理的云服务由厂商更新。对旧版本且 DTLS 可达的服务,尽快安排修补。暂时关闭相关 DTLS 服务或在受控网络边界阻断其 UDP 入口,可以收窄这项漏洞的暴露;远程访问的性能和可用性可能随之改变,是否回退到其他传输必须按实际客户端验证。同一公告中的 88771 仍需升级处理。

截至 9 月 30 日,官方下载页普通分支列出的修复目标为 14.1-73.37 和 13.1-64.24。各分支按自己的发布线选择,不能把普通包替换到 FIPS 或 NDcPP 环境:

各分支的首次修复版本与本次部署选择
分支首次修复本次选择
ADC / Gateway 14.114.1-73.3714.1-73.37
ADC / Gateway 13.113.1-64.2313.1-64.24
ADC 14.1 FIPS14.1-73.37 FIPS同分支 14.1-73.37 FIPS
ADC 13.1 FIPS / NDcPP13.1-37.279对应 FIPS / NDcPP 的 13.1-37.279

评分和版本数据库也值得多看一眼。本轮读取时,NVD 已完成分析,NIST 给出 CVSS 3.1 的 8.1 分,NetScaler CNA给出 CVSS 4.0 的 9.5 分;两套评分不能当成同一把尺子的升降。NVD 的 14.1 FIPS 机器可读范围还把 14.1-73.37 包含在受影响端点中,与厂商公告和 CNA 的修复边界不一致。本文按厂商包表安排修补,保留这个差异供扫描结果复核,状态截止为 2026 年 9 月 30 日 04:07 UTC。

13.1 分支多出的一个小版本有实际意义。Citrix 的补充说明记录了 13.1-64.23 的循环重启问题:配置过变量的部署应改用 13.1-64.24。只读命令 show ns variable 可以检查这一条件。升级还会要求签名的 SAML assertion,应提前确认身份提供方配置,避免安全更新完成后员工无法登录。15.1 Technology Preview 当时仍受影响,厂商也未许可用于生产。

验收应从自己的正常业务开始:逐节点核对实际运行版本、主备状态、预期的 DTLS 开关,完成一次合法登录及应用访问,再检查进程稳定性和日志。保留需要的临时限制,直到这些检查结束。如果升级失败,继续隔离未修节点;普通 13.1 环境本次回退也优先使用 13.1-64.24,避免把已知循环重启风险带回来。其他分支不得退回各自首次修复版本之前。确有业务原因只能启动旧版本时,应保持隔离,由应急负责人决定后续恢复。

5 补上入口之后,还要查之前发生过什么

已知利用让这次升级多了一项责任:检查旧设备在暴露期间是否被进入。Citrix 的疑似入侵处置指南要求保全时间信息、日志和必要的实例或磁盘证据,再隔离、调查、重建。Packet Engine core 的采集会引发 warm restart 并断开 SSH,安排前要清楚它对现场和业务的影响。外部 syslog 中保留下来的记录也应一起保存。

如果发现入侵迹象,恢复工作需要覆盖设备接触过的身份和系统:调查关联认证服务,撤销可能泄露的凭据、证书和私钥,从可信介质重建,再恢复入侵前的可靠配置并轮换秘密。Citrix 提供的 IOC 检查可以辅助判断,覆盖范围随检测逻辑更新而变化;一次无命中仍留下未覆盖行为的调查空间。记录检测版本与时间,才能知道这次检查实际回答了多少问题。

这项漏洞留下的教训很具体:接收端确认消息完整,只完成了协议处理中的一件事。把消息从一种存储形式搬到另一种形式时,还得按真正要写入的字节重新核算容量。对正在值守的管理员,今天更重要的也是这两个具体结果:网关已经运行修复版本,更新前的暴露已经有人负责调查。正常登录重新跑通以后,这次应急才有条件逐步收尾。

研究依据

研究依据核对厂商公告与版本、CNA、NVD及变更、KEV和DTLS协议。设备机制取自公开固件分析;未取得固件、未复现设备漏洞。仅验证离线容量模型。资料截止2026-09-30 04:07 UTC。

来源Citrix、CISA、NVD、RFC 6347 与 watchTowr

证据置信度 高

6证据与来源

6.1来源与材料

  1. Citrix:受影响条件与修复版本公告 CTX697096https://support.citrix.com/external/article/CTX697096
  2. watchTowr:9 月 29 日 DTLS 内存溢出与固件补丁分析https://labs.watchtowr.com/here-we-go-again-citrix-netscaler-dtls-preauth-memory-overflow-cve-2026-88772/
  3. RFC 6347:DTLS 握手、cookie 和分片处理https://www.rfc-editor.org/rfc/rfc6347.html#section-4.2
  4. Citrix:当前 NetScaler 各分支下载列表https://www.citrix.com/downloads/citrix-adc/
  5. Citrix:配置、IOC、13.1 升级及 SAML 补充说明https://community.citrix.com/techzone-blogs/110_security-updates/netscaler-adc-and-netscaler-gateway-security-bulletin-for-cve-2026-88771-through-cve-2026-88778/
  6. Citrix:疑似入侵设备的取证、隔离与恢复https://support.citrix.com/external/article/CTX694799/steps-to-take-if-netscaler-adc-is-suspec.html
  7. CISA:KEV 实时目录https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json
  8. NetScaler CNA:CVE-2026-88772 原始记录https://cveawg.mitre.org/api/cve/CVE-2026-88772
  9. NVD:独立评分、产品匹配与变更历史https://nvd.nist.gov/vuln/detail/CVE-2026-88772