文件上传方法总结
以upload-labs讲解
项目地址https://github.com/c0ny1/upload-labs/releases
每道题都要通过上面这张图判断文件校验的方式,才能有大体绕过思路
PASS 01 前端js校验
尝试上传符合条件的文件,将一句话木马后缀改为jpg,抓包修改成php文件。
PASS 02 MIME文件类型校验
提示文件类型不正确,可能是MIME校验
PASS 03 php多种扩展名绕过
上传php文件时出现提示,php被加入了黑名单,并且会将上传的文件重新命名,无法通过上传.htaccess文件绕过,大小写失败了,尝试上传php3,phtml等其他扩展名文件绕过黑名单限制
PASS 04 上传.htaccess文件绕过
通过上传jpg图片发现文件名并未改变,但是各种扩展名大小写都被限制,尝试上传.htaccess文件,内容为
SetHandler application/x-httpd-php
将所有文件解析为ph执行,此时上传文件改为jpg格式成功上传,查看解析
PASS 05 后缀名大写绕过
将后缀名大写绕过
PASS 06 Windows特性文件命名规则
相比前几题,大小写绕过和上传.htaccess文件已经行不通了。查看源代码没有去掉末尾的空格,那可以利用Windows的特性,Windows下xx.jpg[空格]或xx.jpg.这两类文件都是不允许存在的,若是这样命名,Windows会默认除去空格或点。
上传1.php,抓包修改为1.php[空格]
PASS 07 Windows特性文件命名规则
原理同pass 06,通过Windows文件命名规则绕过,抓包将文件改为1.php.即可
综合pass06和pass07,碰到此类型的都可以将文件修改为1.php[空格].
PASS 08 Windows特性 ::$DATA绕过
在php+Windows的情况下:如果文件名+"::$DATA" 会把 "::$DATA"之后的数据当成文件流处理,不会检测后缀名且保持”::$DATA”之前的文件名
抓包修改1.php为如图所示
上传成功后查看链接,链接为http://192.168.135.144/upload/202004231705477566.php::$data
查看http://192.168.135.144/upload/202004231705477566.php 即为已上传文件
PASS 09
从源码可以看出这次拼接的路径是$file_name的值,结合Windows特性构造文件
PASS 10 后缀名双写绕过
通过上传1.php文件后查看文件后缀.php被过滤,猜测可能之过滤一次,尝试双写后缀名绕过,这里双写要注意:1.pphphp和1.phphpp产生的文件是不同的,过滤是从左往右的,所以1.phphpp会生成文件1.hpp
PASS 11 %00截断绕过
通过测试得知是后端白名单限制,对内容并未过滤
代码分析发现最终返回的图片链接是”存储路径名+重命名后的文件名“,看到这个我们可以联想到使用%00截断路径。
截断条件:1.php版本小于5.3.4 2.php.ini的magic_quotes_gpc为OFF状态(默认为OFF)
访问链接http://192.168.135.144/upload/1.php 上传成功
PASS 12 %00截断绕过
同pass 11一样使用00截断绕过,但这里是通过POST方式,由于POST不像GET可以自动解码%00,所以需要手动解码,如下
访问http://192.168.135.144/upload/2.php 上传成功
PASS 13 文件内容头部检测
分析代码可知通过读文件的前2个字节判断文件类型,因此直接上传图片马即可,制作方法:
copy 1.jpg /b + shell.php /a webshell.jpg
成功上传后利用的话还需结合文件包含漏洞。
PASS 14 文件内容头部检测
通过代码得知这里使用getimagesize获取文件类型,直接上传图片马可绕过
PASS 15 图片马绕过
这里用到php_exif模块来判断文件类型,同样可以利用图片马直接绕过
PASS 16 图片二次渲染
绕过思路:对比上传前和上传后的图片的差异,找到相同数据同时又是非图片数据区的地方,在此处写入恶意代码。不同的图像类型插入方式有区别。
GIF
GIF的二次渲染绕过是最简单的,将源文件和二次渲染过的文件进行比较,找到源文件中没有被修改的那段区域,写入PHP代码即可。 使用工具winhex
PNG和JPG通过脚本可以生成,使用方法:
1.先将一张正常的jpg图片上传,上传后将服务器存储的二次渲染的图片保存下来。
2.将保存下来经过服务器二次渲染的那张jpg图片,用脚本进行处理生成payload.jpg
3.然后再上传payload.jpg
PASS 17 利用竞争条件绕过
可以从代码看到,文件是先上传再判断是否是合法文件,不是则将文件删除
绕过思路:可以上传一个php文件,文件的功能是写一句话木马,然后再重复访问该php文件,目的是卡在删除之前执行该文件,上传的php文件代码如下:
<?php $f= fopen ("shell.php","w") ; fputs ($f,'<?php phpinfo();?>'); ?>
PASS 18 条件竞争上传图片马
PASS 19 利用/.达到00截断的效果
move_uploaded_file会忽略掉文件末尾的/.
因此可以构造smile.php/. 达到00截断的作用
PASS 20 数组+/.绕过
$is_upload = false; $msg = null; if(!empty($_FILES['upload_file'])){ //检查MIME $allow_type = array('image/jpeg','image/png','image/gif'); if(!in_array($_FILES['upload_file']['type'],$allow_type)){ $msg = "禁止上传该类型文件!"; }else{ //检查文件名 $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name']; if (!is_array($file)) { $file = explode('.', strtolower($file)); } $ext = end($file); $allow_suffix = array('jpg','png','gif'); if (!in_array($ext, $allow_suffix)) { $msg = "禁止上传该后缀文件!"; }else{ $file_name = reset($file) . '.' . $file[count($file) - 1]; $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH . '/' .$file_name; if (move_uploaded_file($temp_file, $img_path)) { $msg = "文件上传成功!"; $is_upload = true; } else { $msg = "文件上传失败!"; } } } }else{ $msg = "请选择要上传的文件!"; }
可以发现$file_name
经过reset($file) . '.' . $file[count($file) - 1];
处理。
如果上传的是数组的话,会跳过$file = explode('.', strtolower($file));
。
并且后缀有白名单过滤。
而最终的文件名后缀取的是$file[count($file) - 1]
,因此我们可以让$file
为数组。$file[0]
为smi1e.php/
,也就是reset($file)
,然后再令$file[2]
为白名单中的jpg。
此时end($file)
等于jpg,$file[count($file) - 1]
为空。
而 $file_name = reset($file) . '.' . $file[count($file) - 1];
,也就是smi1e.php/.
,最终move_uploaded_file
会忽略掉/.
,最终上传smi1e.php
。