
IDOR + Stored XSS tramite autorizzazione a livello di oggetto non corretta in JoomGallery
JoomGallery ≤ 4.3.0 — un utente con ruolo Editor dirotta qualsiasi immagine della galleria e memorizza un payload XSS, consentendo il dirottamento della sessione admin
UserimageController::save() in JoomGallery controlla checkACL('edit', ...) invece di checkACL('edit.own', ...). Un utente con ruolo Editor può inviare una POST a task=userimage.save&id=N per qualsiasi immagine, indipendentemente dalla proprietà (IDOR — CWE-639). Poiché il ruolo Editor dispone di core.edit a livello globale, il controllo di autorizzazione viene superato per ogni ID immagine del sito, incluse le immagini di proprietà degli amministratori.
Combinata con la mancanza di una chiamata $this->escape() nel template frontend delle immagini, un Editor può memorizzare un payload XSS nel titolo di qualsiasi immagine — incluse quelle di proprietà degli amministratori — causando l'esecuzione di JavaScript nel browser di ogni visitatore. Ciò consente il dirottamento completo della sessione admin e la compromissione dell'intero sito.
| COMPONENTE | VULNERABILE | TESTATO SU | CORRETTA |
|---|---|---|---|
| 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 |
Tipo: Autorizzazione a livello di oggetto non corretta / IDOR (CWE-639) combinata con Cross-Site Scripting persistente (CWE-79) Autenticazione richiesta: account Editor con privilegi bassi
File: components/com_joomgallery/src/Controller/UserimageController.php
L'azione save() esegue un controllo ACL utilizzando il permesso edit invece di edit.own. Il permesso edit è concesso globalmente a tutti gli utenti con ruolo Editor, quindi il controllo ha esito positivo per qualsiasi ID immagine, indipendentemente da chi l'ha creata.
USERIMAGECONTROLLER.PHP — CODICE VULNERABILE (RIGA 145)
// Vulnerable
if (!$this->checkACL('edit', 'image', $recordId, $parent_id, true)) { ... }
Poiché core.edit è detenuto globalmente dal gruppo Editor, la condizione restituisce false per ogni ID immagine, concedendo accesso in scrittura senza restrizioni. In caso di salvataggio riuscito, il modello aggiorna inoltre created_by con l'ID utente dell'attaccante, trasferendo silenziosamente la proprietà dell'immagine all'attaccante.
File: components/com_joomgallery/tmpl/image/default.php
Il template frontend delle immagini stampa $this->item->title senza codificarlo in HTML nel contesto dell'attributo alt. Il filtro STRING di JInput di Joomla non rimuove i caratteri di doppio apice, quindi un payload contenente " fuoriesce dall'attributo e inietta gestori di eventi arbitrari.
DEFAULT.PHP — CODICE VULNERABILE (RIGHE 64, 78)
// Vulnerable
item->title; ?>" ...>
Il payload abc" onmouseover="alert(document.domain);" x=" viene memorizzato in jos_joomgallery.title e iniettato grezzo nell'attributo HTML a ogni rendering della pagina. Non avviene alcuna sanitizzazione né a livello di memorizzazione né a livello di visualizzazione.
task=userimage.save&id=3 con il payload XSS in jform[title]. Il controllo ACL viene superato (core.edit, non edit.own). Il server risponde con HTTP 303 — non 403.created_by viene trasferito all'ID utente dell'attaccante.jos_joomgallery.title.alt="abc" onmouseover="alert(document.domain);". L'XSS scatta. La sessione admin viene catturata → compromissione completa del sito.L'admin crea admin_image tramite il backend di JoomGallery (Joomla 5.4.7). L'immagine è Pubblicata, Approvata e di proprietà di Amministratore

GET /index.php/component/users/login — la risposta JSON contiene "csrf.token":"a68c2b3a...". Token catturato per la successiva POST di login.

joomla_user_state=logged_inPOST /index.php/component/users/login con token CSRF e credenziali dell'Editor. Risposta: HTTP 303 e Set-Cookie: joomla_user_state=logged_in. Cookie di sessione catturato.

GET /index.php?option=com_joomgallery con il cookie di sessione. La risposta contiene un nuovo "csrf.token":"2d96934b..." da utilizzare nella richiesta di salvataggio.

L'Editor invia una POST a option=com_joomgallery&task=userimage.save&id=3 con jform[title] impostato su:
abc" onmouseover="alert(document.domain);" x="
Il server risponde con HTTP 303 (non 403), confermando l'IDOR. L'header Location mostra il payload XSS nell'URL di reindirizzamento, confermando che il titolo è stato accettato e salvato.

Il backend di JoomGallery mostra che l'immagine ID=3 ora ha Proprietario: Editor User. Il campo created_by è stato aggiornato silenziosamente nel database durante il salvataggio non autorizzato.

La query SQL su jos_joomgallery conferma che il payload XSS è memorizzato — " è salvato come doppio apice grezzo, non come ". Nessuna sanitizzazione è avvenuta a livello di memorizzazione.

Qualsiasi utente che visita /index.php/component/joomgallery/gallery attiva il payload. La finestra di dialogo alert() del browser conferma l'esecuzione di JavaScript nell'origine della vittima (document.domain).

created_by all'attaccante, alterando in modo permanente la traccia di audit.alt può esfiltrare il cookie di sessione dell'amministratore, concedendo all'attaccante accesso completo al backend e il controllo dell'intera installazione Joomla.S:C), attraversando il confine di fiducia tra la sessione a bassi privilegi dell'attaccante e quella ad alti privilegi della vittima.