基於時間的 SQL註入研究
SQL註入攻擊是業界一種非常流行的攻擊方式,是由rfp在1998年《Phrack》雜誌第54期上的“NT Web Technology Vulnerabilities”文章中首次提出的。時過境遷,相關SQL註入的技術和工具都進行了不斷的發展和演化。目前 SQL註入漏洞已經是信息安全的一大領域,無論是小到個人網站,還是大到電子商務網站,都或多或少的存在SQL註入漏洞。為什麽SQL註入漏洞會屢禁不止,原因就在於要想防禦SQL註入漏洞,需要對SQL語句、業務流程行為、各種主流數據庫相關機制都有較為深入的認識和理解,才能真正做好SQL註入的攻擊和防範。
SQL註入和盲註
對於SQL註入的定義和一般的判斷方法,無非就是著名的三段式。普通SQL註入是通過構造SQL語句,將敏感信息直接暴露在網頁上,有兩種方式,一種是通過報錯方式,一種是通過union select聯合查詢方式。普通的SQL註入並不是完美的,一旦開發人員將錯誤頁面進行處理,將unionselect關鍵字進行過濾,註入將不再有效。其實這種修復方式存在較大的問題。如果是在不采取其他措施的情況下,僅僅更換成統一的錯誤頁面是不能避免SQL註入的,這將會產生一種更高級的SQL註入方式盲註。盲註是通過構造SQL判斷語句,通過返回頁面的不同將信息判斷出來。返回頁面有三種:有結果頁面、0結果頁面和錯誤過濾頁面。只要有其中的兩個頁面,無論哪兩個頁面都可以,就可以判斷存在註入漏洞。當然,這中間還有一個前提,就是這些不同的頁面是由輸入到URL中的SQL語句執行的不同造成的。但是普通的盲註也不是絕對有效的,一旦沒有兩個以上的差異頁面,或者不能通過頁面的不同來來判斷 URL中SQL語句的有效性,此時就要使用基於時間的SQL盲註。基於時間的SQL盲註的特點和使用假設有這麽一個文件,無論怎麽註入,頁面內容都一樣,但此文件確實存在註入點。最關鍵的是通過普通盲註不能得到差異頁面,沒有差異也就沒法進行盲註。為什麽沒有差異,有這麽幾種情況:
第一種情況:無論輸入什麽都只顯示無信息頁面,例如登陸頁面。這種情況下可能只有登錄失敗頁面,錯誤頁面被屏蔽了,並且在沒有密碼的情況下,登錄成功的頁面一般情況下也不知道。在這種情況下,有可能基於時間的SQL註入會有效。
第二種情況:無論輸入什麽都只顯示正常信息頁面。例如,采集登錄用戶信息的模塊頁面。采集用戶的 IP、瀏覽器類型、refer字段、session字段,無論用戶輸入什麽,都顯示正常頁面。
第三種情況:差異頁面不是由輸入URL中的SQL語句來決定的。這種情況下,也只能使用基於時間的盲註。
總之,情況有很多種,只要無法通過差異頁面來進行一般SQL盲註,基於時間的SQL盲註就都有存在的可能。
Oracle數據庫盲註
Oracle中基於時間的盲註主要是使用了DBMS_PIPE.RECEIVE_MESSAGE()函數和CASEWHEN?THEN?語句。下面是一個示例:
5593=(CASE WHEN (ASCII(SUBSTRC((SELECT NVL(CAST([ColumnName] AS VARCHAR(4000)),CHR(32)) FROM (SELECT [ColumnName],ROWNUM AS LIMIT FROM (SELECT DISTINCT([ColumnName]) FROM [TableName])) WHERE LIMIT=[StringIndex]),[CharIndex],1)) [GuessChar]) THENDBMS_PIPE.RECEIVE_MESSAGE(CHR(90)||CHR(80)||CHR(71)||CHR(74),5) ELSE 5593 END)
將[TableName]中的[ColumnName]字段下的所有數據選出,逐一選擇每條數據,並且逐一選擇每條數據中的每個字符,判斷該字符的 ASCII碼值是不是大於[GuessChar],如果大於,將等待 5秒,如果不大於將返回 5593,當為 5593時,整個判斷條件為真。上面的語句是用來獲取指定表指定列中的數據。我們還可以通過使用 user_tab_columns、all_tab_columns、
all_tables和user_tables等表或視圖來獲取想要的表名和列名。如果是過濾了“”、“”,可以使用 like來進行等價變化.MSSQL數據庫盲註
1)普通註入方法
MSSQL中基於時間的盲註主要使用了waitfor delay和if語句。下面是一個示例:
;if(ascii(substring((SELECT top 1 name FROM [DatabaseName]..sysobjects where xtype=Uand name not in(SELECTtop [StringIndex] name FROM [DatabaseName]..sysobjects wherextype=U)),[CharIndex],1))%3E[GuessChar]) waitfor delay 0:0:4--選出[DatabaseName]數據庫 sysobjects表中 name字段下的所有數據,並且逐一選擇條目,每個條目中的字符逐一進行 ASCII碼值的判斷,如果大於[GuessChar]中指定的碼值,將延遲 4秒鐘響應。
2)高級註入方法
除了直接使用延遲函數的方法,MSSQL中還有另外一種方法,簡單說就是MSSQL數據庫中where子句的執行順序問題。因為MSSQL數據庫使用了CBR技術進行優化,因此where後的子句不一定按照子句的書寫順序來執行,是按照各個子句的復雜度來進行,數據庫將先執行復雜度較小的子句,如果各個子句使用and來進行連接,那麽較小子句的返回結果為false,導致整體的返回結果為 false,其它高復雜度的語句的結果將無關緊要,導致其它高復雜度的語句免於執行,又因為高復雜的子句消耗時間和系統資源較大,從而縮短系統執行時間。如果 where後面的各個子句不是並列關系,而是依賴關系或遞進關系的話,則必須進行特殊處理,如 case when或子查詢。
總之,復雜度較小的子句的返回結果的真假,將決定復雜度較大的子句是否執行,也就決定了整個 SQL語句執行下來的返回時間的長短。通過這樣一個時間差,即可判斷之前復雜度較小的子句是否執行成功。
3)使用示例
如果判斷網站是否存在基於時間的盲註,那麽可以使用下面的語句:
http://xxx/index.asp?id=1 and (SELECTcount(*) FROM syscolumns AS sys1,syscolumns assys2,syscolumns AS sys3,syscolumns AS sys4,syscolumns AS sys5,syscolumns AS sys6)0 and 1=1
其中(SELECT count(*) FROM syscolumns AS sys1, syscolumns as sys2,syscolumns AS
sys3,syscolumns AS sys4,syscolumns AS sys5,syscolumns AS sys6)0是復雜度較大的子句,1=1
是復雜度較小的語句。1=1返回為真,那麽前面復雜度較大的子句將免於執行。整個查詢結果將立即返回。如果為 1=2,那數據庫將執行復雜度較大的子句,整個查詢結果將會有很大的延遲。例如下面的語句可以用來判斷當前用戶權限是否夠用。
http://xxx/index.asp?id=1 and (SELECT count(*) FROM syscolumns AS sys1, syscolumns assys2,syscolumns AS sys3,syscolumns AS sys4,syscolumns AS sys5,syscolumns AS sys6)0 and1=(SELECT IS_MEMBER(sysadmin))
MySQL數據庫盲註
MySQL數據庫基於時間的盲註在使用延遲函數上可以有兩個選擇,一個是BENCHMARK(count,expr)函數,一個是 sleep(time)函數。前者通過將 expr語句執行 count次來達到延遲的目的,後者是直接延遲 time時間。例如 benchmark函數的使用,可以寫成:
id=1 union select 1,benchmark(1000000,md5(test)),1 from use where userid=1 and ord(substring(username,1,1))=97 /*
也可以寫成:
id=1 union select if(substring(password,1,1)=A,benchmark(10000000,sha(1)),0) username,password from cms_users where username = admin/*
使用 sleep函數的示例如下:
8468=IF((ORD(MID((SELECT%20IFNULL(CAST([ColumnName]%20AS%20CHAR),0x20)%20FRO M%20[DatabaseName].[TableName]%20LIMIT%20[StringIndex],1),[CharIndex],1))%20%3E%20[G uessChar]),SLEEP([DelayTime]),8468)
其中,為了對付部分 waf防火墻,可以去掉 if關鍵字,也可以去掉“”、“”等符號,使用 like或 in來進行代替。
防禦方法
對付基於時間的 SQL盲註和對付其它類型盲註的方法是一樣的,無非是做好三個方面的工作:輸入數據的過濾、輸出數據的處理、SQL語句訪問權限的設置。
返回信息是否進行過濾:僅僅控制返回信息不能完全避免註入漏洞的存在,僅僅是讓利用難度大增,可能會相繼存在明註、盲註、基於時間的盲註。即使將錯誤頁面重定向,也不一定不能明註,比如說利用 union select走正規輸入頁面來輸出。做好返回信息的過濾只是必要條件而不是充分條件。
連接權限是否為 sa:如果連接權限設置非常嚴密,那麽利用系統表的註入就很難成功,只能通過暴力猜表名猜數據的方式,運氣成分很大,但是如果有更新當前數據表的權限,就可以向普通業務表中插入或刪除數據。輸入數據是否進行過濾:輸入數據過濾這部分說起來比較復雜,需要結合 waf、中間件、應用程序三者配合進行過濾,如果過濾嚴密,SQL註入將非常困難。但在某些特殊業務和某些特殊環境下,不可能將所有的關鍵字和符號都過濾掉,如果過濾掉,可能會導致業務不可用。
總結
無論對於普通SQL盲註,還是基於時間的SQL盲註,最重要的特點是不同點,只要有不同就能註入。這就是所謂的行不行。數據庫的連接用戶最好是管理員賬號,否則就只能使用暴力破解。這就是所謂的難不難的問題。當然,這些都是在關鍵字和符號過濾不嚴的情況下進行的。上面提到的註入方法,也只能幾個簡單的例子。如果對數據庫有足夠的了解,可以任意發揮想象去構造 SQL語句來完成特定的功能。
基於時間的 SQL註入研究