
IDOR + Stored XSS durch fehlerhafte Autorisierung auf Objektebene in JoomGallery
JoomGallery ≤ 4.3.0 — Editor-Role User Hijacks Any Gallery Image and Stores XSS Payload, Enabling Admin Session Takeover
UserimageController::save() in JoomGallery prüft checkACL('edit', ...) anstelle von checkACL('edit.own', ...). Ein Benutzer mit der Rolle „Editor" kann unabhängig vom Besitzer an jedes Bild ein POST an task=userimage.save&id=N senden (IDOR — CWE-639). Da die Editor-Rolle global über core.edit verfügt, besteht die Autorisierungsprüfung für jede Bild-ID auf der Website, einschließlich Bildern, die Administratoren gehören.
In Kombination mit einem fehlenden $this->escape()-Aufruf in der Frontend-Bildvorlage kann ein Editor eine XSS-Payload im Titel eines beliebigen Bildes speichern – einschließlich Bildern von Administratoren –, was zur Ausführung von JavaScript im Browser jedes Besuchers führt. Dies ermöglicht eine vollständige Übernahme der Admin-Sitzung und eine Kompromittierung der gesamten Website.
| KOMPONENTE | VERWUNDBAR | GETESTET AUF | BEHOBEN |
|---|---|---|---|
| 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 |
Typ: Broken Object-Level Authorization / IDOR (CWE-639) verkettet mit Stored Cross-Site Scripting (CWE-79) Erforderliche Authentifizierung: Editor-Konto mit niedrigen Rechten
Datei: components/com_joomgallery/src/Controller/UserimageController.php
Die Aktion save() führt eine ACL-Prüfung mit der Berechtigung edit anstelle von edit.own durch. Die Berechtigung edit wird allen Benutzern mit der Rolle „Editor" global gewährt, sodass die Prüfung für jede Bild-ID unabhängig vom Ersteller erfolgreich ist.
USERIMAGECONTROLLER.PHP — VERWUNDBARER CODE (ZEILE 145)
// Verwundbar
if (!$this->checkACL('edit', 'image', $recordId, $parent_id, true)) { ... }
Da core.edit von der Editor-Gruppe global gehalten wird, ergibt die Bedingung für jede Bild-ID false, was uneingeschränkten Schreibzugriff gewährt. Bei einem erfolgreichen Speichern aktualisiert das Modell außerdem created_by auf die Benutzer-ID des Angreifers und überträgt damit stillschweigend den Besitz des Bildes an den Angreifer.
Datei: components/com_joomgallery/tmpl/image/default.php
Die Frontend-Bildvorlage gibt $this->item->title aus, ohne es für den alt-Attributkontext HTML-zu kodieren. Der JInput-Filter STRING von Joomla entfernt keine doppelten Anführungszeichen, sodass eine Payload mit " aus dem Attribut ausbricht und beliebige Event-Handler injiziert.
DEFAULT.PHP — VERWUNDBARER CODE (ZEILEN 64, 78)
// Verwundbar
item->title; ?>" ...>
Die Payload abc" onmouseover="alert(document.domain);" x=" wird in jos_joomgallery.title gespeichert und bei jedem Seitenaufruf roh in das HTML-Attribut eingefügt. Weder auf der Speicher- noch auf der Anzeigeebene findet eine Bereinigung statt.
POST an task=userimage.save&id=3 mit der XSS-Payload in jform[title]. Die ACL-Prüfung ist erfolgreich (core.edit, nicht edit.own). Der Server antwortet mit HTTP 303 — nicht 403.created_by wird auf die Benutzer-ID des Angreifers übertragen.jos_joomgallery.title gespeichert.alt="abc" onmouseover="alert(document.domain);". XSS wird ausgelöst. Admin-Sitzung erfasst → vollständige Kompromittierung der Website.Der Admin erstellt admin_image über das JoomGallery-Backend (Joomla 5.4.7). Das Bild ist Veröffentlicht, Genehmigt und gehört Administrator

GET /index.php/component/users/login — die JSON-Antwort enthält "csrf.token":"a68c2b3a...". Das Token wird für den anschließenden Login-POST erfasst.

joomla_user_state=logged_inPOST /index.php/component/users/login mit CSRF-Token und Editor-Anmeldedaten. Antwort: HTTP 303 und Set-Cookie: joomla_user_state=logged_in. Das Session-Cookie wird erfasst.

GET /index.php?option=com_joomgallery mit Session-Cookie. Die Antwort enthält ein neues "csrf.token":"2d96934b..." für die Verwendung in der Speicheranfrage.

Der Editor sendet POST an option=com_joomgallery&task=userimage.save&id=3 mit jform[title] gesetzt auf:
abc" onmouseover="alert(document.domain);" x="
Der Server antwortet mit HTTP 303 (nicht 403), was den IDOR bestätigt. Der Location-Header zeigt die XSS-Payload in der Weiterleitungs-URL, was bestätigt, dass der Titel akzeptiert und gespeichert wurde.

Das JoomGallery-Backend zeigt, dass das Bild ID=3 nun den Besitzer Editor User hat. Das Feld created_by wurde während des nicht autorisierten Speicherns stillschweigend in der Datenbank aktualisiert.

Eine SQL-Abfrage auf jos_joomgallery bestätigt, dass die XSS-Payload gespeichert ist — " wird als rohes doppeltes Anführungszeichen gespeichert, nicht als ". Auf der Speicherebene fand keine Bereinigung statt.

Jeder Benutzer, der /index.php/component/joomgallery/gallery besucht, löst die Payload aus. Der alert()-Dialog des Browsers bestätigt die JavaScript-Ausführung im Ursprung des Opfers (document.domain).

created_by stillschweigend dem Angreifer zu und verändert den Prüfpfad dauerhaft.alt-Attribut kann das Session-Cookie des Administrators exfiltrieren, wodurch der Angreifer vollständigen Backend-Zugriff und die Kontrolle über die gesamte Joomla-Installation erhält.S:C), wodurch die Vertrauensgrenze zwischen der Sitzung des Angreifers mit niedrigen Rechten und der Sitzung des Opfers mit hohen Rechten überschritten wird.