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注入會有效。session
第二種狀況:不管輸入什麼都只顯示正常信息頁面。例如,採集登陸用戶信息的模塊頁面。採集用戶的 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、md5
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語句來完成特定的功能。