JoomGallery ≤ 4.3.0 — 编辑器角色用户可劫持任意相册图片并存储 XSS 载荷,从而实现管理员会话接管
JoomGallery 中的 UserimageController::save() 检查的是 checkACL('edit', ...),而非 checkACL('edit.own', ...)。拥有编辑器(Editor)角色的用户可以无视图片归属,向 task=userimage.save&id=N 发起 POST(IDOR — CWE-639)。由于编辑器角色全局拥有 core.edit 权限,因此站点上每个图片 ID 的授权检查都会通过,包括管理员拥有的图片。
再加上前端图片模板中缺少 $this->escape() 调用,编辑器用户可以在任意图片标题(包括管理员拥有的图片)中存储 XSS 载荷,导致 JavaScript 在每个访客的浏览器中执行。这可以实现完全的管理员会话劫持和整站沦陷。
| 组件 | 受影响版本 | 测试环境 | 修复版本 |
|---|---|---|---|
| JoomGallery (com_joomgallery) | 4.0.0 – 4.3.0 | Joomla 5.4.7 + JoomGallery 4.3.0-stable (PHP 8.2 / Apache) | 4.4.0 |
类型: 失效的对象级授权 / IDOR(CWE-639)与存储型跨站脚本(CWE-79)链式利用 所需认证: 低权限编辑器账户
文件: components/com_joomgallery/src/Controller/UserimageController.php
save() 操作使用 edit 权限(而非 edit.own)执行 ACL 检查。edit 权限被全局授予所有编辑器角色用户,因此无论图片由谁创建,该检查对任何图片 ID 都会通过。
USERIMAGECONTROLLER.PHP — 漏洞代码(第 145 行)
// Vulnerable
if (!$this->checkACL('edit', 'image', $recordId, $parent_id, true)) { ... }
由于编辑器用户组全局持有 core.edit 权限,该条件对每个图片 ID 均评估为 false,从而授予无限制的写入访问权。保存成功后,模型还会将 created_by 更新为攻击者的用户 ID,悄无声息地将图片所有权转移给攻击者。
文件: components/com_joomgallery/tmpl/image/default.php
前端图片模板在 alt 属性上下文中直接输出 $this->item->title,未进行 HTML 编码。Joomla 的 JInput STRING 过滤器不会去除双引号字符,因此包含 " 的载荷可以突破该属性并注入任意事件处理器。
DEFAULT.PHP — 漏洞代码(第 64、78 行)
// Vulnerable
item->title; ?>" ...>
载荷 abc" onmouseover="alert(document.domain);" x=" 被存入 jos_joomgallery.title,并在每次页面渲染时原样注入 HTML 属性。在存储层和显示层均未进行任何净化处理。
task=userimage.save&id=3 发起 POST,并在 jform[title] 中携带 XSS 载荷。ACL 检查通过(core.edit,而非 edit.own)。服务器返回 HTTP 303 — 而非 403。created_by 被转移为攻击者的用户 ID。jos_joomgallery.title 中。alt="abc" onmouseover="alert(document.domain);"。XSS 触发。管理员会话被捕获 → 整站沦陷。管理员通过 JoomGallery 后端(Joomla 5.4.7)创建 admin_image。图片已发布、已批准,属主为 管理员

GET /index.php/component/users/login — 响应 JSON 中包含 "csrf.token":"a68c2b3a..."。该令牌被捕获,用于随后的登录 POST。

joomla_user_state=logged_in使用 CSRF 令牌和编辑器凭据执行 POST /index.php/component/users/login。响应:HTTP 303 和 Set-Cookie: joomla_user_state=logged_in。会话 Cookie 被捕获。

携带会话 Cookie 执行 GET /index.php?option=com_joomgallery。响应中包含一个新的 "csrf.token":"2d96934b...",用于保存请求。

编辑器用户向 option=com_joomgallery&task=userimage.save&id=3 发起 POST,并将 jform[title] 设置为:
abc" onmouseover="alert(document.domain);" x="
服务器返回 HTTP 303(而非 403),确认了 IDOR 的存在。Location 头在重定向 URL 中显示 XSS 载荷,确认标题已被接受并保存。

JoomGallery 后端显示图片 ID=3 现在的属主为:Editor User。在未经授权的保存过程中,数据库中的 created_by 字段被悄然更新。

对 jos_joomgallery 的 SQL 查询确认 XSS 载荷已被存储 — " 以原始双引号形式存储,而非 "。存储层未进行任何净化处理。

任何访问 /index.php/component/joomgallery/gallery 的用户都会触发该载荷。浏览器的 alert() 对话框确认了 JavaScript 在受害者源(document.domain)中执行。

created_by 静默重新指派给攻击者,永久篡改审计轨迹。alt 属性中的恶意脚本可以窃取管理员的会话 Cookie,使攻击者获得完整的后端访问权限并控制整个 Joomla 安装。S:C)中执行,跨越了攻击者低权限会话与受害者高权限会话之间的信任边界。