SQL注入漏洞之背景介紹
SQL 注入 (SQL Injection, SQLi) 攻擊在網頁應用服務當中是很主要的漏洞之一,普遍到被 OWASP 這個組織蒐錄在 OWASP Top 10 應用服務安全清單裡,其中在 2025 年版本清單中名列第五1
一般來說,SQLi 漏洞能讓攻擊者利用 SQL 語法干涉目標網頁應用服務跟資料庫之間的操作,意思是攻擊者有辦法利用該漏洞擴充原本服務提供的資料庫操作指令,使其存取原本設定不可對外存取的資料庫表單
SQL背景
在探討如何達成之前,我們先來了解何謂 SQL 以及資料庫的運作樣態,目前最常見到的 SQL,就是結構式查詢語法 (Structured Query Language, SQL) 被設計出來跟關聯式資料庫裡的資料進行管理跟互動操作
SQL 語言可以用來查詢、插入資料、變更甚至刪除資料等等,在某些情況下,甚至還可以執行作業系統指令,讀者可以想像,SQL 可以做到這麼多與管理員權限相關的操作,勢必會讓所有需要資料庫的應用服務面臨巨大的安全風險
近代網頁應用服務設計上都以使用者為本位,基本上你我接觸到的網頁都是前端所刻出來的,通常都會包含著許多不同的運作區塊,像是 HTML 本體、CSS 以及 JavaScript 是各位可以在前端摸到的
而當我們在前端互動完之後,就會將輸入的資料送進後端的應用服務層,目前常見的後端都有一些知名的架構可以用,像是 PHP、Java 以及 Python 等都是很多人在使用的,接著後端伺服器會處理收到的資料,像是根據拿到的使用者帳號跟密碼做資料庫裡的比對
SQL 的語法跟功能都植基在關聯式資料庫上,諸如針對 MySQL、Microsoft SQL 伺服器、PostgreSQL 以及 Oracle 等各家不同的資料庫進行實作,讓我們來看一下每家不同的特色
以最簡單最常見的 MySQL 為例,我們可以來搜尋一下使用者表單並且取得特定的使用者內容,利用 “SELECT” 這個描述來告訴資料庫我們想要搜尋整個紀錄,並且透過 “FROM” 這個關鍵字找到庫裡特定的表單,我們現在要找的是 “users” 這個表單,最後我們要在這張表單裡只拿出 “leon” 這個使用者當初填的所有資訊,整個語法構成就會如下
SELECT * FROM users WHERE user_name='leon'
為了自動處理使用者的功能,網頁應用服務經常會把 SQL 搜尋語法嵌入進網頁原始碼中,我們舉個後端 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);
?>
特別要注意的是這段 SQL
$sql_query = "SELECT * FROM users WHERE user_name= '$uname' AND password='$passwd'";
這個半編譯好的 SQL 搜尋語法想要根據使用者提供的帳號名稱跟密碼進行搜尋,而在 PHP 裡先用 $uname 跟 $passwd 變數來儲存,再把這段搜尋字串存在 sql_query 變數裡,根據 PHP 相對應跟資料庫互動的套件,例如這邊是用 “mysqli_query” 這個功能呼叫資料庫,執行完搜尋後的結果放進 $result 變數裡
話說我們在這裡看到的 “mysqli_query” 是 PHP 模組套件進行優化改良 (improved) 的版本,因為他們目前捨棄了舊版 “mysql_query” 的功能了,所以請讀者不要誤會這是不是跟注入漏洞 (Injection) 有關係,兩者先分清楚一下
至目前為止,介紹給各位讀者基本後端 PHP 跟資料庫是如何做互動了,照我們方才看到的這段 SQL 請求,可以注意到從前端接收到 “user_name” 跟 “password” 的 POST 請求後,伺服器是直接放進 “sql_query” 裡而沒有做任何檢查
這意味著,攻擊者可以資料庫執行之前修改 SQL 描述來達成自己的目的,像是惡意人士可以把一些SQL語法放進 “user” 或 “password” 變數要接受的內容來嘗試破壞原本預期的語法邏輯
讓我們回想剛剛的情況,當我們在 “user” 裡輸入 “leon” 時是想要搜尋這個使用者名稱並得到回傳的資料,為了回應這項請求,今天資料庫幫我們處理的是 “SELECT * FROM users WHERE user_name=leon” 這段
換言之,如果我們在使用者名稱輸入欄位打上 “leon ’+!@#$“,則 SQL 資料庫就是幫我們處理 “SELECT * FROM users WHERE user_name=leon ’+!@#$”
則如我們剛才看到的,資料庫或伺服器並沒有阻擋特殊的字元,這也正是造成漏洞的原因,但在那之前,針對資料庫我們需要先進行一些解釋
資料庫型態及特徵
當我們對網頁應用服務進行滲透測試時,無法確保自己對於目標背後的資料庫有足夠的認識,所以需要先準備跟一些 SQL 資料庫變體如何互動的概念
基本上各家資料庫之間差異在於語法、函式庫名稱以及功能,想要跟讀者介紹的是兩個最常見的資料庫,MySQL 以及微軟 SQL Server(MSSQL)
MySQL
MySQL 是最常被部署考量的資料庫,另外同樣的概念可以套用在 MariaDB 上,因為這是在 Linux 上常見 MySQL 的開源版本,在我們的實驗中,會連接 Local MySQL 資料庫裡進行操作
首先使用 “mysql” 指令我們可以直接連接 SQL 介面裡,預設 “root” 作為使用者名稱跟密碼,以及預設的 3306 port
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)]>
在進入 MySQL 介面之後,我們可以用 “version()” 函式來顯示目前 SQL 資料庫的版本
MySQL [(none)]> select version();
+-----------+
| version() |
+-----------+
| 8.0.21 |
+-----------+
1 row in set (0.107 sec)
我們同樣可以驗證資料庫裡的使用者是不是正確的,利用 “system_user()” 這項函式會回傳給我們目前登入的使用者以及連接 IP 資訊
MySQL [(none)]> select system_user();
+--------------------+
| system_user() |
+--------------------+
| root@192.168.20.50 |
+--------------------+
1 row in set (0.104 sec)
這樣可以確保登入時沒有其他可疑的使用者存在,並且也確保自己登入的狀態是否正確,不過讀者不要誤會,這個 “root” 使用者是資料庫系統內的管理權限使用者,並非系統層級的管理員權限帳號
接著我們可以檢查資料庫內目前所有的集合,利用 “show” 指令針對整個 database 可以看到目前安裝的 DB
MySQL [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.107 sec)
我們來嘗試指定一組之前插入進去的帳號,看看要如何顯示該帳號的密碼,在 “mysql” 資料庫裡我們可以利用 “SELECT” 描述來過濾表單裡的內容,其中我們指定只需要 “user” 跟 “authentication_string” 這兩個關鍵字,再下一層我們就可以過濾的更精確,針對 “WHERE” 來指定某個使用者
MySQL [mysql]> SELECT user, authentication_string FROM mysql.user WHERE user = hshuang
+---------+----------------------------------------------------------------------- +
| user | authentication_string |
+---------+------------------------------------------------------------------------+
| hshuang | $A$005$?qvorPp8#lTKH1j54xuw4C5VsXe5IAa1cFUYdQMiBxQVEzZG9XWd/e6 |
+---------+------------------------------------------------------------------------+
1 row in set (0.106 sec)
MySQL 為了提升安全性,在儲存使用者的密碼通常會放在 authentication_string 欄位,並且用 SHA-256 暫存演算法來壓縮,混淆明文資訊改用密文形式替代
上述就是我們針對 MySQL 的介紹,接著我們介紹微軟 SQL(MSSQL)
微軟SQL (Microsoft SQL, MSSQL)
MSSQL 是內建在 Windows 系統上的資料庫管理系統,所以可以在 Windows 上的命令提示字元直接利用 “SQLCMD” 指令工具操控,除了操作 SQL 查詢指令之外,甚至還能讓其他使用者遠端進來操作
在 Kali Linux 裡,有一套可以連接多種協定的網路工具,叫做 “Impacket”2,它是由 Python 寫成的架構,支援表格資料流 (Tabular Data Stream, TDS) 協定,代表這個工具可以接受 MSSQL 的連接,只需要呼叫 impacket-mssqlclient 工具
而我們用這個工具來遠端連線進 Windows 裡的 MSSQL,但知道 Windows 上有什麼使用者帳號、密碼以及遠端連線的 IP,再加上 “-windows-auth” 關鍵字,因為使用遠端工具連接 Windows 系統時需要強制認證 NTLM(NT LAN Manager 驗證通訊協定)3
微軟裡不太常用Kerberos作為認證
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)>
遠端連進去後,我們可以利用 “@@version” 指令檢查當前作業系統下的 MSSQL 版本,由於不同的資料庫有著自己的語法設計,所以讀者要經常預設在滲透測試時搜集目標資訊會遇到不同情形,經常需要臨時去看某個特別的語法
SQL (SQLPLAYGROUND\Administrator dbo@master)> SELECT @@version;
...
Microsoft SQL Server 2019 (RTM) - 15.0.2000.5 (X64)
Dec 10 2025 13:48:23
Copyright (C) 2019 Microsoft Corporation
Express Edition (64-bit) on Windows Server 2022 Standard 10.0 <X64> (Build 20348:) (Hypervisor)
上述機器回應給我們的資訊非常有價值,因為除了 MSSQL 正在運作的版本資訊之外,連背後的 Windows 伺服器版本也回應給我們了,甚至還有建置的號碼
當我們在 sqlcmd 這類工具執行 SQL 語法時,通常需要在最後加上一個分號結束我們的查詢,因為工具最後會填寫一個 “GO” 語法進行請求,但是如果在遠端 Windows 的情況下,我們可以忽略分號結尾,因為在 MSSQL TDS 協定後面是不加上 “GO” 語法的,所以有沒有這個分號是沒差的4
為了顯示所有的資料庫內容,我們可以從系統紀錄中針對全部的名稱都一併選取
SQL (SQLPLAYGROUND\Administrator dbo@master)> SELECT name FROM sys.databases;
name
...
master
tempdb
model
msdb
hshuang
SQL>
裡面的 master、tempdb、model 以及 msdb 都是 MSSQL 裡預設的資料庫,而 hshuang 就是我們想要探索的目標,檢查該資料庫裡面的 “tables” 就可以看相關的資訊結構
SQL (SQLPLAYGROUND\Administrator dbo@master)> SELECT * FROM hshuang.information_schema.tables;
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE
------------- ------------ ---------- ----------
hshuang dbo users b'BASE TABLE'
SQL (SQLPLAYGROUND\Administrator dbo@master)>
在上面我們的查詢回應我們該資料庫裡的表單只有一組 users,所以我們就可以針對 users 這個表單查看裡面全部的紀錄,要注意的是還需要特別指定表單的結構,就是 “dbo” 這個結構才能讓回應組織成我們想要的內容
SQL>select * from hshuang.dbo.users;
username password
---------- ----------
admin lab
guest guest
這個查詢 users 表單指令回應給我們使用者跟密碼欄位兩欄,讀者可以看到結果是這兩組帳號密碼都是明文顯示的
以上就是 MySQL 跟 MSSQL 資料庫的基礎語法介紹,對於關聯式資料庫的操作有了基本的了解後,就可以針對這些語法進行擴充,在網頁應用服務當中嘗試取得資料庫內隱密資訊的方法或破壞資料庫內容的操作
Footnotes
-
OWASP Top 10 Team, “Introducing the OWASP Top 10:2025: A05:2025 Injection,” 2025, OWASP 2025 RC1, The Open Worldwide Application Security Project, https://owasp.org/Top10/2025/A05_2025-Injection/ ↩
-
SecureAuth, “Impacket,” OCT, 2022, Github, https://github.com/fortra/impacket ↩
-
Microsoft, “NTLM 概觀,” 2025/08/16, Microsoft Learn: Windows 伺服器 – 安全性, https://learn.microsoft.com/zh-tw/windows-server/security/kerberos/ntlm-overview ↩
-
Microsoft, “SQL Server 公用程式陳述式 – GO,” 2025/11/19, Microsoft Learn: SQL – SQL Server, https://learn.microsoft.com/zh-tw/sql/t-sql/language-elements/sql-server-utilities-statements-go?view=sql-server-ver17 ↩
...在[[SQL注入漏洞之背景介紹]]中我們介紹了 SQL 基本指令以及兩個主要的關聯式資料庫,接著我們可以來看如何識別 SQL 注入漏洞後並進行利用,SQL Injection vulnerability 經常被 sqlmap 這個自動化工具發現,或者在操作時誤用觸發到...