0x01 前言

本文参考了大佬的文章主要以学习为目的,下面进入正文。

文件上传的Bypass更多的考验的是实战经验,以及姿势的积累。绕过的思路主要是结合各种特性和waf设计的各种缺陷。

  1. 一个判断文件上传存在waf的小思路:
  2. 1、上传正常.jpg的图片 #成功
  3. 2、上传正常.php #拦截,可能存在WAF
  4. 3、绕过.php文件的filename后进行上传 #成功
  5. 4、使用绕过了filename的姿势上传恶意.php #拦截
  6. 以上这么个逻辑通常来讲是waf检测到了正文的恶意内容,后面就涉及到免杀的范畴了

0x02 开搞前的准备

首先我们要思考两个问题:上传文件时waf会检查哪里?

  1. 1、请求的URL
  2. 2Boundary边界
  3. 3MIME类型
  4. 4、文件扩展名
  5. 5、文件的内容

常用的黑名单有哪些?

1、asp|asa|cer|cdx|aspx|ashx|ascx|asax
2、php|php2|php3|php4|php5|asis|htaccess
3、htm|html|shtml|pwml|phtml|phtm|js|jsp
4、vbs|asis|sh|reg|cgi|exe|dll|com|bat|pl|cfc|cfm|ini

测试前的准备工作:

1、什么语言?什么容器?什么系统?分别是什么版本的?
2、上传文件都可以上传什么格式的文件?还是允许任意类型上传
3、上传的文件是不是被重命名或二次渲染
4、是不是返回上传路径,还是需要我们去猜测或者FUZZ

0x03 开搞!

容器特性

Apache1.X 2.X解析漏洞:

Apache在以上版本中,解析文件名的方式是从后向前识别扩展名,直到遇见Apache可识别的扩展名为止。
Win2k3 + APACHE2.0.59 + PHP
image.png

IIS6.0两个解析缺陷:

目录名包含.asp、.asa、.cer的话,则该目录下的所有文件都将按照asp解析。例如:
image.png
文件名中如果包含.asp;、.asa;、.cer;则优先使用asp解析。例如:
image.png
有一点需要注意,如果程序会将上传的图片进行重命名的话就gg了。

Nginx解析漏洞

(1)

Nginx 0.5.*
Nginx 0.6.*
Nginx 0.7 <= 0.7.65
Nginx 0.8 <= 0.8.37

以上Nginx容器的版本下,上传一个在waf白名单之内扩展名的文件shell.jpg,然后以shell.jpg.php进行请求。

(2)Nginx 0.8.41 – 1.5.6:
以上Nginx容器的版本下,上传一个在waf白名单之内扩展名的文件shell.jpg,然后以shell.jpg%20.php进行请求。

PHP CGI解析漏洞:

IIS 7.0/7.5
Nginx < 0.8.3

以上的容器版本中默认php配置文件cgi.fix_pathinfo=1时,上传一个存在于白名单的扩展名文件shell.jpg,在请求时以shell.jpg/shell.php请求,会将shell.jpg以php来解析。

多个Content-Disposition:

在IIS的环境下,上传文件时如果存在多个Content-Disposition的话,IIS会取第一个Content-Disposition中的值作为接收参数,而如果waf只是取最后一个的话便会被绕过,例如:
image.png

请求正文格式问题

正常的upload请求都是以下这样:

Content-Disposition: form-data; name="file1"; filename="shell.asp"
Content-Type: application/octet-stream

然而这个格式也并非强制性的,在IIS6.0下如果我们换一种书写方式,把filename放在其他地方:
image.png
我们把filename放到最后,就成功上传了文件

结合.htaccess指定某些文件使用php来解析

这个方法通常用于绕过waf黑名单的,配置该目录下所有文件都将其使用php来解析:
image.png

系统特性

windows特殊字符

当我们上传一个文件的filename为shell.php{%80-%99}时,如shell.php%90:
image.png
waf可能识别为.php{%80-%99},就会导致被绕过。
image.png

exee扩展名

上传.exe文件通常会被waf拦截,如果使用各种特性无用的话,那么可以把扩展名改为.exee再进行上传。

NTFS ADS特性

ADS是NTFS磁盘格式的一个特性,用于NTFS交换数据流。在上传文件时,如果waf对请求正文的filename匹配不当的话可能会导致绕过。
image.png
Windows在创建文件时,在文件名末尾不管加多少点都会自动去除,那么上传时filename可以这么写shell.php……也可以这么写shell.php::$DATA…….
image.png

WAF缺陷

匹配过于严谨

一个空格导致安全狗/玄武盾被绕过:
正常请求包如下:

Content-Type: multipart/form-data; boundary=---------------------------4714631421141173021852555099

尝试在boundary后面加个空格或者其他可被正常处理的字符:

boundary =---------------------------4714631421141173021852555099

image.png
以上也能说明一个问题,安全狗在上传文件时匹配各个参数都十分严谨,不过IIS6.0以上也变的严谨了,再看看其他的地方:
每次文件上传时的Boundary边界都是一致的

Content-Type: multipart/form-data; boundary=---------------------------4714631421141173021852555099
Content-Length: 253

-----------------------------4714631421141173021852555099
Content-Disposition: form-data; name="file1"; filename="shell.asp"
Content-Type: application/octet-stream

<%eval request("a")%>
-----------------------------4714631421141173021852555099--

但如果容器在处理的过程中并没有严格要求一致的话可能会导致一个问题,两段Boundary不一致使得waf认为这段数据是无意义的,可是容器并没有那么严谨:
image.png

修改Content-Type的MIME类型

这里就不解释了
image.png

ASCII > 127的字符绕过

ASCII表一共126,大于127后就不识别了
image.png

数据过长(脏字符)导致的绕过

waf如果对Content-Disposition长度处理的不够好的话可能会导致绕过,例如:
image.png

基于文件名的超长数据

image.png
如果web程序会将filename除了扩展名的那段重命名的话,那么还可以构造更多的点、符号等等。
image.png

特殊的长文件名

文件名使用非字母数字,比如中文等最大程度的拉长,不行的话再结合一下其他的特性进行测试,如:

shell.asp;王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王.jpg

0x04 参考

1、一次实战:https://www.sohu.com/a/272080406_99907709
2、文件上传bypass总结:https://www.cnblogs.com/sunny11/p/14918367.html