CVE-2026-27971 Qwik 框架反序列化 RCE 漏洞分析与利用
字数 3931
更新时间 2026-04-01 13:18:57

CVE-2026-27971 Qwik 框架反序列化远程代码执行漏洞教学文档

漏洞概述

漏洞编号: CVE-2026-27971
影响产品: Qwik JavaScript 框架
受影响版本: ≤ 1.19.0
漏洞类型: 反序列化漏洞 → 远程代码执行
CVSS评分: 9.2 (高危)
披露时间: 2026年3月24日
修复版本: 1.19.1

漏洞描述

Qwik 是一个注重性能的 JavaScript 框架。在版本 1.19.0 及之前的 server$ 远程过程调用机制中,存在不安全的反序列化实现,使得任何未经验证的攻击者都能通过发送单个精心构造的 HTTP 请求,在服务器上执行任意系统命令,实现远程代码执行。该漏洞影响所有在 Node.js 运行时上部署的、使用了受影响版本 Qwik 框架的应用。

漏洞核心原理

漏洞的根本原因在于,Qwik 框架在特定条件下会信任并反序列化用户可控的输入,并且能够通过特定的序列化格式,动态加载 Node.js 核心模块(如 child_process)并调用其中的危险函数。

详细技术分析

攻击面与触发条件

攻击需要满足以下条件才能成功触发:

  1. 目标服务器运行着 Qwik ≤ 1.19.0 版本的应用。
  2. 目标应用至少存在一个有效的页面路由。
  3. 攻击者能够向该路由发送一个特制的 POST 请求。

漏洞利用链分解

整个攻击流程遵循以下链条:构造恶意请求触发反序列化绕过校验动态加载模块执行系统命令

第一步:构造恶意 HTTP 请求

一个能够触发漏洞的完整 HTTP 请求示例如下:

POST /some-page?qfunc=exec HTTP/1.1
Host: victim.com
Content-Type: application/qwik-json
X-QRL: exec
Content-Length: 87

{
  "_objs": ["child_process#exec[['whoami']]"],
  "_entry": "0"
}

关键参数解释

  • 路径 (/some-page): 必须是目标服务器上真实存在的页面路由。攻击者通常需要先对目标进行路径枚举。
  • 查询参数 (?qfunc=exec): 此处的值 exec 需要与后面请求体中的恶意函数名,以及 X-QRL 请求头的值匹配。它是服务端查找和验证要执行的函数的依据之一。
  • 请求头 (X-QRL: exec): 其值必须与 qfunc 参数的值完全相同,这是框架进行初步校验的环节。
  • 请求头 (Content-Type: application/qwik-json): 这是触发框架进入特殊反序列化路径的关键,如果类型不是此值,请求体会被当作普通数据处理。
  • 请求体 (_objs 数组): 这是载荷的核心。数组中的字符串 child_process#exec[['whoami']] 是一个 QRL 序列化字符串,它指定了要加载的模块(child_process)、要调用的函数(exec)以及传递给函数的参数(['whoami'])。

第二步:后端处理流程与漏洞触发点

  1. 请求接收与路由:请求首先进入 packages/qwik-city/src/middleware/node/index.ts 的中间件。该处将原生 Node.js 请求转换为 Qwik 内部格式,并注入反序列化器 (qwikSerializer)。
  2. 路由匹配:在 packages/qwik-city/src/middleware/request-handler/resolve-request-handlers.ts 中,框架尝试匹配请求路径。如果匹配到一个已存在的页面路由,runServerFunction 处理函数会被自动添加到处理链中。
  3. 校验与解析:在 runServerFunction 函数中,框架执行以下检查:
    • 从 URL 查询参数中获取 qfunc 的值(记为 fn)。
    • 验证请求头 X-QRL 的值是否等于 fn
    • 验证 Content-Type 是否为 application/qwik-json
      如果全部通过,则调用 ev.parseBody() 解析请求体,从而进入反序列化流程。
  4. 触发反序列化:在 request-event.ts 中,由于 Content-Type 匹配,框架直接调用 qwikSerializer._deserializeData 对请求体进行反序列化。
  5. 解析 QRL 字符串:在反序列化器的 _deserializeData 方法中,会遍历 _objs 数组。当遇到以特殊前缀()开头的字符串时,会调用 parser.prepare 进行处理,最终进入 parseQRL 函数。
  6. 解析载荷结构parseQRL 函数按照特定格式解析字符串 child_process#exec[['whoami']]
    • chunk: "child_process" (模块名)
    • symbol: "exec" (函数名)
    • captures: ["['whoami']"] (函数参数)
  7. 创建 QRL 对象:解析后的参数被传递给 createQRL 函数,创建一个 QRL 对象。此对象包含一个关键的 getHash() 方法,用于返回该 QRL 的哈希标识。哈希的计算规则(见 getSymbolHash 函数)是:提取 symbol 字符串中最后一个下划线 (_) 之后的部分;如果没有下划线,则返回整个 symbol。对于 symbol = "exec",其哈希值 hash = "exec"

第三步:绕过执行校验

创建 QRL 对象后,流程回到 runServerFunction。此处存在一个关键校验:

if (isQrl(qrl) && qrl.getHash() === fn) {
  // 执行 QRL
}

此校验意图是确保要执行的 QRL 对象与请求中声明的 (qfunc=fn) 是同一个。然而,这里的校验逻辑是用 QRL 对象的哈希值URL 参数 fn 进行比较。
在我们的攻击载荷中,qrl.getHash() 返回 "exec",而 URL 参数 ?qfunc=exec 使得 fn 的值也是 "exec"。因此,校验通过,程序继续执行这个 QRL 对象。

第四步:动态模块加载与命令执行

  1. 解析模块路径:执行 QRL 时,会调用 importSymbol 函数来动态加载模块。该函数会将我们指定的 chunk ("child_process") 补上 .js 后缀,变为 "child_process.js",然后尝试通过 Node.js 的 require 函数加载。
  2. 查找并调用函数require("child_process.js") 实际上会加载 Node.js 内置的 child_process 核心模块。接着,框架会尝试从这个模块对象中查找名为 symbol ("exec") 的导出。child_process.exec 函数是真实存在的,因此被成功找到并返回。
  3. 最终执行:返回的 child_process.exec 函数被调用,参数为我们通过 captures 指定的 ['whoami']。至此,系统命令 whoami 在服务器上成功执行,攻击完成。

关于错误示例的说明:文档中提到了一个错误示例 child_process#exec_abc123[['whoami']]。这个载荷的问题在于,它生成的 symbol"exec_abc123",其哈希值 hash"abc123"。虽然这样能通过 qrl.getHash() === fn 的校验(只需设置 ?qfunc=abc123),但在 importSymbol 阶段,框架会在 child_process 模块中查找名为 "exec_abc123" 的导出,而这个导出并不存在,导致攻击失败。因此,正确的攻击载荷中,symbol 必须是目标模块中真实导出的函数名。

漏洞修复

在 1.19.1 版本中,官方修复了此漏洞。主要的修复点在于修改了 importSymbol 函数(或相关逻辑),限制了动态加载模块的范围,禁止了通过此类反序列化操作任意加载 Node.js 核心模块(如 child_process, fs, os 等)或文件系统上其他危险模块的能力,从根本上杜绝了通过此途径实现远程代码执行的可能。

缓解与防范建议

  1. 立即升级:所有使用 Qwik 框架的项目应立即升级到 1.19.1 或更高版本。这是最根本、最有效的解决方案。
  2. 输入验证与过滤:对于无法立即升级的环境,应在网关、WAF 或应用层中间件上,对传入的请求进行严格检查。可考虑拦截或阻断满足以下特征的请求:
    • Content-Type: application/qwik-json
    • 包含 X-QRL 请求头
    • 查询字符串中包含 qfunc 参数
    • 请求体中含有疑似 QRL 序列化字符串(如包含 #[ 的特定格式)。
  3. 网络隔离:运行受影响应用的服务应处在严格的网络策略之下,限制其出网和横向移动的能力,以降低漏洞被利用后的影响。
  4. 最小权限原则:运行 Qwik 应用的进程应遵循最小权限原则,避免使用 root 或高权限账户运行,以限制命令执行成功后攻击者获得的权限。

参考链接

  • 官方安全公告:https://github.com/QwikDev/qwik/security/advisories/GHSA-p9x5-jp3h-96mm
相似文章
相似文章
 全屏