
Joomla 6.1.3 - Alto - Remoto - Sobrescrita - gerenciador de mídia sobrescreve resíduos
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · joomla-media-override
Classe: Privilégio remanescente Alcance: Remoto
Joomla CMS 6.1.3 (0f2d4de) - Open Source Matters
CVE-2026-48947 ensinou a API de webservice de mídia a exigir core.edit quando override está definido. A API JSON do site ainda não. O Author padrão tem core.create em com_media e nenhum core.edit. O dispatcher do site considera core.create suficiente e carrega o ApiController do administrador. postFiles() então passa override diretamente para createFile().
Um Author padrão pode substituir um arquivo que já está no disco. Os visitantes continuam acessando a mesma URL pública e recebem os novos bytes.
| ID | ainda sem CVE |
| Classe | Privilégio remanescente / integridade |
| Alcance | Remoto (Author padrão, sem token de API) |
| CWE | CWE-863, CWE-639 |
| CVSS | Médio: 6.5 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N |
| Produto | Joomla CMS |
| Afetado | 6.1.3 (0f2d4de4729eb951e0878fec98c7990da07915b2), API JSON com_media do site |
| Autenticação | Author padrão (grupo 3). Sem token de API. |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1 |
Fazer login como um Author padrão e substituir um arquivo que já está no site. Isto é desfiguração / bait-and-switch de mídia armazenada, não uma tomada de controle do site. A denylist de extensões permanece inalterada, portanto isto não é um upload de .php.
| Privilégio | Método / caminho | Tipo | Comprovado em lab ou inferido |
|---|---|---|---|
| Sobrescrever um arquivo de mídia existente (logo, imagem de artigo) | Site POST /index.php?option=com_media&task=api.files&format=json&path=local-images:/ com JSON override: true | integridade | Comprovado em lab. HTTP 200, SHA do disco alterado, GET público /images/joomla_black.png serviu o novo PNG que carrega JOOMLA-MEDIA-OVERRIDE-WITNESS |
| Desfigurar tudo que ainda aponta para essa URL | Mesmo caminho público, sem cache-bust | integridade | Comprovado em lab que os bytes públicos mudaram. Inferido para outros adaptadores sob images/ |
| Criar um novo arquivo permitido | Mesmo POST sem override | pretendido | Author tem core.create em com_media |
| Editar via PUT | PUT na mesma task, caminho inclui o nome do arquivo | n/a | Comprovado em lab fechado. HTTP 403. putFiles() já exige core.edit |
| Criar quando o nome existe, sem override | POST override: false (padrão) | n/a | Comprovado em lab fechado. HTTP 409, SHA original inalterado até o POST com override |
Enviar .php ou outros tipos negados | denylist de createFile / isMediaFile | n/a | Inferido fechado. Este lab envia apenas um PNG |
| Chamar a API de webservice de mídia com override | /api/index.php/v1/media/files | n/a | Inferido fechado. MediaController::allowAdd verifica core.edit quando override está definido (CVE-2026-48947) |
| Super User / RCE | n/a | n/a | Fechado. Author permanece Author |
Fixe em 6.1.3 após a onda JSST de 2026-07/08. A API de Groups já exige core.admin. O webservice de mídia já exige core.edit no override. O controller interno ainda não.
O Author padrão tem core.create em com_media e nada em core.edit:
{"core.admin":{"7":1},"core.manage":{"6":1},"core.create":{"3":1},"core.delete":{"5":1}}
O Dispatcher do site deixa core.create passar e carrega o ApiController do administrador. postFiles() então:
if (!$this->app->getIdentity()->authorise('core.create', 'com_media')) {
throw new \Exception(Text::_('JLIB_APPLICATION_ERROR_CREATE_RECORD_NOT_PERMITTED'), 403);
}
$override = $content->get('override', false);
if ($mediaContent) {
$name = $this->getModel()->createFile($adapter, $name, $path, $mediaContent, $override);
Webservice corrigido (api/.../MediaController.php):
if ($this->input->json->get('override', false)) {
return $user->authorise('core.edit', 'com_media');
}
Caminhos errados já registrados: tratar PUT como o remanescente (PUT já é 403); tratar o caminho do webservice como ainda aberto (CVE-2026-48947 o fechou); ler 409 sem override como um erro (esse é o caminho pretendido de criar-se-ausente). Teatro: um reverse shell. O oráculo é POST override 200 mais PUT 403 mais GET público do PNG testemunha.
Outros remanescentes do mesmo pin: levels API, menu items API, articles catid.
python3 joomla-media-override-Abraxas-Labs.py
ou
cd lab
./run.sh
Alvo apenas http://127.0.0.1:19540. Imagem joomla:6.1.3-php8.3-apache mais mariadb:11.4.
SUCCESS joomla-media-override post-http=200 override=yes bytes-changed=yes put-http=403 no-edit=yes conflict-http=409 JOOMLA-MEDIA-OVERRIDE-WITNESS
Mesma verificação override -> core.edit que MediaController::allowAdd dentro de ApiController::postFiles() antes de createFile(). Manter PUT em core.edit.
0f2d4de4729eb951e0878fec98c7990da07915b2)ApiController.php postFilesGNU Affero GPL v3.0. Veja LICENSE. Apenas lab em loopback. Sem garantia.