Lỗ hổng SQL Truncation Attack là một lỗ hổng trong cơ sở dữ liệu hoặc ứng dụng khi xử lý dữ liệu đầu vào, dẫn đến việc hệ thống thực hiện việc cắt xén dữ liệu không mong muốn. Từ đó tạo điều kiện cho kẻ tấn công thực hiện các hành động gây hại.
Mục lục
SQL Truncation Attack
Lỗ hổng này xuất phát từ việc không kiểm soát chặt chẽ độ dài của dữ liệu nhập vào, cho phép dữ liệu dài hơn giới hạn của trường dữ liệu được gửi đến cơ sở dữ liệu.
Khi thực thi lệnh SELECT hoặc INSERT, cơ sở dữ liệu sẽ kiểm tra và cắt bớt phần dữ liệu dư thừa. Việc này để đảm bảo dữ liệu nhập vào sẽ phù hợp hợp với giới hạn lưu trữ dữ liệu được thiết lập khi tạo bảng.
Lỗ hổng SQL Truncation Attack lần đầu tiên được biết đến trong trong CVE-2008-4106, liên quan đến WordPress CMS.
Mức độ ảnh hưởng SQL Truncation Attack
Khi dữ liệu này được cơ sở dữ liệu xử lý, phần vượt quá giới hạn sẽ bị cắt bỏ, có thể gây ra các vấn đề trong tam giác bảo mật CIA:
- Tính Toàn Vẹn: Nếu phần dữ liệu bị cắt bao gồm các ký tự hoặc thông tin quan trọng, việc cắt bỏ chúng có thể làm thay đổi ý nghĩa hoặc mục đích của dữ liệu đó, dẫn đến việc thay đổi hoặc mất mát dữ liệu.
- Tính Bảo Mật: Kẻ tấn công có thể cố gắng sử dụng lỗ hổng này để ghi đè dữ liệu nhạy cảm, như thông tin đăng nhập hoặc quyền truy cập, bằng cách chèn dữ liệu mà khi bị cắt xén sẽ tạo ra một kết quả mong muốn cho kẻ tấn công.
Root Cause SQL Truncation Attack
Như ví dụ dưới đây, trường username chỉ cho phép lưu trữ 20 ký tự. Hệ thống sẽ tự thu gọn vùng nhớ để tiết kiệm không gian lưu trữ nếu dữ liệu của người dùng nhập vào ít hơn.
CREATE TABLE IF NOT EXISTS `users` (
user_id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
password VARCHAR(40) NOT NULL,
PRIMARY KEY (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `users` (username, password) VALUES ('admin', 'tZYSeSfUDHPhGXn');
Nếu người dùng nhập vào toàn khoảng trắng ở phía cuối, hệ thống cũng tự động loại bỏ chúng vì nó không quan trọng
Nếu kẻ tấn công cố gắng nhập một chuỗi 21 ký tự, theo lý thuyết 1 ký tự cuối cùng ở phía sau sẽ bị loại bỏ
MariaDB [chh]> INSERT INTO `users` (username, password) VALUES ('admin 1', 'Yulm5zpKGKdGqlr');
ERROR 1406 (22001): Data too long for column ‘username’ at row 1
Thay vì cho người dùng bất chấp INSERT dữ liệu, các bản cài đặt MySQL mới nhất đã thiết lập chức năng Strict SQL Mode. Nếu người dùng cố tình INSERT một bản ghi có độ dài lớn hơn chiều dài lưu trữ của một cột, nó sẽ báo lỗi như phía trên và không thực hiện việc INSERT dữ liệu.
Để mô phỏng lại lỗ hổng này, bạn phải thực hiện tắt chức năng Strict SQL Mode trong MySQL bằng lệnh thiết lập SQL Mode dưới đây.
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
Sau khi tắt Strict SQL Mode, chúng ta thử nghiệm lại với câu lệnh INSERT một username có độ dài 21 ký tự:
- Chuỗi “admin” 5 ký tự
- Ghép với 15 ký tự khoảng trắng
- Để tránh bị MySQL loại bỏ các khoảng trắng phía sau dữ liệu, ta thêm 1 ký tự bất kỳ.
MariaDB [chh]> INSERT INTO `users` (username, password) VALUES ('admin 1', 'Yulm5zpKGKdGqlr');
Query OK, 1 row affected (0.01 sec)
MariaDB [chh]> select * from users;
+---------+----------------------+-----------------+
| user_id | username | password |
+---------+----------------------+-----------------+
| 1 | admin | Yulm5zpKGKdGqlr |
| 2 | admin | 123456 |
+---------+----------------------+-----------------+
2 rows in set (0.001 sec)
Dữ liệu được INSERT thành công, nếu chỉ quan sát bằng mắt thường, ta sẽ thấy 2 tài khoản “admin” được lưu trữ trong bảng users. Khi thực hiện đếm độ dài bằng hàm length(), ta sẽ thấy tài khoản admin đầu tiên có 5 ký tự cái chỉ có 5 ký tự, tài khoản còn lại 20 ký tự (5 ký tự nhìn thấy, 15 ký tự khoảng trắng)
MariaDB [chh]> select length(username) from users where user_id=1;
+------------------+
| length(username) |
+------------------+
| 5 |
+------------------+
1 row in set (0.001 sec)
MariaDB [chh]> select length(username) from users where user_id=2;
+------------------+
| length(username) |
+------------------+
| 20 |
+------------------+
1 row in set (0.001 sec)
MySQL loose comparison
Với MySQL, toán tử = mặc định khi thực hiện phép so sánh sẽ rất lỏng lẻo (Loose comparison). Với Postgresql thì ngược lại, mặc định các so sánh đều chặt chẽ. Bạn có thể tham khảo các kết quả so sánh dưới đây của MySQL, nó đều trả về kết quả TRUE
SELECT '0' = 0;
SELECT '0.0' = 0;
SELECT '0 ' = '0';
Trong MySQL, khi thực hiện truy vấn với các lệnh điều kiện, so sánh. Các khoảng trắng phía sau phần dữ liệu sẽ bị loại bỏ. Nên khi bạn thực hiện câu truy vấn dưới đây, bạn đã vô tình đăng nhập thành công vào hệ thống với tài khoản “admin” fake.
MariaDB [chh]> select * from users where username='admin' AND password='123456';
+---------+----------------------+----------+
| user_id | username | password |
+---------+----------------------+----------+
| 2 | admin | 123456 |
+---------+----------------------+----------+
1 row in set (0.001 sec)
Nói một cách khác, kẻ tấn công có thể lợi dụng lỗ hổng này để đăng ký sau đó truy cập vào bất kỳ tài khoản nào trong hệ thống. SQL Truncation là một lỗ hổng thú vị trong nhóm Misconfiguration OWASP (thiết lập cấu hình sai).
Thực hành SQL Truncation Attack
Hãy tìm cách đăng nhập vào tài khoản “admin” của thử thách SQL Truncation Attack.
Ngăn chặn lỗ hổng SQL Injection Attack
- Kiểm soát đầu vào: Thực hiện các kiểm tra đầu vào mạnh mẽ để đảm bảo rằng dữ liệu nhập không vượt quá giới hạn định sẵn của trường dữ liệu.
- Sử dụng các cơ chế xác nhận và báo lỗi: Hệ thống nên xác nhận dữ liệu đầu vào và thông báo cho người dùng nếu có dữ liệu không hợp lệ hoặc quá dài.
- Cấu hình cơ sở dữ liệu: Đảm bảo rằng cơ sở dữ liệu và các ứng dụng liên quan được cấu hình để hạn chế hoặc ngăn chặn hành vi cắt xén không mong muốn.
- Cập nhật và bảo mật: Luôn giữ cho hệ thống cơ sở dữ liệu và ứng dụng của bạn được cập nhật với các bản vá bảo mật mới nhất.
What do you think?
It is nice to know your opinion. Leave a comment.