SQL Injection là gì?
SQL Injection là một kỹ thuật tấn công code注入, nơi kẻ tấn công chèn các câu lệnh SQL độc hại vào các tham số đầu vào của ứng dụng web. Điều này cho phép chúng繞 qua các biên giới an toàn của ứng dụng và truy cập vào các dữ liệu nhạy cảm trong cơ sở dữ liệu, thậm chí kiểm soát toàn bộ server.
Nguyên lý của SQL Injection
Ứng dụng web thường sử dụng các câu lệnh SQL để tương tác với cơ sở dữ liệu. Nếu ứng dụng không kiểm tra và làm sạch đầu vào của người dùng một cách đầy đủ, kẻ tấn công có thể tạo ra các dữ liệu đầu vào đặc biệt. Khi được ghép vào các câu lệnh SQL gốc, chúng có thể gây ra các hành vi không mong muốn.
Ví dụ điển hình
Giả sử một truy vấn SQL cho việc xác thực đăng nhập như sau:
SELECT * FROM users WHERE username = '$username' AND password = '$password'
- Đầu vào thường规:
- username = admin
- password = 123456
Truy vấn SQL sinh ra:
SELECT * FROM users WHERE username = 'admin' AND password = '123456'
- Đầu vào độc hại:
- username = admin' --
Truy vấn SQL sinh ra:
SELECT * FROM users WHERE username = 'admin' --' AND password = ''
Chú ý: -- là ký tự注释 trong SQL, mọi nội dung sau đó sẽ bị bỏ qua. Quá trình xác thực mật khẩu cũng bị繞 qua!
Cách phát hiện lỗ hổng SQL Injection
1. Phương pháp kiểm tra ngoại lệ
Nhập các ký tự đặc biệt vào các trường đầu vào và quan sát phản ứng của ứng dụng:
- Ký tự apostrophe
' - Ký tự double quote
" - Ký tự comment
--hoặc/* - Kiểm tra logic:
' OR '1'='1'
Nếu ứng dụng trả về lỗi liên quan đến cú pháp SQL (ví dụ: "MySQL syntax error"), điều này cho thấy可能存在 SQL Injection.
2. Blind Injection dựa trên布尔
Khi ứng dụng không hiển thị thông tin lỗi rõ ràng, nhưng nội dung trang web thay đổi tùy thuộc vào đầu vào (ví dụ: thông báo đăng nhập thành công hoặc thất bại), bạn có thể sử dụng phương pháp Blind Injection để dần dần đoán dữ liệu.
Phân tích bài tập CTF: SQL Injection cơ bản
Đề bài: Basic SQL Injection
<?php
$user_name = $_POST['username'];
$pass_word = $_POST['password'];
$sql = "SELECT * FROM users WHERE username='$user_name' AND password='$pass_word'";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
echo "Đăng nhập thành công! Flag: " . $flag;
} else {
echo "Đăng nhập thất bại!";
}
?>
Tư duy giải bài
Đây là một trường hợp điển hình của trang đăng nhập có lỗ hổng SQL Injection. Chúng ta có thể lợi dụng ký tự注释 để繞 qua việc kiểm tra mật khẩu:
Dữ liệu tấn công (Payload):
- Tên người dùng:
admin' -- - Mật khẩu: Giá trị bất kỳ (ví dụ:
123)
Nguyên lý:
-- Truy vấn thực thi
SELECT * FROM users WHERE username='admin' --' AND password='123'
-- Tương đương (bỏ qua phần kiểm tra mật khẩu)
SELECT * FROM users WHERE username='admin'
Như vậy, chúng ta đã繞 qua việc kiểm tra mật khẩu và đăng nhập thành công với tư cách người dùng admin, từ đó lấy được Flag.
Phương pháp phòng vệ
- Sử dụng các câu lệnh đã chuẩn bị (Prepared Statements)
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $user_name, $pass_word);
$stmt->execute();
- Lọc và kiểm tra đầu vào
- Kiểm tra loại dữ liệu đầu vào một cách nghiêm ngặt
- Sử dụng whitelist để kiểm tra -_escape các ký tự đặc biệt
- Nguyên tắc限 quyền tối thiểu
- Tài khoản cơ sở dữ liệu phải tuân thủ nguyên tắc限 quyền tối thiểu
- Tránh sử dụng các tài khoản có quyền限 cao như root
Liên kết kiến thức
SQL Injection là một trong những lỗ hổng bảo mật quan trọng nhất trong web安全. Nó liên quan chặt chẽ đến các kiến thức sau:
- Blind Injection dựa trên布尔: Khi ứng dụng không hiển thị thông tin, sử dụng sự khác biệt trong phản ứng của trang để đoán dữ liệu
- Union Injection: Exploit Union để lấy dữ liệu từ các bảng khác
- Injection dựa trên lỗi: Lợi dụng thông tin lỗi từ cơ sở dữ liệu để truy xuất dữ liệu
- Injection dựa trên thời gian: Sử dụng các hàm chậm (ví dụ: SLEEP()) để đoán thông tin