
Joomla 6.1.3 - Élevé - À distance - ACL - GET /api/v1/users/levels divulgue les niveaux de visibilité
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · joomla-levels-api
Write-up : https://abraxaslabs.tech/research/joomla-levels-api
Classe : Privilège résiduel Portée : Distante
Joomla CMS 6.1.3 (0f2d4de) - Open Source Matters
Administrateur Utilisateurs -> Niveaux d'accès en visualisation nécessite core.admin sur com_users (LevelController::allowSave et suppression). Le webservice Groups fait déjà de même (GroupsController, 6.1.1). LevelsController ne possède aucune surcharge allowAdd, allowEdit ou delete, donc ApiController laisse passer core.manage plus core.create.
Un jeton d'API de classe Manager, accordé avec core.login.api sans core.admin, peut créer des niveaux d'accès en visualisation que l'interface interdit.
| ID | pas encore de CVE |
| Classe | Privilège résiduel / contournement d'autorisation |
| Portée | Distante (jeton d'API avec core.login.api) |
| CWE | CWE-863 |
| CVSS | Moyen : 6.1 CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N |
| Produit | Joomla CMS |
| Affecté | 6.1.3 (0f2d4de4729eb951e0878fec98c7990da07915b2) |
| Auth | Jeton d'API pour Manager (groupe 6) avec core.login.api et com_users manage/create/edit. Sans core.admin. Par défaut, core.login.api est réservé au Super User. |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 uniquement |
Utiliser un jeton d'API non-Super-User pour modifier quels groupes voient quelles pages. Il ne devient pas Super User à partir de ce seul privilège résiduel. Il s'agit d'un contrôle de visibilité du contenu, pas d'une prise de contrôle du site.
| Privilège | Méthode / chemin | Type | Prouvé en lab ou déduit |
|---|---|---|---|
| Créer un niveau d'accès en visualisation | POST /api/index.php/v1/users/levels JSON title, rules (ids de groupe) | intégrité | Prouvé en lab. HTTP 200, #__viewlevels id=7, titre poc-level-JOOMLA-LEVELS-API-WITNESS |
| Modifier un niveau existant (liste de groupes / titre) | PATCH /api/index.php/v1/users/levels/{id} | intégrité | Déduit. Même contrôleur, pas de allowEdit. Lab : création uniquement. |
| Supprimer un niveau | DELETE /api/index.php/v1/users/levels/{id} | intégrité / disponibilité des lignes ACL | Déduit. Même surcharge manquante. Le lab n'a pas effectué de DELETE. |
| Exposer un article, module ou élément de menu réservé aux membres | Nouveau niveau ou niveau modifié dont les rules incluent Public / Guest / Registered | reconnaissance (visibilité du contenu) | Déduit de #__viewlevels.rules. Le lab a inséré la ligne ; il n'a pas réappliqué d'ACL à un article en production. |
| Masquer une page aux Registered, ou ajouter le groupe de l'attaquant à un niveau Special | Même PATCH / création | intégrité | Déduit. Même stockage. |
| Modifier les groupes d'utilisateurs depuis l'API | POST /api/index.php/v1/users/groups | s.o. | Prouvé en lab fermé. HTTP 403 (GroupsController core.admin) |
| Ouvrir Administrateur Utilisateurs -> Niveaux d'accès en visualisation | GET /administrator/index.php?option=com_users&view=levels | s.o. | Prouvé en lab fermé. HTTP 403 |
| Enregistrer un niveau depuis l'interface | POST ... task=level.save | s.o. | Prouvé en lab fermé. HTTP 403 (LevelController::allowSave nécessite core.admin) |
Solliciter l'API avec un Manager standard (sans core.login.api) | Jeton Bearer / X-Joomla-Token | s.o. | Déduit fermé. Par défaut, core.login.api est réservé au Super User (groupe 8). Ce lab l'accorde d'abord au groupe 6. |
| RCE via Super User / installateur | s.o. | s.o. | Fermé. Le Manager reste Manager. |
J'ai épinglé joomla/joomla-cms 6.1.3 après la vague JSST de 2026-07/08. L'API Groups exige déjà core.admin. Les niveaux d'accès passent toujours par ApiController (core.manage plus core.create / core.edit / core.delete). La seule logique supplémentaire sur LevelsController est le décodage JSON PATCH de rules.
Sibling Groups corrigé :
public function allowAdd($data = [])
{
return $this->app->getIdentity()->authorise('core.admin', $this->option);
}
Interface d'administration :
protected function allowSave($data, $key = 'id')
{
return $this->app->getIdentity()->authorise('core.admin', $this->option)
&& parent::allowSave($data, $key);
}
Faux pas déjà consignés : traiter l'API Groups comme encore ouverte (elle renvoie 403) ; interroger l'API en tant que Manager standard sans avoir d'abord accordé core.login.api (par défaut réservé au Super User, même configuration que CVE-2026-71574 / 72531 / 48904) ; interpréter le 403 de l'UI comme l'histoire complète (le reliquat, c'est l'API). Théâtre : un reverse shell. L'oracle est API 200 plus Groups 403 plus UI 403.
Mêmes reliquats d'épinglage : menu items API, media override, articles catid.
python3 joomla-levels-api-Abraxas-Labs.py
ou
cd lab
./run.sh
Ciblez uniquement http://127.0.0.1:19520. Image joomla:6.1.3-php8.3-apache plus mariadb:11.4.
SUCCESS joomla-levels-api api-http=200 level-id=7 groups-api=403 ui-view=403 ui-save=403 JOOMLA-LEVELS-API-WITNESS
Copiez core.admin allowAdd / allowEdit / delete de GroupsController vers LevelsController. Conservez la restriction de l'interface administrateur.
0f2d4de4729eb951e0878fec98c7990da07915b2)LevelsController.phpcore.admin (6.1.1) · CVE-2026-71574GNU Affero GPL v3.0. Voir LICENSE. Laboratoire en boucle locale uniquement. Aucune garantie.