echosecure/vuln-chain-lab
GitHub: echosecure/vuln-chain-lab
演示文件上传绕过与存储型XSS漏洞链如何绕过CSP/CORS/CSRF防护创建后门管理员账户的Docker靶场。
Stars: 0 | Forks: 0
# 文件上传绕过 + 存储型 XSS PoC 实验室
一个故意存在漏洞的 Web 应用程序,演示了文件上传绕过如何与存储型 XSS 结合以创建后门管理员账户,即使启用了 CSP、CORS 和 CSRF 防护。
完整博文:[KurtiseBear Blog](https://kurtisebear.com/2026/03/28/chaining-file-upload-xss-admin-compromise/)
**这是一个用于防御性安全培训的教育实验室。请勿将其部署在任何可公开访问的地方。**
## 演示内容
该应用程序具有真正的安全控制措施:
- **Content Security Policy** 将脚本源限制为 `'self'`(但启用了 `'unsafe-inline'` 和 `'unsafe-eval'`)
- **不发送 CORS headers**,因此浏览器会阻止跨域请求
- **CSRF tokens** 用于所有表单提交(消息、文件上传)
- **标准安全头**(X-Content-Type-Options, X-Frame-Options, Referrer-Policy)
拥有低权限用户账户的攻击者可以通过链接两个漏洞来绕过所有这些防护:
1. **文件上传绕过** —— 上传表单通过客户端 `accept` 属性限制为 `.pdf`,但服务器端不执行任何文件类型验证。攻击者上传包含 JavaScript 的 `.js` 文件。下载端点从同源提供该文件,因此 CSP 和 CORS 不会阻止它。
2. **通过消息主题进行的存储型 XSS** —— 消息功能在未经净化的情况下存储用户输入。管理员收件箱将消息主题渲染为原始 HTML。XSS payload 使用 `
` 处理程序来获取上传的脚本并 `eval()` 它。CSP 允许这样做,因为允许 `'unsafe-inline'` 和 `'unsafe-eval'`。
3. **API 端点上缺少 CSRF** —— 用户管理 API (`/api/manage-user.php`) 不验证 CSRF tokens,尽管表单端点会验证。XSS payload 使用管理员的同源会话调用此 API。即使存在 CSRF,同源 JavaScript 也可以从 DOM 中读取 token。
结果:当管理员打开收件箱时,XSS 触发,JavaScript 使用管理员的会话创建后门管理员账户。每项防御都已到位并正常运作。此链之所以有效,是因为它从未离开源站。
## 前置条件
- Docker
- Docker Compose
## 设置
```
docker-compose up -d
```
等待 10-15 秒让 MySQL 初始化,然后访问 http://localhost:8080
### 凭据
| 角色 | 邮箱 | 密码 |
|--------|--------------------|----------|
| Admin | admin@company.com | admin |
| User | user@company.com | user |
## 攻击演示
### 步骤 1:以普通用户身份登录
访问 http://localhost:8080 并使用 `user@company.com` / `user` 登录。
### 步骤 2:上传 payload
转到 **Upload Files**。表单显示“PDF only”,但仅在客户端强制执行。可以:
- 使用浏览器开发者工具从文件输入中删除 `accept=".pdf"` 属性,或
- 使用 curl/Burp 直接上传(你需要包含表单中的 CSRF token)
上传提供的 `payload.js`(或你自己的)。记下返回的文件 ID(例如 `1`)。
上传的文件现在从同源的 `/api/download.php?file_id=1` 提供。CSP 不会阻止对此端点的 fetch,因为它是 `'self'`。
### 步骤 3:构建 XSS 消息
转到 **Send Message**。在主题字段中输入:
```
```
(将 `1` 替换为步骤 2 中的实际文件 ID。)
正文随便填。如果希望它显示在收件箱顶部,请勾选 priority。发送。
`onerror` 处理程序有效,因为 CSP 允许 `'unsafe-inline'`。`eval()` 有效,因为 CSP 允许 `'unsafe-eval'`。对下载端点的 fetch 有效,因为它是同源的。
### 步骤 4:等待管理员检查收件箱
注销。以 `admin@company.com` / `admin` 身份登录。转到 **Inbox**。
消息主题渲染为原始 HTML。`
` 标签加载失败,`onerror` 处理程序触发,获取上传的 payload,`eval()` 执行它。该 payload 使用管理员的会话 cookie(对于同源请求会自动附加)POST 到 `/api/manage-user.php`。不需要 CSRF token,因为 API 端点不检查它。
### 步骤 5:验证后门
转到 **Users**。你应该看到一个新用户:`BackdoorAdmin`,角色为 `admin`,邮箱为 `attacker@evil.com`。
注销并使用 `attacker@evil.com` / `Compromised1!` 登录以确认。
## 为什么防御失败了
```
CSP blocks external scripts
--> But the payload is hosted on the same origin via file upload
--> And unsafe-inline/unsafe-eval allow the onerror handler and eval()
CORS blocks cross-origin requests
--> But every request in the chain is same-origin
CSRF tokens protect form submissions
--> But the API endpoint doesn't validate them
--> And even if it did, same-origin JS can read tokens from the DOM
Session cookies have standard protections
--> But same-origin requests carry them automatically
```
防御措施都正常工作。它们旨在阻止跨域攻击。这个链从未离开源站。
## 防御措施
真正能打破这个链的措施:
1. **服务器端文件类型验证** —— 检查 MIME 类型、文件扩展名和魔数。不要信任客户端。这可以防止攻击者在你的源站上托管 payload。
2. **输出编码** —— 对所有用户控制的输出使用 `htmlspecialchars()`。收件箱原始渲染 `$row['subject']`。这能彻底扼杀 XSS。
3. **严格的 CSP** —— 移除 `'unsafe-inline'` 和 `'unsafe-eval'`。为合法的内联脚本使用 nonce 或 hash。这会阻止 `onerror` 处理程序和 `eval()`。
4. **Content-Disposition: attachment** —— 强制下载用户上传的文件,而不是内联渲染。这可以防止浏览器解释上传的内容。
5. **所有更改状态的端点都要有 CSRF** —— 包括 API 端点,而不仅仅是表单。
6. **上传的访问控制** —— 下载 API 向任何经过身份验证的用户提供任何文件。文件应限定为其所有者。
## 清理
```
docker-compose down -v
```
## 免责声明
此应用程序是故意存在漏洞的。它仅用于教育和防御性安全培训目的。请勿将其部署在任何可供不受信任用户访问的网络上。未经明确书面授权,请勿将这些技术用于攻击系统。
标签:CISA项目, CORS, CSP绕过, CSRF, Docker, ffuf, OPA, OpenVAS, PHP, PoC, Web安全, XSS, 协议分析, 后门账户, 多模态安全, 存储型XSS, 安全培训, 安全防御评估, 数据可视化, 数据展示, 文件上传绕过, 暴力破解, 权限提升, 漏洞情报, 漏洞链, 红队, 网络安全, 蓝队分析, 请求拦截, 隐私保护, 靶场