常见web漏洞学习之文件上传
.htacess的Apache解析漏洞
配合文件包含,图片马
条件竞争
客户端验证
js校验后缀名
绕过:先把木马改为jpg或其他形式,burp抓包后修改为php
服务端验证
- MIME
绕过:burp修改文件头content-type字段为image/gif
- 文件内容头
在马之前加上一些图片信息,如
1 | GIF89a<?php @eval($_POST['caidao']);?> |
- 文件扩展名校验(白名单,黑名单)
- 文件内容检测(检测内容是否合法或是是否有恶意代码)
绕过方式
- 大小写、双写绕过pphphp
- 文件名后加上个**.或是空格**(burp中修改)
- 🔲尝试黑名单可能没有的类型,如asa、cer、.htaccess
.htaccess是Apache的
修改后缀类型,php修改为php3、php5(php高版本会向低版本兼容)
针对Windows系统,上传不符合Windows命名规则的文件名,可以尝试**::$DATA进行绕过或是:1.jpg**
windows下文件名+::$DATA,会把它当做数据流来处理,不会检验文件的后缀名,并且保留::$DATA之前的的文件名及后缀
简单来说,数据流$DATA是Windows下NTFS文件系统的一个特性,即NTFS文件系统的存储数据流的一个属性DATA时,就是请求 a.asp 本身的数据,如果a.asp 还包含了其他的数据流,比如 a.asp:lake2.asp,请求 a.asp:lake2.asp::$DATA,则是请求a.asp中的流数据lake2.asp的流数据内容。
- %00截断,解析的时候会自动忽略%00后面的内容
- 常用在服务端把文件路径和文件名加在一起进行判断后缀
- 截断条件:
php < 5.3.4
php.ini文件magic_quotes_gpc为off(这个函数的作用是转义字符,在php>5.4.0中已经移除了)
- 当参数是以post方式传入时,需要二进制修改
2e改为00
- 🔲配合文件包含使用
上传图片马
拼接图片马:copy xxx.jpg /b + shell.php /a shell.jpg (b是binary二进制的意思,/b就是以二进制的格式)
进行文件包含
- 🔲条件竞争
简单来说就是利用了并发处理请求不当或是相关操作逻辑顺序设计不合理时,会导致条件竞争的发生
具体实例可见upload-labs pass17、18
pass17源码 – 利用方式:在文件删除之前访问文件
1 | $is_upload = false; |
一些函数
- trim(string,charlist) ——移除字符串两侧的空白或其他预定义的字符charlist
- strrchr(string,char) ——在string中查找char最后出现的位置,并返回(截取)包括char在内到字符串末尾的所有字符
- str_ireplace(find,replace,string) ——在string中找到find,然后进行替换replace
- substr(string,start,length可选) ——在string中从start处开始,返回length长度的字符串
- strrpos(string,find,start可选) ——在string中从start开始,返回最后一次出现的位置
- move_uploaded_file(string $filename,string $destination) ——检测确保上传的文件filename是合法的(即通过post方式上传),如果合法就将其移动为由destination指定的文件
- in_array(data,array) —— 检查数组array中是否存在某个值data
bypass之waf
总体的思路就是让waf无法获取到文件名或是其他方式无法判断上传的木马(php、jsp、asp、aspx等)
waf检查的东西
根据前面的学习,猜测waf会检查
- MIME类型
- 文件扩展名
- 文件内容
除此之外还会检查
- 请求的url
- Boundary边界
常见扩展名黑名单:
1 | asp|asa|cer|cdx|aspx|ashx|ascx|asax |
这里并没有进行复现,只是可能进行绕过的一些思路
增加Content-Disposition字段长度
在常规的 HTTP 应答中,Content-Disposition 响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。
在 multipart/form-data 类型的应答消息体中,Content-Disposition 消息头可以被用在 multipart 消息体的子部分中,用来给出其对应字段的相关信息。各个子部分由在Content-Type 中定义的分隔符分隔。用在消息体自身则无实际意义。
Content-Disposition 消息头最初是在 MIME 标准中定义的,HTTP 表单及 POST 请求只用到了其所有参数的一个子集。只有 form-data 以及可选的 name 和 filename 三个参数可以应用在HTTP场景中。
对文件名进行修改
- 去除filename=”shell.php”中的双引号或是修改为单引号,扰乱匹配
- 因为文件在上传时接收的是最后一个文件,那么尝试在这之前加一些干扰的filename参数
Content-Disposition: form-data; name=”file”; filename=1.jpg; filename=”shell.php”
- 当是对所有的filename进行检测时,尝试将前面的filename去掉
Content-Disposition: form-data; name=”file”; filename= ; filename=”shell.php”
在文件名中间加符号扰乱匹配,如
1 | ; |
对filename动手脚
让waf对filename这个字符串匹配不到,但是服务器又可以接收,加入换行这类的干扰
可能的绕过
- 对文件名中的每个字符进行换行
- 切断filename=和之后的值(换行)
- 文件名换行,就是在HEX中加入0a
修改匹配字段
filename参数是在post包中的 Content-Disposition 字段,那么waf也是先匹配到这个http头在对内容进行检测,我们可以尝试对这个头的特征进行修改
我们尝试去掉这个form-data (form-data;的意思是内容描述,form-data的意思是来自表单的数据,但是即使不写form-data,apache也接受。)
- 去掉form-data
- 对Content-Disposition 字段进行参数污染、Content-Disposition大小写混淆
Content-Disposition 字段参数污染

- 添加额外的Content-Type字段

- 添加额外的filename进行参数污染

- 添加额外的Content-Length头
多个等号
就是将filename=处添加多个等号
%00截断
产生的原因是0x00为十六进制表示法,ASCII码里就为0,有些函数在处理时会将其当做结束符;当url中出现%00会认为读取已经结束
参考文章
[文件上传Bypass安全狗 ](