Phân tích một số lỗ hổng nghiêm trọng trên sản phẩm GLPI (P1)
Cũng sau một thời gian khá dài kể từ bài viết cuối cùng của mình. Loay hoay với những dự định, kế hoạch của bản thân, nên mình chưa có thời gian viết bài chia sẻ. Hôm nay mình quay lại với bài phân tích một số lỗ hổng trên sản phẩm GLPI.
Nếu các bạn thắc mắc GLPI là gì thì ngay dưới mình sẽ giới thiệu cho các bạn biết. Nói thật ngay từ đầu mình cũng chẳng biết GLPI là thằng nào. Vào một ngày đẹp trời thì trên telegram nhảy thông báo về một lỗ hổng RCE được đánh mã CVE-2022-35914 và tên sản phẩm thì lạ hoắc. Điều đó làm mình tò mò và quyết định phân tích lỗ hổng này.
Khi xem xét CVE này, nhận thấy phiên bản bị lỗi là 10.0.2. Mình đi đến repo của sản phẩm trên github và nhận thấy phiên bản 10.0.2 còn một lỗ hổng critical nữa là CVE-2022-35947 liên quan đến bypass Authentication thông qua SQL injection. Do đó trong 2 phần của bài viết mình sẽ phân tích lần lượt CVE-2022-35914 và CVE-2022-35947
Giới thiệu về GLPI
GLPI là một phần mềm quản lý tài sản và yêu cầu hỗ trợ mã nguồn mở được phát triển bởi French IT service company Teclib'. GLPI viết tắt của "Gestionnaire Libre de Parc Informatique", có nghĩa là "Phần mềm quản lý tài sản miễn phí cho các thiết bị máy tính". Nó cung cấp một hệ thống quản lý tài sản IT cho các tổ chức và công ty, bao gồm quản lý hệ thống, thiết bị, phần mềm, người dùng và yêu cầu hỗ trợ. GLPI cũng cho phép định kỳ bảo trì và theo dõi tài sản để giúp quản lý tài nguyên IT hiệu quả hơn.
Setup môi trường
Cài đặt môi trường GLPI khá đơn giản khi bạn chỉ cần download source code từ github https://github.com/glpi-project/glpi/releases/download/10.0.2/glpi-10.0.2.tgz. Sau đó giải nén và đưa lên server. Các bước cài đặt mình thấy khá tương tự khi bạn cài đặt Wordpress. Nếu các bạn thấy mất thời gian thì có thể sử dụng docker-compose với file docker-compse.yml như sau:
version: "3.8"
services:
#MariaDB Container
mariadb:
image: mariadb:10.7
container_name: mariadb
hostname: mariadb
environment:
- MARIADB_ROOT_PASSWORD=password
- MARIADB_DATABASE=glpidb
- MARIADB_USER=glpi_user
- MARIADB_PASSWORD=glpi
#GLPI Container
glpi:
image: diouxx/glpi
container_name : glpi
hostname: glpi
environment:
- VERSION_GLPI=10.0.2
ports:
- "8001:80"
Phân tích CVE-2022-35914
Khi đọc mô tả về CVE này mình nhận ra nó không nằm trong sản phẩm GLPI mà lại nằm trong thư viện bên thứ 3 là HtmLawed < v1.2.9. Do có thể truy cập trực tiếp vào đường dẫn /vendor/htmlawed/htmlawed/htmLawedTest.php
Giới thiệu về HtmLawed
HtmLawed là một thư viện PHP mã nguồn mở được sử dụng để loại bỏ các thẻ HTML không an toàn và các đoạn mã độc hại từ đầu vào của người dùng trước khi xử lý trên server. Thư viện này có thể được tích hợp vào các ứng dụng web để bảo vệ chúng khỏi các cuộc tấn công liên quan đến bảo mật web. HtmLawed hỗ trợ các tính năng chính như lọc các thẻ HTML không an toàn, loại bỏ các đoạn mã độc hại và cho phép sử dụng các thẻ và thuộc tính HTML an toàn. HtmLawed được thiết kế để đảm bảo tính linh hoạt và dễ dàng tùy chỉnh để phù hợp với các yêu cầu cụ thể của ứng dụng web. Thư viện này là một giải pháp đáng tin cậy để giảm thiểu các lỗ hổng bảo mật trong các ứng dụng web.
Lỗ hổng RCE
CVE-2022-35914 liên quan đến việc xử lý dữ liệu POST được gửi đến server và sử dụng htmLawed. Tuy nhiên, có một lỗ hổng bảo mật trong đoạn code này.
htmLawedTest.php dòng 612
<?php
if($do){
$cfg = array();
foreach($_POST as $k=>$v){
if($k[0] == 'h' && $v != 'nil'){
$cfg[substr($k, 1)] = $v;
}
}
Ở đoạn code này, một mảng rỗng $cfg
được tạo ra, và sau đó, vòng for sẽ lặp qua tất cả các giá trị trong mảng $_POST
. Nếu giá trị của một khóa bắt đầu bằng kí tự h
và không phải là nil
, giá trị đó được đưa vào mảng $cfg
với khóa được cắt bỏ ký tự h
đầu tiên. Ví dụ, nếu $_POST['hhook']
được đặt thành exec
, thì sau đoạn mã này, $cfg['hook'] = 'exec'
.
Sau đó, tại dòng 643, hàm htmLawed
được gọi với các tham số $_POST ['text']
, $cfg
và $_POST ['spec']
.
$out = htmLawed($_POST['text'], $cfg, $_POST['spec']);
nhảy vào hàm htmLawed
tại dòng 11 file htmLawed.php
function htmLawed($t, $C=1, $S=array()){
$C = is_array($C) ? $C : array();
if(!empty($C['valid_xhtml'])){
$C['elements'] = empty($C['elements']) ? '*-acronym-big-center-dir-font-isindex-s-strike-tt' : $C['elements'];
$C['make_tag_strict'] = isset($C['make_tag_strict']) ? $C['make_tag_strict'] : 2;
$C['xml:lang'] = isset($C['xml:lang']) ? $C['xml:lang'] : 2;
}
.........
$C
là $cfg
, $t
là $_POST['text']
Tại dòng 70 trong file htmLawed.php
, giá trị của mảng $C
được kiểm tra xem có chứa một hàm hook được chỉ định không. Nếu có và hàm đó tồn tại, giá trị của $C['hook']
được đặt là hàm đó, nếu không thì $C['hook']
được đặt thành 0.
$C['hook'] = (!empty($C['hook']) && function_exists($C['hook'])) ? $C['hook'] : 0;
Cuối cùng, tại dòng 99, nếu giá trị của $C['hook'] khác 0
, hàm hook được gọi với các tham số $t, $C và $S
.
if($C['hook']){$t = $C['hook']($t, $C, $S);}
Lỗ hổng bảo mật trong đoạn mã này là nếu kẻ tấn công có thể gửi giá trị POST với khóa hhook
được đặt thành hàm độc hại, chẳng hạn như exec
. Sau đó, khi đoạn code tại dòng 99 được thực thi, hàm độc hại đó sẽ được gọi mà không cần xác thực, cho phép kẻ tấn công thực hiện RCE trên server.
Để dễ hiểu, nếu ta truyền tham số hhook=exec
và tham số text=id
thì câu lệnh sẽ thực thi là exec(id)
POC
Chẳng hiểu sao khi phân tích lỗ hổng RCE này mình có cảm giác nó như một backdoor vậy, vì đơn giản mọi thứ xảy ra trong logic code quá trùng hợp. Đó là suy nghĩ cá nhân của mình thôi. Bài viết sau mình sẽ phân tích CVE-2022-35947 mà theo mình nghĩ là sẽ hay hơn CVE-2022-35914 khá nhiều. Cảm ơn các bạn đã theo dõi và đọc bài viết.
All rights reserved