SQL盲注攻击的简单介绍

发表于:2014-4-16 11:45

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:yansj_scu    来源:51Testing软件测试网采编

分享:
  2 确定注入漏洞
  要进行SQL注入攻击,首先当然是确认要攻击的网络应用程序存在注入漏洞,因此攻击者首先必须能确立一些与服务器产生的错误相关的提示类型。尽管错误信息本身已被屏蔽,网络应用程序仍然具有能区分正确请求和错误请求的能力,攻击者只需要学习去识别这些提示,寻找相关错误,并确认其是否和SQL相关。
  2.1 识别错误
  一个网络应用程序主要会产生两种类型的错误,第一种是由Web服务器产生的代码异常(exception),类似于“500:Internal Server Error”,通常如果SQL注入语句出现语法错误,比如出现未闭合的引号,就会使服务器抛出这类异常。如果要屏蔽该类错误,一般会采用将默认的错误信息替换成一个事先定制的HTML页面,但只要观察到有这种响应出现,就可以确认其实是发生了服务器错误。在其他情况下,为了进一步屏蔽该类错误,有些服务器一出现异常,会简单地跳转到主页面或前一个访问过的页面, 或者显示一条简单的错误消息但不提供任何细节。
  第二类错误是由应用程序代码产生的,这代表其开发者有较好的编程习惯。这类应用程序考虑到可能会出现一些无效的情况,并分别为之产生了一个特定的错误信息。尽管出现这类错误一般会返回一个请求有效的响应(200 OK),但页面仍然会跳转到主页面,或者采用某种隐藏信息的办法,类似于“Internal Server Error”。
  为了区分这两种错误,我们看一个例子:有两个电子商务的应用程序,A和B,两个应用程序都使用同一个叫proddetails.asp的页面,该页面期待获得一个参数,叫ProdID。它获取该参数后,从数据库中提取相应的产品详细信息数据,然后对返回的结果进行一些处理。两个应用程序都是通过一个产品列表页面上的链接调用proddetails.asp,因此能保证ProdID一直都是存在且有效的。应用程序A认为这样就不会出现问题,因此对参数不做额外的检查,而如果攻击者篡改了ProdID,插入了一个在数据表中不存在的id,数据库就会返回一个空记录。由于应用程序A没有料到可能会出现空记录,当它试图去处理该记录中的数据时,就可能会出现异常,产生一个“500:Internal Server Error”。而应用程序B,会在对记录进行处理前确认记录的大小超过0,如果是空记录,则会出现一个错误提示“该产品不存在”,或者开发者为了隐藏该错误,会将页面重新定位到产品的列表页面。
  因此攻击者为了进行SQL盲注,会首先尝试提交一些无效的请求,并观察应用程序如何处理这些错误,以及如果出现SQL错误会发生什么情况。
  2.2 定位错误
  对要攻击的应用程序有了初步的认识后,攻击者会试图定位由人为构造的输入而产生的错误信息。这时,攻击者就会使用标准的SQL注入测试技术,比如添加一些SQL关键字(如OR,AND等)和一些META字符(如;或’等)。每一个参数都被独立地进行测试,而获得的响应将被检验用来判断是否产生了错误。通过一个拦截代理服务器(intercepting proxy)或者类似的工具可以方便地识别页面跳转和其他一些可预测的隐藏错误,而任何一个返回错误的参数都有可能存在SQL注入漏洞。而在单独测试每个参数过程中,必须保证其他参数都是有效的,因为需要避免除注入以外任何其他可能的原因所导致的错误影响了判断结果。测试的结果一般是一个可疑参数的列表,列表中的一些参数可能的确可以进行注入利用,另外一些参数则可能是由一些SQL无关的错误所造成,因此需要被剔除。攻击者接下来就需要从这些参数中挑选真正存在注入漏洞的参数,我们称之为确定注入点。
  2.3 确定注入点
  SQL字段可以被划分为三个主要类型:数字、字符串和日期。虽然每个类型都有其特点,但却与注入的过程无关。每一个从网络应用程序提交给SQL查询的参数都属于以上三个类型中的一类,其中数字参数被直接提交给服务器,而字符串和日期则需要加上引号才被提交,例如:
  SELECT * FROM Products WHERE ProdID = 4
  与
  SELECT * FROM Products WHERE ProdName = 'Book'
  而SQL服务器,并不关心它接受到的是什么类型的参数表达式,只要该表达式是相关的类型即可。而这个特点则使攻击者能够很容易地确认一个错误是否和SQL相关。如果是数字类型,最简单的处理办法是使用基本的算术操作,例如以下请求:
  /mysite/proddetails.asp?ProdID=4
  测试该参数的一种办法是插入4’作为参数,另一种是使用3+1作为参数,假设这两个参数已直接被提交给SQL请求语句,则将形成以下两个SQL请求语句:
  (1) SELECT * FROM Products WHERE ProdID = 4'
  (2) SELECT * FROM Products WHERE ProdID = 3 + 1
  第一个SQL语法有问题,将一定会产生一个错误,而第二个如果被顺利地执行,返回和最初的请求(即ProdID等于4)一样的产品信息,这就提示该参数是存在注入漏洞的。
  类似的技术可以被应用于用一个符合SQL语法的字符串表达式替换该参数,这里有两个区别:第一,字符串表示式是放在引号中的,因此需要阻断引号;第二,不同的SQL服务器连结字符串的语法不同,比如MS SQL Server使用符号+来连结字符串,而Oracle使用符号||来连结。例如以下请求:
  /mysite/proddetails.asp?ProdName=Book
  要测试该ProdName参数是否有注入漏洞,可以先其替换成一个无效的字符串比如Book’,然后再替换成一个可能生成正确字符串的表达式,比如B’+’ook(对于Oracle,是B’||’ook)。这就会形成以下两个SQL请求语句:
  (1) SELECT * FROM Products WHERE ProdName = 'Book''
  (2) SELECT * FROM Products WHERE ProdID = 'B' + 'ook'
  则第一个仍然可能产生一个SQL错误,而第二个则可能返回和最初的请求一样的值为Book的产品。
  我们注意到,即使应用程序已经过滤了’和+等META字符,我们仍然可以在输入时过把字符转换成URL编码(即字符ASCII码的16进制)来绕过检查,例如:
  /mysite/proddetails.asp?ProdID=3+1就等于/mysite/proddetails.asp?ProdID=3%2B1
  /mysite/proddetails.asp?ProdID=B’+’ook就等于/mysite/proddetails.asp?ProdID=B%27%2B%27ook
  类似的,任何表达式都可以用来替换最初的参数。而特殊的系统函数也可以被用来提交以返回一个数字,一个字符串或一个日期,比如Oracle中sysdate返回一个日期表达式,而在SQL Server中,getdate()会返回日期表达式。其他的技术同样可以被用来判断是否存在SQL注入漏洞。
  通过以上介绍可以发现,即使没有详细的错误信息,对于攻击者来说,判断是否存在SQL注入漏洞仍然是一个非常简单的任务。
  3 实施注入攻击
  攻击者在确定注入点后,就要尝试进行注入利用,这需要其能确定符合SQL语法的注入请求表达式,判断出后台数据库的类型,然后构造出所需的利用代码。
  3.1 确定正确的注入句法
  这是SQL盲注攻击中最难也最有技巧的步骤,如果最初的SQL请求语句很简单,那么确定正确的注入语法也相对容易,而如果最初的SQL请求语句较复杂,那么要想突破其限制就需要多次的尝试,但进行这些尝试所需要的基本技术却是非常简单。
  确定基本的句法的过程即通过标准的SELECT … WHERE语句,被注入的参数(即注入点)就是WHERE语句的一部分。为了确定正确的注入句法,攻击者必须能够在最初的WHERE语句后添加其他数据,使其能返回非预期的结果。对一些简单的应用程序,仅仅加上OR 1=1就可以完成,但在大多数情况下如果想构造出成功的利用代码,这样做当然是不够的。经常需要解决的问题是如何配对插入语符号(parenthesis,比如成对的括号),使之能与前面的已使用的符号,比如左括号匹配。另外常见的问题是一个被篡改的请求语句可能会导致应用程序产生其他错误,这个错误往往难于和一个SQL错误相区分,比如应用程序一次如果只能处理一个记录,在请求语句后添加OR 1=1可能使数据库返回1000条记录,这时就会产生错误。由于WHERE语句本质上是一串通过OR、AND或插入语符号连接起来的值为TRUE或FALSE的表达式,因此要想确定正确的注入句法,关键就在于能否成功地突破插入语符号限制并能顺利地结束请求语句,这就需要进行多次组合测试。例如,添加AND 1=2能将整个表达式的值变为FALSE,而添加OR 1=2则不会对整个表达式的值产生影响(除非操作符有优先级)。
  对于一些注入利用,仅仅改变WHERE语句就足够了,但对于其他情况,比如UNION SELECT注入或存储过程(stored procedures)注入,还需要能先顺利地结束整个SQL请求语句,然后才能添加其他攻击者所需要的SQL语句。在这种情况下,攻击者可以选择使用SQL注释符号来结束语句,该符号是两个连续的破折号(--),它要求SQL Server忽略其后同一行的所有输入。例如,一个登录页面需要访问者输入用户名和密码,并将其提交给SQL请求语句:
  SELECT Username, UserID, Password FROM Users WHERE Username = ‘user’ AND Password = ‘pass’
  通过输入john’--作为用户名,将会构造出以下WHERE语句:
  WHERE Username = ‘john’ --'AND Password = ‘pass’
  这时,该语句不但符合SQL语法,而且还使用户跳过了密码认证。但是如果是另外一种WHERE语句:
  WHERE (Username = ‘user’ AND Password = ‘pass’)
  注意到这里出现了插入语符号,这时再使用john’--作为用户名,请求语句就会错误:
  WHERE (Username = ‘john' --' AND Password = ‘pass’)
  这是因为有未配对的插入语符号,请求语句就不会被执行。
  这个例子显示出使用注释符号能够用来判断请求语句是否被顺利地结束了,如果添加了注释符号且没有产生错误,这就意味着注释符号前的语句已经顺利地被结束。如果出现了错误,这就需要攻击者进行更多的请求尝试。
32/3<123>
2023测试行业从业人员调查问卷已开启,千元大奖正在等你~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2023
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号