Kimdir01/library-qr-csrf-xss-cve

GitHub: Kimdir01/library-qr-csrf-xss-cve

针对图书馆二维码系统的安全概念验证,披露了 CSRF 禁用、存储型 XSS、弱 UID 生成及缺少授权等十余项漏洞详情。

Stars: 0 | Forks: 0

# GitHub 安全公告:图书馆二维码系统 (CodeIgniter 4) — CSRF 被禁用、存储型 XSS、弱 UID ## 公告信息 | 字段 | 值 | |-------|-------| | **严重程度** | 严重 / 高 | | **CWE** | CWE-352 (CSRF 被禁用) / CWE-79 (存储型 XSS) / CWE-327 (弱加密) | | **CVSS v3.1** | 9.8 (全局 CSRF 被禁用) / 8.5 (存储型 XSS) / 5.0 (弱 UID) | | **CVSS 向量** | AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H | ## 摘要 图书馆二维码系统 (Sistem Perpustakaan QR Code, CodeIgniter 4) 存在全局禁用 CSRF 保护的问题(在全局 `before` 过滤器链中 `csrf` 过滤器被注释掉了)、通过未转义的图书/会员数据输出导致的系统性存储型 XSS(任何地方都没有使用 `esc()`)、使用 SHA-1 且仅有 1001 种可能熵值的弱 UID 生成方式,以及所有 admin 控制器缺少授权/存在 IDOR。 ## 漏洞详情 ### 受影响的包/仓库 - **仓库:** `sistem-perpustakaan-qr-code` - **受影响版本:** 当前版本 - **修复版本:** 无 (0-day) **提交哈希 (已审计):** `a7084f0e8f001d340c68a3b4ced6f263a3bdfd58` ## CVE-REQUEST-001:全局 CSRF 保护被禁用 (CVSS 9.8) **文件:** `app/Config/Filters.php`,第 37-39 行 ``` 'before' => [ // 'honeypot', // 'csrf', // <-- COMMENTED OUT! 'forcehttps', 'pagecache', ], ``` `csrf` 过滤器在全局 `before` 链中被注释掉了。CodeIgniter 4 不会验证 POST/PUT/DELETE 请求上的 CSRF token,即使视图仍然渲染了 `` —— 服务端验证也永远不会执行。 **受影响的操作(均存在 CSRF 漏洞):** - 创建/编辑/删除图书 - 创建/编辑/删除会员(完整 PII) - 创建/删除借阅(借书) - 还书 - 缴纳罚款(可能部分支付) - 创建/更新/删除 admin 用户 - 更改罚款设置 - 对类别和书架进行 CRUD 操作 ## CVE-REQUEST-002:图书和会员数据中的存储型 XSS (CVSS 8.5) **根本原因:** 所有视图都没有使用 CI4 的 `esc()` 函数。`` 语法不会自动转义。 **通过 `string` 验证字段的 XSS:** - 图书标题 (`required|string|max_length[127]` — 接受任何 HTML/JS) - 图书出版社 (`required|string|max_length[64]`) - 会员地址 (`required|string|min_length[5]|max_length[511]`) **受影响的视图(所有输出均未转义):** - `books/index.php:85` — `` - `books/show.php:66-69` — 标题、作者、出版社、年份 - `members/index.php:67-72` — 会员姓名、电子邮件、电话、地址 - `members/show.php:67-68` — 会员详情 - `loans/index.php:92` — 图书标题 - `home/book.php:61` — 搜索结果 **PoC:** 创建图书时,将标题设置为: ``` ``` 任何查看图书列表的 admin 都会触发该 payload。 ### 搜索中的反射型 XSS (CVSS 8.1): **7 个文件**包含 `value=""` — 搜索 GET 参数未经转义直接输出: - `books/index.php:36`, `members/index.php:28`, `loans/index.php:33`, `returns/index.php:32`, `fines/index.php:40`, `home/book.php:26` PoC: `/admin/books?search=">` ## CVE-REQUEST-003:弱 UID 生成 (SHA-1 + rand 1001) (CVSS 5.0) **文件:** `app/Controllers/Members/MembersController.php`,第 193-199 行 ``` $uid = sha1( $this->request->getVar('first_name') . $this->request->getVar('email') . $this->request->getVar('phone') . rand(0, 1000) // Only 1001 possible values! . md5($this->request->getVar('gender')) ); ``` 只有 1001 种可能的随机值。如果 first_name、email 和 phone 是已知的(通常是可猜测的),攻击者可以通过尝试所有 1001 个 `rand()` 值来暴力破解 UID。 ## CVE-REQUEST-004:所有 Admin 路由缺少授权 / 存在 IDOR (CVSS 6.5) **文件:** `app/Config/Routes.php`,第 39 行 ``` $routes->group('admin', ['filter' => 'session'], ...); ``` `admin/*` 路由仅应用了 `session` 过滤器(检查用户是否已登录)。没有基于角色的授权: - `MembersController::show()` — 任何 admin 都可以通过 UID 查看任何会员的完整 PII、借阅历史、罚款 - `LoansController::show()` — 任何 admin 都可以查看任何借阅记录 - `ReturnsController::create()` — 任何 admin 都可以处理任何借阅的还书 - `FinesController::pay()/update()` — 任何 admin 都可以修改/支付任何罚款 只有 `fines/settings` 和 `users` 路由具有 `group:superadmin` 过滤。 ## CVE-REQUEST-005:库存验证中的竞态条件 (CVSS 5.3) **文件:** `app/Controllers/Loans/LoansController.php`,第 283-359 行 `create()` 方法在插入借阅记录之前不会重新验证图书库存。如果两个 admin 同时提交同一本书的借阅,即使只有一本可借,两者也都会成功。没有针对会员的借阅限制。 ## 其他发现(共 14 项): | # | 漏洞 | CVSS | 类型 | |---|--------------|------|------| | 4 | AJAX 搜索端点泄露完整的会员 PII | 6.5 | 信息泄露 | | 6 | 删除二维码/图书封面时的路径遍历 | 6.1 | 路径遍历 | | 9 | Dashboard 加载所有数据且没有分页 | 5.3 | 信息泄露 | | 10 | 图书封面上传至 Web 可访问目录 | 5.3 | 文件上传 | | 11 | 通过 GET 参数重新生成二维码 | 3.5 | 业务逻辑 | | 12 | 撤销还书反转罚款且无审计 | 4.3 | 业务逻辑 | | 13 | Session matchIP=false,Cookie 安全性弱 | 3.7 | Session 管理 | | 14 | .env.example 中的默认 root 凭据 | 3.3 | 硬编码密钥 | ## 影响 - 通过 CSRF 实现**完全接管应用程序**(任何 admin 操作均可被伪造) - 通过影响所有 admin 的存储型 XSS 实现 **Session 劫持** - 通过 IDOR + AJAX 枚举导致**会员 PII 泄露** - 通过针对 fines/pay 的 CSRF + IDOR 进行**罚款篡改** - 通过竞态条件实现**图书失窃**(借阅图书而不减少库存) ## 补丁 / 修复 1. **严重:** 在 `Filters.php` 全局 `before` 数组中取消对 `'csrf'` 的注释 2. 在视图中所有的 `` 输出中添加 `esc()`(尤其是图书标题、会员数据) 3. 将 `sha1(...rand(0,1000))` 替换为 `bin2hex(random_bytes(16))` 4. 添加所有权/权限检查(不仅仅是 `session` 过滤器) 5. 添加并强制执行每个会员的借阅限制 6. 重命名 `delete()` 还书方法,要求使用带 CSRF 的 POST 请求 7. 在 `public/uploads/` 中添加 `.htaccess` 拒绝访问 `.php` 8. 在输出前验证 `$search` 参数 ## 披露时间线 - **2026-06-28:** 所有漏洞由 Fatullayev Asadbek (Kimdir01) 发现 - **待定:** 报告给维护者 - **待定:** 通过 GitHub 请求 CVE - **待定:** 发布公告 ## 致谢 - 发现者:Fatullayev Asadbek | GitHub: Kimdir01 - 独立安全研究员 ## 参考 - CWE-352:跨站请求伪造 - CWE-79:跨站脚本攻击 - CWE-327:使用破损或有风险的加密算法 - CWE-862:缺少授权
标签:CodeIgniter, CSRF, Web安全, 存储型XSS, 漏洞证明, 蓝队分析, 越权访问