代码审计视角下的CVE-2026-40369:12字节内核写与沙箱逃逸的底层触发点剖析"

admin 2026-10-17 04:03:02 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

代码审计视角下的 CVE-2026-40369:12 字节内核写与沙箱逃逸的底层触发点剖析

Ots安全

2026年8月21日 18:18
广东

在小说阅读器读本章

去阅读

威胁简报

恶意软件

漏洞攻击

在之前的文章里,我们聊了 CVE-2026-40369 这个漏洞的宏观影响——一个从浏览器的低权限沙箱一路通往 SYSTEM 权限的“满分跳板”。但对于我们这些技术人来说,光知道“能提权”是远远不够的。这 12 字节的内核写原语在汇编层到底长什么样?为什么 ProbeForWrite 偏偏在这个函数里形同虚设?

今天咱们就卷起袖子,直接上 Hex-Rays 反编译出来的内核源码,从代码审计的视角,把这个漏洞的触发点和调用链彻底盘个底朝天。


一、 调用链跟踪:从 NtQuerySystemInformation 到底层工作函数

当我们在用户态发起系统调用时,整个执行流会从 nt!NtQuerySystemInformation 一路下沉。通过对 Windows 11(build 26100.8246)内核符号的逆向分析,其核心调用路径非常清晰1:

NtQuerySystemInformation(SystemInformationClass, SystemInformation, Length, ReturnLength)    -> nt!NtQuerySystemInformation         -> nt!ExpQuerySystemInformation        (负责参数分发与头部的基本 Probe)              -> nt!ExpGetProcessInformation   (核心进程遍历工作线程,包含未校验写)

漏洞的核心引爆点,就藏在 nt!ExpGetProcessInformation 这个负责收集进程信息的内部函数中。当传入的信息类(Information Class)为 253 时,函数内部会进入一段特殊的处理逻辑。


二、 核心源码审计:那个让校验失效的“零长度”陷阱

我们直接来看 nt!ExpGetProcessInformation 在处理类 253 时的关键反编译代码片段1:

NTSTATUS __fastcall ExpGetProcessInformation(        __int64 a1,         // 用户态传入的 SystemInformation 指针(完全由调用者控制)        unsignedint a2,    // 传入的 Length 缓冲区长度        _DWORD *a3,         // 返回长度指针        _DWORD *a4,         // 会话过滤参数        int a5)             // 信息类 (Class, 此处为 253){    unsignedint *v85, *v95, *v99;    ...    v95 = (unsignedint *)a1;    ...    if ( a5 == 253 ) {        v77 = 0;        v86 = 12;           // 固定的目标写入长度:12 字节        v71 = 12;        v87 = 0;        v99 = v95;          // <-- 关键点:v99 直接指向了用户态传入的指针 a1!        v85 = NULL;        goto LABEL_11;    }    ...LABEL_11:    ...    /* 长度校验段:仅仅设置状态,但不进行提前返回! */    v97 = v86;    v11 = a2 < v86;    if ( a2 < v86 ) {        if ( !a3 )            return STATUS_INFO_LENGTH_MISMATCH;        v11 = a2 < v86;    }    v13 = v11 ? STATUS_INFO_LENGTH_MISMATCH : 0;    // 状态被置为 MISMATCH,但函数继续硬着头皮往下走!

从这段代码里,我们可以敏锐地抓出两个极其致命的设计缺陷:

  1. 指针无条件混同:当 a5 == 253 时,全局指针变量 v99 被直接赋值为了 v95(即用户态传入的指针 a1)。在这之后,没有任何中间层去对 v99 指向的物理或虚拟地址合法性进行重新核对。
  2. 校验逻辑“形同虚设”:虽然代码检查了 a2 < v86(即用户传入的缓冲区长度是否小于 12 字节),但它并没有选择立即 return 错误码,而是把错误状态暂存到 v13 里,随后继续执行主循环。也就是说,即便你传进来的 Length 是 0,代码也不会在这里被拦住。

三、 触发点引爆:硬编码的 12 字节任意内核写

当代码流进入主循环、遍历完系统的进程链表后,真正触发崩溃和任意写的汇编现场出现了:

if ( a5 == 253 ) {            v25 = v99;            ++*v99;                                                     // 写入 #1: [target + 0] 自增 1            v25[1] += PsGetProcessActiveThreadCount((__int64)NextProcess);  // 写入 #2: [target + 4] 累加线程数            v25[2] += ObGetProcessHandleCount((struct _EX_RUNDOWN_REF *)NextProcess, 0LL);                                                                        // 写入 #3: [target + 8] 累加句柄数        }

这就是整个漏洞的绝对触发点:

  • 第一次写入:对目标地址的内容执行 ++*v99(4 字节递增)。
  • 第二次写入:在目标地址偏移 +4 的位置,加上当前遍历进程的活跃线程数(4 字节累加)。
  • 第三次写入:在目标地址偏移 +8 的位置,加上当前进程的句柄数(4 字节累加)。

加起来刚好是12 字节的内核写入原语。

为什么在顶层的 ExpQuerySystemInformation 里没有拦住它?因为在上层分发时,通用的 ProbeForWrite 检查是用用户传入的 Length(比如设为 0)去跑的。而当 Length == 0 时,ProbeForWrite 内部的页触摸和范围检查会直接变成空操作(No-op):

void __stdcall ProbeForWrite(volatilevoid *Address, SIZE_T Length, ULONG Alignment){    if ( Length ) { // <-- 只要 Length 为 0,大门直接敞开,根本不进循环检查!        ...    }}

这就形成了一个完美的逻辑闭环:攻击者在沙箱内调用 NtQuerySystemInformation,精心伪造类 253 且 Length=0,顶层检查放行,底层误以为有合法的 12 字节空间,直接往任意可写的内核地址(甚至是通过某种方式构造的虚拟地址)上疯狂叠加计数器。


四、 从 12 字节到 SYSTEM:攻击者的提权闭环

拿到这个 12 字节的写原语之后,利用链并没有直接去搞传统的内核劫持,而是玩了一套非常现代的“组合拳”:

  1. 破除 KASLR:利用这几次累加写入,去翻转内核中的某些状态标志位(如 Feature_RestrictKernelAddressLeaks),把原本藏得严严实实的内核地址指针给“挤”出来。
  2. 绕过经典窃取:攻击者没有去修改常规进程的 Token 指针,而是直接呼叫 NtCreateToken 系统调用。
  3. 凭空造令牌:在内存中利用系统原生 API 的合法通道,硬生生“捏”出一个带有 SeTcbPrivilege 特权的 SYSTEM 主令牌,并把它拍到自己头上。

至此,一个从浏览器沙箱出发,仅仅依靠内核记账逻辑在“加减法”上的疏忽,最终演变成了对整台 Windows 主机的完全接管。

已关注

关注

重播 分享 赞

关闭

观看更多

更多

退出全屏

切换到竖屏全屏退出全屏

Ots安全已关注

分享视频

,时长00:33

0/0

00:00/00:33

切换到横屏模式

继续播放

[ ]

进度条,百分之0

播放

00:00

/

00:33

00:33

倍速

全屏

倍速播放中

0.5倍0.75倍1.0倍1.5倍2.0倍

超清流畅

 您的浏览器不支持 video 标签

继续观看

代码审计视角下的 CVE-2026-40369:12 字节内核写与沙箱逃逸的底层触发点剖析

观看更多

转载

,

代码审计视角下的 CVE-2026-40369:12 字节内核写与沙箱逃逸的底层触发点剖析

Ots安全已关注

分享点赞在看

已同步到看一看写下你的评论

视频详情

参考:

  • https://voidsec.com/cve-2026-40369-browser-sandbox-escape/

END

公众号内容都来自国外平台-所有文章可通过点击阅读原文到达原文地址或参考地址

排版 编辑 | Ots 小安

采集 翻译 | Ots Ai牛马

公众号 | AnQuan7 (Ots安全)


代码审计视角下的CVE-2026-40369:12字节内核写与沙箱逃逸的底层触发点剖析" 网络安全文章

代码审计视角下的CVE-2026-40369:12字节内核写与沙箱逃逸的底层触发点剖析"

本文从代码审计视角深入剖析CVE-2026-40369漏洞,一个允许从浏览器沙箱逃逸至SYSTEM权限的12字节内核写入原语。核心缺陷在于NtQuerySystemInformation系统调用中,当信息类为253且用户传入长度为0时,ProbeForWrite检查形同虚设,导致底层函数ExpGetProcessInformation直接对用户可控指针进行硬编码的12字节写入。攻击者可利用此原语破除KASLR并调用NtCreateToken创建特权令牌,实现完全接管。
Shiro550反序列化漏洞原理与复现" 网络安全文章

Shiro550反序列化漏洞原理与复现"

本文详细介绍了ApacheShiro550反序列化漏洞(CVE-2016-4437)的原理与复现方法。漏洞源于Shiro框架的RememberMe功能使用固定AES密钥kPH+bIxk5D2deZiIxcaaaA==对用户身份信息进行加密,攻击者可利用此密钥构造恶意序列化数据触发远程代码执行。影响版本为Shiro≤1.2.24。文章提供了使用Vulhub搭建靶场及shiro\\_attack工具进行漏洞验证的步骤。
评论:0   参与:  0