Skip to content
Kurisu
Go back

React2Shell 漏洞五讲:从 Thenable 到 15 万美元的 WAF 绕过

之前写过 Next.js CVE-2025-29927(middleware 鉴权绕过),那是 Next.js 的”门卫”问题。React2Shell 是另一个量级的东西——React Server Components(RSC)链路的 RCE,前端框架写出了后端级别的洞。这篇整理自一套五篇连载课件(作者参与应急并拿下 Vercel 官方 WAF 绕过活动的奖金),按原课程顺序讲:前置知识 → 调试环境 → 协议 → 原理 → 绕过。

0x01 前置:从回调地狱到 Thenable

看懂这个洞要先懂 JS 异步的演进史:

  1. 回调地狱:古早 JS 大量 API 靠回调,登录拿token → 查用户id → 查订单 的流程层层嵌套,可读性差且难复用;
  2. Promise(ES6):把”嵌套”变”链式调用”,then() 让回调回到同一上下文——函数式编程思想的落地;
  3. Thenable:任何实现了 then() 方法的对象。React 内部处理数据时会检查”这个值是不是 Thenable,是就调用它的 then”——记住这句话,漏洞的引信就是它

0x02 SSR vs RSC:前端怎么写出了后端漏洞

Next.js Conf 2023 有个著名场面:团队成员演示用 React 19 的 Server Components + Server Actions 解决客户端 bundle 越来越大的问题,推特上吵翻天——嘲讽者说这是”历史的倒退”,Web 开发回到了 90 年代 PHP/JSP 的模式,“前端开发也可以写后端漏洞了”。

一语成谶。两者区别:

攻击面由此而来:Flight 协议的解析端是服务端代码,处理的是”可被伪造的客户端数据”。

0x03 应急视角:为什么 SCA 扫不到这个组件

漏洞通告出来当天,作者的应急流程值得抄作业:

  1. 按通告排查 react-server-dom-webpack 等漏洞组件——查 npm 日志和 SCA(软件成分分析),结果寥寥
  2. 但公司明明有 Next.js 业务。猜想:RSC 对 Next.js 是可选依赖,开发没装;
  3. 拿 Vulhub 源码直接调试验证 → 发现真相:Next.js 不像传统 JS 项目单独装依赖,而是把第三方依赖直接打包进 compiled 目录——所以 SCA 依赖清单里根本看不到 react-server-dom-webpack

教训一句话:框架自打包依赖会绕过你的成分分析,SCA 说”没有”不等于”不受影响”,要以调试为准。

0x04 Flight 协议:Chunk 是怎么被解析的

RSC 数据包由一个个 Chunk 组成,服务端解析流程:

遍历 multipart 字段
  → 每个字段 JSON.parse() 成对象
  → 递归遍历所有子孙结构
  → 发现 $ 开头的值 → 按规则互相"引用"(扩展 JSON 不支持的类型:函数/组件/Thenable…)
  → 结果放进 chunk.value,作为"数据"

$ 前缀引用机制是 Flight 对 JSON 的类型扩展,也是攻击者往解析过程里塞逻辑的入口。

0x05 漏洞本质:还是”混淆数据和业务逻辑”

我反复验证的万能公式:SQL 注入是输入变成 SQL、命令注入是输入变成命令、XSS 是输入变成 HTML——React2Shell 是攻击者的”数据”变成了服务端的”Chunk 对象”

POC 的形态:POST 一个 multipart 请求(Next-Action: x 头 + Content-Type: multipart),其中模拟一个假的 Chunk 对象——通过 $ 引用构造出带 constructor 的原型链结构,让解析器把攻击者控制的”数据”识别成了可调用对象(Thenable/函数路径),随后触发执行,达成 RCE。

数据变代码的边界在这里失守:JSON.parse 的产物本该只是数据,但 $ 引用 + 原型链让解析器”亲手”把它升格成了逻辑。

0x06 15 万美元的 WAF 绕过

漏洞爆发后 Vercel 官方办了 WAF 绕过活动,作者拿下奖金。思路分两档:

思维实验级(大多数人能想到)

工程级细节

0x07 小结与防守清单

相关旧文


Share this post:

Previous Post
CMS 与框架漏洞版图:WordPress、ThinkPHP、织梦与十年老洞的现实
Next Post
PHP 代码审计入门靶场复盘:call_user_func、一句话马与 HPP