
Joomla 6.1.3 - Alta - Remota - ACL - POST /api/v1/content/articles ignora l'ACL per categoria
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · joomla-articles-catid
Classe: Privilegio residuo Raggiungibilità: Remota
Joomla CMS 6.1.3 (0f2d4de) - Open Source Matters
Il metodo amministratore ArticleController::allowAdd verifica com_content.category.{catid}. api/components/com_content/src/Controller/ArticlesController.php non ha allowAdd. ApiController::add() chiama quindi allowAdd() senza dati, per cui il catid JSON non entra mai nel controllo. Il allowAdd di base è vero se l'utente può creare in qualsiasi categoria.
Un utente API di classe Manager, a cui sono concessi core.login.api e la creazione su una categoria, può effettuare il POST di un articolo in una categoria in cui è negato nell'interfaccia utente.
| ID | nessuna CVE al momento |
| Classe | Privilegio residuo / bypass di autorizzazione |
| Raggiungibilità | Remota (token API con core.login.api) |
| CWE | CWE-863 |
| CVSS | Medio: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N |
| Prodotto | Joomla CMS |
| Affetto | 6.1.3 (0f2d4de4729eb951e0878fec98c7990da07915b2), POST /api/index.php/v1/content/articles |
| Auth | Token API per Manager (gruppo 6) con core.login.api, com_content core.manage e core.create su una sola categoria. Nessun Super User. Il valore predefinito di core.login.api è solo Super User. |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
Usare un token API non-Super-User che può creare in una categoria per pubblicare in categorie da cui è bandito. Non diventano Super User da questo residuo. Si tratta di pubblicazione non autorizzata, non di takeover del sito e non di lettura di articoli nascosti.
| Privilegio | Metodo / percorso | Tipo | Provato in lab o dedotto |
|---|---|---|---|
| Creare un articolo in una categoria in cui è negato | POST /api/index.php/v1/content/articles JSON catid di B | integrità | Provato in lab. HTTP 200, #__content id=1, catid=9 (Press), titolo poc-art-JOOMLA-ARTICLES-CATID-WITNESS |
| Inserire una copia pubblicata in Official notices / Press mentre sono consentite solo Bozze | Stesso POST, state=1 | integrità | Provata la creazione in Press negata. Dedotto per qualsiasi altra risorsa di categoria con core.create negato |
| Modificare un articolo esistente tramite l'API | PATCH /api/index.php/v1/content/articles/{id} | n/a | Dedotto chiuso per questo Manager. Il allowEdit di base richiede core.edit del componente; le regole com_content del lab danno core.edit ad Author (4), non a Manager (6). Il lab non ha eseguito PATCH |
| Eliminare un articolo tramite l'API | DELETE /api/index.php/v1/content/articles/{id} | n/a | Dedotto chiuso. Il allowDelete di base richiede core.delete del componente. Il lab non ha eseguito DELETE |
| Salvare un articolo nella categoria consentita A dall'amministratore | POST ... task=article.save jform[catid]=A | previsto | Provato in lab aperto come previsto. HTTP 200, non negato |
| Salvare un articolo nella categoria negata B dall'amministratore | Stessa task, jform[catid]=B | n/a | Provato in lab chiuso. HTTP 200 con "not permitted" / create-not-permitted (allowAdd dell'interfaccia su com_content.category.B) |
Colpire l'API con un Manager standard (senza core.login.api) | Bearer token / X-Joomla-Token | n/a | Dedotto chiuso. Il valore predefinito di core.login.api è solo Super User (gruppo 8). Questo lab lo concede prima al gruppo 6 |
| Stessa lacuna su contacts / banners / newsfeeds | POST /api/index.php/v1/contacts (e affini) con catid esterno | integrità | Dedotto. Anche quei controller API mancano di allowAdd. Il lab non li ha esercitati |
| RCE da Super User / installer | n/a | n/a | Chiuso. Il Manager resta Manager |
Ho fissato la versione 6.1.3 dopo l'ondata JSST di 2026-07/08. L'API Groups richiede già core.admin. Il webservice Media richiede già core.edit sull'override. L'API Articles cade ancora attraverso ApiController e considera "creare in qualsiasi categoria" sufficiente per ogni catid.
public function add()
{
if (!$this->allowAdd()) {
throw new NotAllowed('JLIB_APPLICATION_ERROR_CREATE_RECORD_NOT_PERMITTED', 403);
}
$recordId = $this->save();
$this->displayItem($recordId);
}
Controllo di base:
protected function allowAdd($data = [])
{
$user = $this->app->getIdentity();
if (!$user->authorise('core.manage', $this->option)) {
return false;
}
return $user->authorise('core.create', $this->option)
|| \count($user->getAuthorisedCategories($this->option, 'core.create'));
}
L'interfaccia amministratore si basa già su catid:
protected function allowAdd($data = [])
{
$categoryId = ArrayHelper::getValue(
$data,
'catid',
$this->input->getInt('filter_category_id'),
'int'
);
if ($categoryId) {
return $this->app->getIdentity()->authorise(
'core.create',
'com_content.category.' . $categoryId
);
}
return parent::allowAdd();
}
Vicoli ciechi già registrati: leggere l'HTTP 200 dell'interfaccia come autorizzazione (il diniego di B è il corpo "not permitted"); trattare core.create del componente come la falla (il Manager del lab non ne ha; l'autorizzazione su una categoria è sufficiente per il conteggio di base di getAuthorisedCategories); un Manager standard senza core.login.api. Teatro: una reverse shell. L'oracolo è API 200 in Press più autorizzazione dell'interfaccia su Bozze più diniego dell'interfaccia su Press.
Residui dello stesso pin: levels API, menu items API, media override.
python3 joomla-articles-catid-Abraxas-Labs.py
oppure
cd lab
./run.sh
Target solo http://127.0.0.1:19550. Immagine joomla:6.1.3-php8.3-apache più mariadb:11.4.
SUCCESS joomla-articles-catid api-http=200 article-id=1 catid=9 cat-a=8 cat-b=9 ui-a=200 ui-b=200 JOOMLA-ARTICLES-CATID-WITNESS
article-id è il successivo autoincrement di #__content (1 su un'installazione 6.1.3 pulita). ui-a / ui-b sono HTTP 200; il diniego di B è il corpo "not permitted" dell'interfaccia, non uno stato 403.
Sovrascrivere allowAdd (e allowEdit) su api/components/com_content/src/Controller/ArticlesController.php allo stesso modo dell'amministratore ArticleController: verificare core.create su com_content.category.{catid}. Passare il JSON della richiesta a ApiController::add() in modo che catid raggiunga effettivamente quel controllo. Applicare lo stesso schema a contacts, banners e newsfeeds se quei controller restano sul allowAdd predefinito.