萬盛學電腦網

 萬盛學電腦網 >> 系統工具 >> SQL 注入技術詳解

SQL 注入技術詳解

1.1概述

1.2背景

1.3字符編碼

2.1綜合測試

2.2測試過程

2.3分析結果

3.1繞過驗證

3.2 SELECT

3.2.1 直接利用 ' 號
3.2.2 基於UNION
3.2.3 利用結構錯誤查詢表單
3.2.4 插入語句(圓擴號)
3.2.5 利用LIKE語句查詢
3.2.6 "死胡同"
3.2.7 列的數目不匹配問題
3.2.8 附加的WHERE引號
表和域的枚舉
3.2.10 單括號

3.3插入

3.4SQL服務器存儲過程利用

4.1數據處理

4.2安全的SQL網頁應用程序編寫

5.1MS SQL Server

5.2MS Access Server

5.3 Oracle
關於 SPI Dynamics,INc.


一 概述和介紹

1.網絡應用和SQL注射

1.1概述

有些網絡數據庫沒有過濾客戶提供的數據中可能有害的字符,SQL注射就是利用插入有害字符進行攻擊的技術。盡管非常容易防范,但因特網上仍然有驚人數量的存儲系統容易受到這種攻擊。這篇文章的目的是指導專業安全組織了解這種技術,並告訴他們正確的,用來防范SQL注射的辦法,以及處理各種常見的,由於非法輸入引起的問題.


1.2背景

在讀這篇文章之前,你應該對數據庫如何工作,以及SQL如何被用來訪問數據庫有一些基礎的了解。我建議您閱讀eXtropia.com的文章“Introduction to Databases for WebDevelopers”。
(網址:http://www.extropia.com/tutorials/sql/toc.html)


1.3字符編碼

在大多數的網絡浏覽器中,標點符號和許多其它符號在用於一個網絡請求前需要把URL編碼,以便被適當地編譯(interpret)。在本文中的例子和截圖中我使用了固定的ASCII字符以保證最大的可讀性。然而,在實際應用中,你需要在HTTP請求中用%25來代替百分號(%),用%2B來代替加號(+)等等。。。


2.易損性的測試(Testing for vulnerability)

2.1綜合測試

徹底地檢測一個網絡請求是否容易被SQL注射比一個可能的猜測(might guess)需要耗費更多的精力。當你把一個單引號放進一個腳本的第一個參數值時,服務器返回一個空白的網頁,上面除了ODBC錯誤以外什麼都沒有.顯然這種情況直接反映出web程序存在漏洞,但通常都不是這樣的,如果你沒有注意細節的話,很容易忽略掉一個看上去完美,其實很脆弱的腳本。
服務器上每一個腳本中的每一個參數都應該被檢測。開發者和開發組織之間可能很不一致。設計腳本A的程序員也許和腳本B的開發毫無關系,所以,其中一個也許對SQL注射免疫,而另外一個可能不會。事實上,設計腳本A裡的函數A的程序員也許和腳本A裡的函數B的開發毫無關系,所以腳本A裡的一個參數也許對SQL注射是脆弱的,而另外一個參數卻不一定,即使整個網絡請求是由一個程序員來構想,設計,編寫及測試的,在成千上萬的腳本中的參數中,由於某種原因,設計者忘了檢驗某個地方的數據,所以仍有可能存在一個脆弱的參數,而且那個地方是唯一的,你永遠都不能確定是哪裡,所以必須測試所有的東西。


2.2測試過程

用一個單引號和一個SQL關鍵字(比如“WHERE”)替代每一個參數的值(argument),每個參數都應該被單獨地測試,不止那樣,當你測試一個參數的時候,應該保持其它的參數不變,並用有效的數據填充它們的值(argument),It can be tempting to just delete all of the stuff that you're not working with in order to make things look simpler, particularly with applications that have parameter lines that go into many thousands of characters.
當你測試一個參數是否能被SQL注射的時候,如果忽略了其它參數或者給他們一個錯誤的值(argument),網絡請求就有可能由於其它原因而出錯,這阻礙了你判斷SQL注射是否可行。比如,讓我們假設以下是一個有效的,純粹的(unaltered)參數行:

ContactName=Maria%20Anders&CompanyName=Alfreds%20Futterkiste

並且它返回一個ODBC錯誤:
ContactName=Maria%20Anders&CompanyName='%20OR

如果我們這樣檢測:
CompanyName='

可能只會給你一個錯誤告訴你需要指定一個ContactName值。
這行:
ContactName=BadContactName&CompanyName='

可能返回同樣的頁面,因為請求根本沒有指定ContactName。或者,它可能返回你站點默認的主頁。或者,可能它找不到指定的ContactName,或者web程序認為沒有必要看CompanyName,所以它甚至根本不把這個參數值認為是一個SQL聲明,或者,它可能給你一些完全不同的東西,所以,當檢測SQL注射的時候,記得總是用完整的參數行,並且除了你正在檢測的那個參數外,還要給其它所有的參數一個合法的值。


2.3分析結果

如果你得到一個數據庫服務器返回的某些錯誤信息,那麼SQL注射顯然是存在的.然而,數據庫錯誤信息不一定總是明顯的(有時候編寫程序的人可能做一些奇怪的事情),所以,你應該順便看看每個可能的地方來確認注射是否成功,首先你應該從返回的頁面上的所有資源中找尋像"ODBC", "SQL Server", "Syntax"等的短語,更多的信息可能含在HTTP的頭部,隱藏的輸入...。我曾見過某些存儲系統上的網絡請求返回的錯誤信息中,在HTTP回復的body中完全沒有任何信息,但在頭部中卻有數據庫錯誤信息。為了調試和QA的目的,很多網絡請求都內嵌了這種特征,然而到最後發表前卻忘了把它們去處掉或使之無效。
你不只要注意即時返回的頁面,同樣鏈接頁面也要看,在最近的一次pen-test中,我看到一個網絡請求被SQL注射攻擊後,返回了一個類錯誤信息頁面,點擊錯誤旁邊的停止標志圖片,鏈接到了另外一個滿是SQL服務器錯誤信息的頁面。
另一個應該密切注意的是302頁面重定向,在你有機會注意到它之前,你可能就無奈的離開了一個含有數據庫錯誤信息的頁面.
請注意即使你真的得到了一個ODBC錯誤信息回復,SQL注射仍有可能成功,很多時候(Lots of the time)你得到一個properly formatted, seemingly類錯誤消息頁面,告訴你"an internal server error" 或者 "problem processing your request."
有些網絡請求被設計成一旦出現任何的錯誤,客戶都返回到站點的主頁面。如果你得到一個500錯誤頁面,很有可能注射就出現了,很多站點都有一個默認的500服務器內部錯誤頁面來說明服務器正在維護中,或禮貌的讓用戶把他們的請求email給站點的維護人員。這就有可能用procedure techniques來利用這些站點,這將在後面討論。


3.攻擊

3.1繞過驗證

最簡單的SQL注射技術是繞過基於表單的登陸.讓我們假設某個網絡請求的代碼如下:
SQLQuery = "SELECT Username FROM Users WHERE Username = '" & strUsername & "' AND Password = '" & strPassword & "'"
strAuthCheck = GetQueryResult(SQLQuery)
If strAuthCheck = "" Then
boolAuthenticated = False
Else
boolAuthenticated = True
End If
當一個用戶提交了一個用戶名和密碼後,查詢(query)將搜索Users表單來看是否其中有一行中所包含的用戶名和密碼與用戶提供的相同,如果找到了那麼一行,則用戶名被儲存到變量strAuthCheck中,同時說明該用戶應該被鑒定,如果沒有找到那麼一行,則strAuthCheck變量保持為空,同時該用戶不被鑒定。
如果strUsername和strPassword變量可以包含任何你要的字符,你可以修改當前的SQL查詢結構,那樣即使你不知道有效的用戶名和密碼,你仍何以得到一個有效的name,它是如何實現的呢?讓我們假設用戶像下面那樣填充了一個登陸表單:
Login: ' OR ''='
Password: ' OR ''='
這將給SQLQuery以下值:
SELECT Username FROM Users WHERE Username = '' OR ''='' AND Password = '' OR ''=''
請求並不把用戶提交的數據與現存的Users表單做比較,而是直接比較''和'',顯然它總是返回true,(注意nothing和null是有區別的)由於WHERE語句中的所有驗證條件都符合了,用戶名將使用表單中搜索到的第一行中的那個,接著用戶名將被傳遞給變量strAuthCheck,這樣我們的效力就得以保證。使用single result cycling技術,也有可能使用另外一行的數據,這將在以後討論。

3.2 SELECT
對於另一些情況而言,你必須根據查詢那些有缺陷的web程序返回的結果,來判斷和調整你提交的SQL查詢字符串,以便搞定服務器.

3.2.1 直接利用單引號
你將面臨的第一個錯誤是語句結構錯誤.一個結構錯誤表明SQL查詢的語句結構存在缺陷.首先你應該明白,在沒有編碼引號的情況下, 插入腳本攻擊是否可以成功.

直接SQL注射的時候,無論你提交什麼語句都會被不加任何改變地應用於SQL查詢中.試著提交參數的時候,先輸入合法的值,然後在其後添加一個空格和一個OR,如果服務器產生了錯誤,那麼直接SQL注射是可能的.提交的值可以是任何WHERE子句中用到的值,例如:
SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERE Employee = " & intEmployeeID
或者是緊跟於一個SQL關鍵字,例如表名或者表裡的欄目名,比如
SQLString = "SELECT FirstName, LastName, Title FROM Employees ORDER BY " & strColumn
所有其他的例子都是引號注射,在一個存在引號插入漏洞的程序裡面, 任何一個你提交的參數,系統都會在前面和後面添加一個引號,就像這樣:
SQLString = "SELECT FirstName, LastName, Title FROM Employees WHERE EmployeeID = '&q

copyright © 萬盛學電腦網 all rights reserved