2.2 欺骗是如何进行的
简单说来,SQL注入(SQL Injection)攻击,就是攻击者通过往SQL的query中插入一系列的SQL语句,来操作数据写入到应用程序中去,从而达到非法操作数据库或网站程序的目的。但是攻击者是如何提交自己的SQL欺骗语句的呢?
2.2.1 一个无名小站与一条典型SQL语句
对于一个普通的网站,用户可以提交数据的地方很多,比如页面登录框、搜索框、文章发布、留言板、投票等,甚至一个简单的网页链接,都可能是用户数据提交的途径。而这些数据提交途径,往往也会成为攻击者提交自己欺骗性语句的入口点。这里,我们先来看看攻击者是如何提交欺骗性的SQL攻击语句的。
在Internet网上一个不知名小站,很不幸被攻击者所选中,作为攻击目标。在这个网站上,有一个小镇的简介文章,单击打开这个文章的链接,可以看到小镇的介绍信息(见图2)。
这是一个很普通的网页文章,但是却会成为攻击者提交欺骗性SQL语句的入口。看看文章的链接是这样的:
http://www.***.cn/gkml1/dwgk.asp? name=永宁镇
表面上看来,这只是一个链接地址而已,而事实上,这是一个典型的用户向数据库提交数据的例子。这个链接对应的SQL操作指令,可以猜测其语句格式如下:
Select name, article, address from gkml where name=’永宁镇’
这是一条典型的SQL语句,表示从名为“gkml”的数据库中,查询“name”字段为“永宁镇”的记录,并显示该记录中的“name”、“article”及“address”等数据。正是这些查询显示的数据信息,构成了最终显示的页面结果。
图2 小镇信息介绍
这样一条经典的语句,是如何被攻击者所利用的呢?在上面的语句中,“永宁镇”就是用户提交的数据,而攻击者时时可以通过修改这个数据进行攻击,在这个查询中注入一些SQL语句或字符,从而改变原来的整条SQL语句。例如,攻击者可能会修改文章的链接为:
http://www.***.cn/gkml1/dwgk.asp? name=永宁’镇
那么,攻击者就完成了一次修改后的数据提交,提交的数据是“永宁’镇”,这个数据被作为“name”字段的值,进入原来的SQL语句中,从而改变了原来的SQL语句,变成如下:
Select name, article, address from gkml where name=’永宁’镇’
当数据库试图去执行这个查询时,它将返回类似如下的错误(见图3):
Microsoft OLE DB Provider for SQL Server 错误 '80040e14' 第 1 行: ’镇’ 附近有语法错误。 /gkml1/dwgk.asp,行 42
造成这种结果的原因是插入了单引号“' ”,作为定界符的单引号,改变了SQL语句的构成。数据库管理系统尝试去执行如下语句:
Select name, article, address from gkml where name=’永宁’镇’
图3 修改提交数据出错
由于其中有一个不闭合的单引号,这是不符合SQL语句规范的,因此执行失败,返回了错误信息。
如果攻击者再提交特别的参数,例如:“永宁镇’; drop table authors-”,那么原来的SQL语句,就变成了如下形式:
Select name, article, address from gkml where name=’永宁镇’ ; dro p table authors--
可以看到,原来的一条SQL语句,现在经过攻击者精心提交的数据,被修改成了两条SQL语句。数据库会在执行了正常的查询之后,又执行攻击者添加的另一条语句:
drop table authors--
这条SQL语句执行的结果是,将数据库中名为“authors”的表删除。造成这种结果的原因,我们后面会详细进行讲解。此外,攻击者还可以猜解数据库中的用户名和密码等。
从上面的小例子可以看出,SQL注入式攻击主要就是通过非法修改提交SQL查询语句,达到猜解或破坏数据库的目的。而网站给攻击者所利用的数据提交入口,也是非常多的。
2.2.2 创建SQL注入检测的数据库平台
当然,并非任意一个网站,都可以被攻击者成功地进行入侵破坏,这往往取决于网站是否存在着SQL注入漏洞。在上面的例子中,也许攻击所产生的效果并不是那么直观,那么下面我们就来自己打造一个SQL注入攻击的简单实例。相信这个例子,可以让读者更加清楚地看到SQL注入攻击的危害。
首先,需要搭建一个SQL注入攻击的目标——数据库。这里我们简单地打造一个MS SQL数据库作为攻击目标。
常见的数据库非常多,在本书后面的章节中,读者将会经常碰到几种最常见的数据库,如Access数据库、MS SQL、MySQL数据库等。对于这几种数据库的创建及安装与配置,都是必须了解熟悉的,可以为后面进行网站数据库入侵检测打下基础。由于本书不是专门的数据库著作,因此没有将数据库的安装、创建及配置等作为独立的章节列出,而是融合到相关的入侵章节中进行介绍。在介绍到相关的数据库知识时,也希望读者们用心学习。
MS SQL数据库管理系统目前最新版本为MS SQL 2005,不过,目前应用最广泛的还是SQL 2000版本。在Windows 2000中安装SQL 2000版本是比较简单的,但是在Windows XP系统中安装SQL 2000企业版本时,会提示版本类型检测不正确,要求安装Windows Server版本。这里主要讲一下如何在Windows XP系统中安装SQL 2000企业版本。
首先,在SQL 2000服务器安装光盘中,打开MSDE目录,双击“setup.exe”程序,即可进行服务器商的安装(图4)。安装过程很简单,按照安装向导,直接单击【下一步】按钮即可。如果在安装过程中,出现“指定的实例名称无效”的错误提示(图5),则可删除“C:\Program Files\Microsoft SQL Server”目录下的所有文件,重新运行安装程序即可。
重启系统后,就可以看到SQL服务的图标出现了。再通过SQL服务器版的安装光盘,双击光盘根目录下的“autorun.exe”工具,直接安装客户端工具。根据提示安装,在自检过程中会提示系统不是Server版,只安装客户端工具。
然后要求选择安装路径,选择“本地计算机”(图6),单击【下一步】按钮,选择“创建新的SQL Sever实例,或安装‘客户端工具’”(图7)单选按钮。然后设置姓名及单位,并选择接受协议,再选择“仅客户端工具”单选按钮(图8)。
图4 直接安装服务端程序
图5 安装出错信息
图6 选择安装路径
图7 创建新的SQL Sever实例
图8 安装客户端工具
然后要求选择安装组件(图9),单击【下一步】按钮后完成文件的安装复制。完成文件安装复制后,在“运行”中输入“regedit”命令,打开注册表编辑器。找到[HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\MSSQLServer\MSSQLServer],这个项里面有一个键值LoginMode,默认值是1,现在将值改为2,重启计算机。然后重启系统即可(图10)。
图9 选择安装组件
图10 修改注册表验证值
重启系统后,单击【开始】→【所有程序】→【Microsoft SQL Server】→【企业管理器】菜单命令,打开企业管理器工具。依次单击左侧栏中的“Microsoft SQL Servers”→“SQL Server组”,双击右边窗口中的“Local”服务器,即可连接SQL Server了(图11)。
图11 使用企业管理器连接SQL Server
对于SQL Server配置,最重要的是连接的用户密码的修改。默认安装的SA用户为空密码,需要手工进行修改设置。在“SQL Server企业管理器”下展开“安全性”→“登录”,双击右边窗口中的“sa”用户(图12),打开用户设置对话框。在“密码”框中,输入新密码,单击【确定】按钮,即可配置新密码(图13)。在“服务器角色”和“数据库访问”选项页中,还可以设置数据库访问权限及其他详细用户设置。
图12 设置sa用户
图13 修改sa密码
MS SQL数据库服务器建立成功后,已经内置默认了几个数据库及表。SQL Server 2000服务器安装完毕后,默认会建立6个数据库:master、model、msdb、tempdb、pubs和Northwind。MS SQL数据库及表的建立主要通过SQL语句执行操作,这里使用MS SQL内置的“SQL查询分析器”来执行SQL语句。
在默认的几个数据库中,pubs和Northwind数据库为用户数据库,存储的是实例数据,供DBA和开发人员练习使用。其余的4个数据库为系统数据库,用于SQL Server 2000服务器的系统管理使用。
master数据库是SQL Server 2000中最重要的数据库,存储的是SQL Server 2000的系统信息,包括磁盘空间、文件分配和使用、系统级的配置参数、所有的登录账户信息、初始化信息和其他数据库的信息等。由于master数据库对SQL Server 2000十分重要,所以禁止用户的直接访问,并确保在修改之前有完整的备份。这几个默认的数据库,我们在以后的入侵中会经常使用到,尤其是默认的master库。
单击【开始】→【所有程序】→【Microsoft SQL Server】→【查询分析器】菜单命令,打开“SQL查询分析器”。首先,输入服务器连接账号及密码(图14),单击【确定】按钮后连接上SQL Server。在中间窗口上方,就可以输入SQL语句,单击工具栏上的【执行】按钮,即可执行SQL语句(图15)。
图14 SQL查询分析器登录
图15 SQL语句执行窗口
在SQL查询分析器窗口中,依次执行如下语句(图16):
Create database users use users CREATE TABLE USERS(USERNAME VARCHAR(20), PASSWORD VARCHAR(20)) Insert into users values(' admin' ,123456)
图16 执行SQL语句
执行后可建立一个名为“users”的数据库,并在此数据库中建立名为“users”的表。“users”表包含两个字段,一个是“username”,另一个是“password”。并在“users”表中插入了一条数据:“username=admin, password=123456”,也就是说,用户名为“admin”,登录密码为“123456”。
2.2.3 搭建一个SQL注入漏洞站点
下面,我们来通过一个简单的ASP登录页面实例,分析SQL注入攻击的原理。此ASP页面功能用于提交用户输入的用户名及密码,并查询数据库中的用户名与密码,如果相符,则显示登录成功的提示;否则,提示登录失败。
我们已经建立了一个用于用户登录的数据库及表、字段和值,该数据库名为“users”,用户名为“admin”,登录密码为“123456”。用记事本编写一个提交表单页的代码,让用户输入用户名和密码,代码如下(源代码见随书光盘\Sample\ch2\1.2.3 SQL注入简单实例.rar):
<HTML> <HEAD> <TITLE>Login Page</TITLE> </HEAD> <BODY bgcolor='000000' text=' cccccc' > <FONT Face=' tahoma' color=' cccccc' > <CENTER><H1>Login</H1> <FORM action=' login.asp' method=post> <TABLE> <TR><TD>用户名:</TD><TD><INPUT type=text name=username size=6 2 width=50></TD></TR> <TR><TD>密 码:</TD><TD><INPUT type=password name=password s ize=70 withd=50></TD></TR> </TABLE> <INPUT type=submit value=’登录’><INPUT type=reset value=’重新 登录’> </FORM> </Font> </BODY> </HTML>
将上面的代码保存为“login.html”。下面是“login.asp”的代码,它是用来控制登录的:
<HTML> <BODY bgcolor='000000' text=' ffffff' > <FONT Face=' tahoma' color=' ffffff' > <STYLE> p { font-size=20pt ! important} font { font-size=20pt ! important} h1 { font-size=64pt ! important} </STYLE> <%@LANGUAGE = JScript %> <% function trace(str) { if(Request.form("debug") == "true") Response.write(str); } function Login(cn) { var username; var password; username = Request.form("username"); password = Request.form("password"); var rso = Server.CreateObject("ADODB.Recordset"); var sql = "select * from users where username = ' " + username + "' and password = ' " + password + "' "; trace("query: " + sql ); rso.open(sql, cn); if (rso.EOF) { rso.close(); %> <FONT Face=' tahoma' color=' cc0000' > <H1> <BR> <CENTER>登录失败</CENTER> </H1> </BODY> </HTML> <% Response.end() return; } else { Session("username") = "" + rso("username"); %>
<FONT Face=' tahoma' color='00cc00' > <H1> <CENTER>登录成功<BR> 欢迎,<% Response.write(rso("Username")); Response.write( "</B ODY></HTML>" ); Response.end() return; } } function Main() { var username var cn = Server.createobject( "ADODB.Connection" ); cn.connectiontimeout = 20; connstr = "Driver={SQL Server}; Server=(local); Database=user s; UID=sa; PWD="; cn.open(connstr); username = new String(Request.form("username")); if(username.length > 0) { Login(cn); } cn.close(); } Main(); %>
建立ASP服务器,在浏览器中打开“login.html”登录页面,要求输入用户名和密码(图17)。如果输入正确的用户名“admin”和密码“123456”,那么会显示“登录成功,欢迎admin”的信息(图18)。如果用户名和密码输入错误,那么则会显示“登录失败”的提示信息(图19)。
图17 登录页面
图18 登录成功
图19 登录失败
2.2.4 第一次SQL注入攻击测试
上面的这个网页,表面上看起来没有任何问题,可以正常地执行,输入正确密码就可以登录,密码错误则登录失败。但实际上,此网页代码中存在着严重的SQL注入漏洞。存在漏洞的代码,是出现于“lgin.asp”中产生查询语句的部分,代码内容如下:
Var sql="select * from users where username=' "+username+"' an d password=' "+password+"' ";
上面的这个SQL查询语句没有问题,但是其中的“username”和“password”参数值是由用户提交的。程序没有对用户提交的值进行限制,因此攻击者可以任意修改构造提交的参数值。假如用户输入的信息如下(图20):
Username: Password:' ; ' drop table users-
图20 用户名处输入SQL注入语句
提交数据后,提示登录失败,但结果不仅如此,而是数据库中表users将被删除,此时再次输入正确用户名和密码后,将提示如下信息(图21):
图21 数据库中的表被删除
Microsoft OLE DB Provider for ODBC Drivers '80040e37' [Microsoft][ODBC SQL Server Driver][SQL Server]对象名 ' users' 无效。 \www\asp\login.asp, line 22
也就是说,此时用户表被删除后,将拒绝任何用户登录。这是因为在上面攻击提交的数据中,“; ”符号表示一个查询的结束和另一个查询的开始;“--”连结符号,在Transact-SQL中表示忽略“--”之后的语句。通过“--”字符,就可使这个用户名查询终止,并且不返回错误。也就是说,经过用户精心提交的参数,原来的SQL查询语句就被修改为如下:
Var sql="select * from users where username=' ; drop table users-
原来后面的“psssword”验证部分直接被忽略掉了,而执行了“drop table users-”语句,虽然此时用户无法进行登录,但是导致数据库中的users表被删除掉。
另外,攻击者可以只需提交一个已知的用户名,就可以用任何用户身份登录。例如,攻击者提交如下参数:
Username:admin Password: 'or'1' ='1
即可直接以admin的身份登录成功。造成这样的结果,也是由于SQL注入攻击漏洞引起的,这里仅是做一个演示,而具体原理将在后面的章节中进行详细的解释。