Skip to content
KitploitKITPLOIT
工具漏洞利用博客
Log in
提交
工具漏洞利用博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

订阅源联系隐私© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-88773 — 对 NetScaler nsppe HTTP/1.1 chunk-size 整数回绕请求走私漏洞的技术分析,包含反汇编、线级 PoC 流程以及固件补丁差异。 | Kitploit
工具/GitHubGitHub/scyrix-llc/cve-2026-88773
漏洞分析漏洞利用逆向工程Web应用程序漏洞利用Web安全二进制分析论文与研究固件分析
GitHubscyrix-llc/cve-2026-88773

CVE-2026-88773

对 NetScaler nsppe HTTP/1.1 chunk-size 整数回绕请求走私漏洞的技术分析,包含反汇编、线级 PoC 流程以及固件补丁差异。

查看仓库
111个月前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
网站
分享

CVE-2026-88773:NetScaler nsppe(HTTP 走私)

HTTP/1.1 解析器中的 32 位块大小累加器回绕

简要说明

nsppe 的 HTTP/1.1 分块正文解析器将块大小字段读入一个 32 位寄存器,并且从不检查溢出。当出现九个或更多十六进制数字时,该值会静默回绕:100000005(2^32 + 5)被当作块大小 5 来消费。

这本来只是个有趣的解析器 bug,直到你想起 NetScaler 对正文做了什么:它把客户端的分块帧原样转发给后端,但它用自己回绕后的值来决定请求在哪里结束。于是代理认为请求 #1 在五个正文字节后就完成了,而一个正确读取相同字节的后端会计算出 4,294,967,301,并等待一个永远不会到达的 4 GB 正文。两台机器,同一个字节流,对请求在哪里结束却有两种不同的看法。

在 NetScaler 版本的“结束”之后的所有内容,都会被重新归类为同一客户端连接上的新流水线请求,然后在共享的代理到后端连接上被独立转发。

最终结果取决于后端自己的解析器:

  • 后端也截断到 32 位: 被走私的字节会作为独立请求执行。经典的 prefix-hijack。
  • 后端正确解析: 硬失步,连接卡在一个永远不会到达的 4 GB 正文上。连接池耗尽 DoS。

一个未认证请求。默认配置。除了能访问 HTTP vserver 之外没有任何前提条件。


根本原因

块大小十六进制解析器

解析器的工作很简单:把像 1a3f\r\n 这样的块大小行转换成一个数字。它接收 rdi 中的缓冲区及其长度 esi,将十六进制值累加到 *rdx 处的 32 位槽中(输入输出,因此跨两个数据包拆分的块大小可以干净地恢复),跳过空白,并要求末尾有 \r\n。它返回已消费的字节数、0 表示“需要更多数据”,或 -1 表示格式错误。

整个循环小到可以用肉眼看出这个 bug:

20af5e0: movzx  eax, BYTE PTR [rbx]
20af5e3: test   BYTE PTR [rax+rax*1+0x2746c80], 0x10   ; ctype: hex digit?
20af5eb: je     20af60b
20af5ed: mov    ecx, r11d
20af5f0: shl    ecx, 0x4                               ; value <<= 4
20af5f3: movzx  r11d, BYTE PTR [rax+0x2746b80]         ; hexval(digit)
20af5fb: add    r11d, ecx                              ; value = value*16 + d
20af5fe: inc    rbx
20af601: dec    r8d
20af604: jne    20af5e0                                ; next digit

r11d 是累加器,宽度为 32 位。每个数字都执行 value <<= 4; value += digit。没有数字计数器,没有大小上限,没有溢出检查,循环中任何地方都没有 jo。第九位数字不会报错;它把数字的高位移出寄存器末尾,而没有人注意到。0x100000005 & 0xffffffff = 5,解析器对此完全满意。

唯一的一项合理性检查拒绝了错误的那一半

下游恰好只有一项合理性检查,而它错得几乎富有诗意。去分块驱动程序(sub_20af6b0,调用点 0x20af719 / 0x20af9fb,大小存储在 [r12+0x344])对累加值应用符号测试。稍等片刻:只有落在负半区 [0x80000000, 0xffffffff] 的环绕才会被捕获。如果环绕后的大小其低 32 位低于 0x80000000,它就会作为完全正常的分块大小顺利通过。0x100000005 环绕为 5 就是典型情况:发生了环绕,未被察觉,且具有破坏性。


为什么它能走私

数据包之所以变成走私,是因为 NetScaler 处理请求体的一个设计决策:它将客户端的 chunked 分帧逐字节原样转发给后端,同时使用自己(已环绕的)对该分帧的理解来决定客户端请求在哪里结束。

因此 NetScaler 在五个请求体字节后结束请求 #1,并将剩余的 37 个字节作为第二个流水线请求排队。后端正确地做算术,将 100000005 读作 4,294,967,301,并继续等待请求 #1 的请求体。从那一刻起,两个盒子读取同一个流,却生活在不同的世界里。

你最终进入哪个世界取决于后端。

流程 A:正确的 64 位后端。失同步楔子。

Attacker                           NetScaler (<=73.30)                            Backend (RFC 64-bit)
   |                                        |                                               |
   |  [1] one TCP segment, 122 bytes:       |                                               |
   |    POST /wrap HTTP/1.1                 |                                               |
   |    Host: poc                           |                                               |
   |    Transfer-Encoding: chunked          |                                               |
   |    100000005\r\nAAAAA\r\n0\r\n\r\n     |                                               |
   |    GET /SMUGGLED HTTP/1.1              |                                               |
   |    Host: poc\r\n\r\n                   |                                               |
   |--[1]---------------------------------->|                                               |
   |                                        | [2] parses "100000005" into a u32             |
   |                                        |     wraps to 5; consumes AAAAA;               |
   |                                        |     sees terminating 0-chunk                  |
   |                                        |     ==> request #1 COMPLETE                   |
   |                                        |     trailing 37 bytes held as a               |
   |                                        |     pending pipelined request #2              |
   |                                        |                                               |
   |                                        |--[3] 85 bytes, framing VERBATIM-------------->|
   |                                        |   POST /wrap HTTP/1.1                         |
   |                                        |   Transfer-Encoding: chunked                  |
   |                                        |   100000005\r\nAAAAA\r\n0\r\n\r\n             |
   |                                        |                                               |
   |                                        |                                               | [4] parses 0x100000005 (64-bit)
   |                                        |                                               |     = 4,294,967,301 bytes
   |                                        |                                               |     waiting for a body that never co
   |                                        |                                               |     [WEDGED: no response, ever]
   |                                        |                                               |
   |                                        | GET /SMUGGLED waits in NetScaler's            |
   |                                        | pipeline queue forever: response #1           |
   |                                        | never arrives                                 |
   |                                        |                                               |

流程 B:像 NetScaler 一样截断到 32 位的后端。完成走私。

下载工具