Liên khúc CVE của GPLI version 10.0.17

I. CVE-2025-24799
Tổng quan
CVE-2025-24799 là lỗ hổng SQL Injection trước xác thực (Pre-auth SQLi) trong GLPI (phiên bản ≤ 10.0.17), nằm trong tính năng “Inventory”. Lỗi xuất phát từ việc xử lý sai kiểu dữ liệu đầu vào XML dẫn đến bypass cơ chế lọc.
Phân tích chi tiết
Hàm handleAgent($metadata) - Gốc truy vấn SQLi
$metadata['deviceid'] nhận giá trị từ client gửi đến, không kiểm tra kiểu dữ liệu đầu vào. Được truyền vào dbEscapeRecursive() với mục đích sanitize.
Hàm dbEscapeRecursive():
Hàm này được viết ra để:
Nhận vào một array các giá trị cần lọc (thường là
['field' => 'value']).Đi qua từng phần tử:
Nếu là array lồng nhau ➜ đệ quy xử lý tiếp.
Nếu là string ➜ gọi
dbEscape()để escape ký tự đặc biệt trong SQL.Nếu không phải array cũng không phải string ➜ trả về như nguyên bản.
Giá trị $value được trả về nguyên bản là giá trị Object đó. Từ đó ta cần tìm hiểu thêm cơ chế Object nếu input vào có định dạng xml để khai thác lỗ hổng ở đây.
Cơ chế object SimpleXMLElement trong PHP:
$xml = simplexml_load_string('<deviceid>abc</deviceid>');
Khi thực hiện thử in kết quả bằng đoạn code sau:
echo $xml->deviceid;
Giá trị trả về string “abc” do PHP đã tự động gọi hàm __toString() khi object được phép ép kiểu sang string.
Từ đó nếu đầu vào là một object chứ không phaie string hay array thì cơ chế bảo vệ ở hàm dbEscapeRecursive() đã bị bypass.
Sau đó giá trị \(value nguyên bản đó tiếp tục được xử lý ở hàm getFromDBByCrit(), trong quá trình xử lý giá trị \)value ở hàm này, PHP tự động gọi hàm __toString() để ép kiểu đưa Object sang dạng String, từ đó gây ra lỗ hổng trên
Khai thác thực tế
Từ phân tích trên nếu chèn payload sau thì chúng ta có thể kiểm tra lỗ hổng này
<deviceid>', IF((1=1),(select sleep(5)),1), 0, 0, 0, 0, 0, 0);#</deviceid>
Theo phân tích ở trên, server sẽ nhận giá trị “', IF((1=1),(select sleep(5)),1), 0, 0, 0, 0, 0, 0);#” để đưa vào câu truy vấn từ đó gây ra lỗi SQLi.
Kết quả:
II. CVE-2025-24801
Tổng quan
Lỗ hổng Local File Inclusion trong chức năng xuất PDF (TCPDF font handling) cho phép include file PHP tùy ý từ hệ thống. Nếu attacker có thể upload file .php vào thư mục tạm, họ có thể thực thi mã => RCE.
Phân tích
Trong TCPDF (được GLPI dùng để xuất PDF), có đoạn logic tìm file font và include() nó như sau:
Đoạn code này có 1 số lỗ hổng sau:
$family(tên font) có thể được điều khiển thông qua cấu hìnhpdffont(global config) hoặc profile người dùng.Không có kiểm tra path an toàn: không loại bỏ
.., không kiểm trarealpath, không đảm bảo file nằm trongfonts/directory.include($fontfile)sẽ thực thi mọi mã PHP trong file nếu file có extension.php.Nếu attacker upload được
shell.phpvào thư mục tạm (ví dụajax/shell.php), họ có thể setpdffontthành chuỗi../../.../ajax/shell.php→fontfiletrỏ tới shell →include()→ RCE.
Từ các vấn đề trên thực hiện tấn công qua các bước sau:
Truy cập Setup → Dropdowns sau đó chọn Extension là php để thực hiện upload
Xác định vị trí thư mục tạm của GLPI (
GLPI_TMP_DIR) bằng cách kiểm tra cấu hình trong trang/front/config.form.php.Upload file qua endpoint /ajax/shell.php.
Thiết lập giá trị cấu hình
pdffontsao cho nó trỏ tới đường dẫn tương đối dẫn tới file đã upload (../../../../../../../../ajax/shell.php).Kiểm tra và khai thác bằng cách xuất báo cáo sang PDF với path: /front/report.dynamic.php?item_type=Computer&sort%5B0%5D=1&order%5B0%5D=ASC&start=0&criteria%5B0%5D%5Bfield%5D=view&criteria%5B0%5D%5Blink%5D=contains&criteria%5B0%5D%5Bvalue%5D=&display_type=2
Kết quả khi khai thác thành công:
III. CVE-2024-27098
Tổng quan
Lỗ hổng cho phép người dùng đã xác thực (authenticated user) thực hiện yêu cầu HTTP từ phía máy chủ đến các địa chỉ do attacker chỉ định (qua SSRF) thông qua việc khởi tạo đối tượng tùy ý trong mã nguồn
Phân tích
Attacker có thể thao tác với các tham số \(_POST['itemtype'] và \)_POST['items_id'] ở filefront/itilsolution.form.php:
Khi \(_POST['itemtype'] trỏ tới lớp có __call(), và sau đó mã gọi \)track->getFromDB(...) — nếu getFromDB không tồn tại trên class đó, PHP sẽ gọi __call('getFromDB', [...]). ew $_POST['xxx']() là pattern cực kì nguy hiểm, nó cho phép PHP khởi tạo lớp từ chuỗi nếu chuỗi đó là tên lớp hợp lệ trong namespace. Nếu input không kiểm soát, attacker có thể tạo instance bất kỳ class nào đã autoloadable (kể cả class vendor như GuzzleHttp\\Client)
__call() là phương thức magic invoked khi gọi method không tồn tại. Một số class (thường các wrapper, clients) dùng __call() để thực hiện các hành động linh hoạt; Guzzle dùng __call() để giả lập các http methods (ví dụ \(client->get(\)uri) → request('GET', \(uri)). Khi gọi \)obj->getFromDB(\(uri), Guzzle sẽ nhận getFromDB là method name → vì không phải method có sẵn, __call() sẽ làm request('getfromdb', \)uri, $opts) (hoặc logic tương tự), tức là thực hiện request tới URI bạn truyền.
Từ đó attacker khởi tạo một GuzzleHttp\\Client (bằng new \(_POST[...]), rồi gọi \)track->getFromDB(\(_POST['items_id']) — vì getFromDB không tồn tại trên Guzzle client, __call() được gọi → Guzzle thực hiện HTTP request tới \)_POST['items_id'] (do attacker cung cấp) → SSRF.
Khai thác
Requests example:
POST /Projects/glpi_10.0.12/front/itilsolution.form.php HTTP/1.1
Host: 127.0.0.1:58080
Cookie: glpi_...=<AUTHENTICATION COOKIE>
Content-Type: application/x-www-form-urlencoded
Content-Length: 173
itemtype=GuzzleHttp\\Client&items_id=https://<REDACTED>.oastify.com/POC&_glpi_csrf_token=<CSRF_TOKEN>
Response excerpt
HTTP/1.1 302 Found
X-Powered-By: PHP/7.4.2
Location: https://<REDACTED>.oastify.com
Content-Length: 0
Content-Type: text/html; charset=UTF-8
IV. CVE-2024-27096
Tổng quan
SQL Injection trong cơ chế xây ORDER BY của chức năng search/list (mảng search.sort) — attacker có thể tiêm chuỗi vào tham số sắp xếp để làm thay đổi câu SQL, dẫn đến time-based hoặc error-based SQLi
Phân tích
Phân tích đoạn code sau ở Search::constructSQL()/Search::addOrderBy():
và addOrderBy() ghép chuỗi để trả về ORDER BY
Ta thấy có 2 lỗ hổng cần quan tâm:
if (\(data['search']['sort'][\)i] == $val)— dùng loose equality (==) để kiểm tra xem giá trị người dùng có nằm trong danh sách hợp lệ không.Khi chấp nhận, code sử dụng trực tiếp giá trị (hoặc giá trị derivated mapping) để ghép vào
ORDER BYmà không validate/escape kỹ.
Bản chất: == trong PHP thực hiện chuyển đổi kiểu ngầm (type juggling). Nếu một toán tử là số và toán tử kia là chuỗi bắt đầu bằng ký tự số/format số, PHP sẽ ép chuỗi sang số trước khi so sánh. Điều này sinh ra các trường hợp sau:
Chuỗi có dạng
2e0(scientific notation) sẽ được chuyển sang số2.Chuỗi bắt đầu bằng số và tiếp theo là ký tự không số có thể bị cắt/convert theo quy tắc cũ.
Ví dụ minh họa:
// giả định PHP < 8 behavior
var_dump("2e0" == 2); // true
var_dump("2e0`a" == 2); // có thể true trên một số phiên bản
Do đó kịch bản tấn công là: Attacker chèn một chuỗi đặc biệt vào sort[] sao cho khi so sánh == với $val (một giá trị hợp lệ, ví dụ '1'), PHP trả true, dù chuỗi attacker không phải giá trị đúng.
Khai thác
Truy cập vào chức năng “Ticket” và thực hiện sort
constructSQL()sẽ kiểm traif (\(sort_input == \)val)— loose check — có thể trả true do type juggling.Do true, code thêm phần tử vào
sort_fieldssử dụng nguyên giá trị user.addOrderBy()ghép cột + direction thànhORDER BY ...với chuỗi do user điều khiển — nếu attacker đưa vào payload như1, SLEEP(10) DESC-- -(ví dụ) thì khi ghép sẽ tạo thànhORDER BY ..., 1, SLEEP(10) DESC-- - ASC→ phần SLEEP được thực thi bởi DB → time-based SQLi.
Kết quả:
V. CVE-2025-25192
Tổng quan
Một lỗ hổng trong GLPI cho phép người dùng quyền thấp kích hoạt Debug Mode. Sau khi được bật, chế độ này sẽ hiển thị các SQL queries, errors, PHP objects, system configuration, and input/output data, cung cấp thông tin chi tiết về hành vi của ứng dụng và các vấn đề tiềm ẩn, ngay cả với người dùng thông thường.
Phân tích chi tiết
Lỗ hổng này trong GLPI cho phép người dùng quyền thấp kích hoạt Debug Mode bằng cách gửi reuquest POST với tham số continuer đến path /install/update.php. Điều này bypass các bước kiểm tra do lỗi logic trong soure code. Sau khi được bật, Debug Mode sẽ làm lộ thông tin nhạy cảm như internal SQL queries, giúp phân tích ứng dụng và xác định các lỗ hổng tiềm ẩn dễ dàng hơn.
POC
Trang web có chức năng update hệ thống tại URL: http://127.0.0.1:8080/install/update.php.
Tuy nhiên khi truy cập URL này trang web sẽ thông báo lỗi không cho thực thi bản cập nhật
Bằng cách review source code của GLPI tại /install/update.php, ta đã xác định được một lỗi logic cho phép bypass biện pháp bảo vệ này bằng cách gửi request POST có chứa tham số continuer hoặc from_update với giá trị tùy ý
Ta có thể nhận thấy trong source code việc bắt đầu cập nhật sẽ kích hoạt chế độ DEBUG.
Quay trở lại Burp sau đó thực hiện gửi request để tiến hành update và kích hoạt chế độ DEBUG MODE
Sau khi quá trình cập nhật hoàn tất, nếu chúng ta quay lại giao diện người dùng quyền thấp, chúng ta có thể thấy chế độ DEBUG thực sự đã được kích hoạt.
VI. CVE-2025-21626
Tổng quan
Người dùng ẩn danh, chưa được xác thực có thể truy cập endpoint status.php và lấy thông tin nhạy cảm. Thông tin này có thể bao gồm GLPI_DB, GLPI_SESSION, LDAP server, IMAP server, CAS server, mail collector, ...
Impact
Việc tiết lộ thông tin nhạy cảm này có thể dẫn đến các cuộc tấn công tiếp theo hoặc truy cập trái phép vào các hệ thống khác.
Giải pháp
Xóa tệp status.php: Thao tác này sẽ xóa hoàn toàn endpoint dễ bị tấn công. Hạn chế quyền truy cập vào status.php: Triển khai cấu hình cấp máy chủ để giới hạn người có thể truy cập endpoint này.




![[ZVE-2025-3566] Stored XSS to RCE in Manage Engine OpManager](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1753930975579%2Fb835c2ae-2b5b-425e-9210-09bb506d46c1.png&w=3840&q=75)
