文件上传方法总结

以upload-labs讲解   

项目地址https://github.com/c0ny1/upload-labs/releases

每道题都要通过上面这张图判断文件校验的方式,才能有大体绕过思路


PASS 01      前端js校验

image尝试上传符合条件的文件,将一句话木马后缀改为jpg,抓包修改成php文件。

PASS 02       MIME文件类型校验

image

提示文件类型不正确,可能是MIME校验

image

image


PASS 03        php多种扩展名绕过

上传php文件时出现提示,php被加入了黑名单,并且会将上传的文件重新命名,无法通过上传.htaccess文件绕过,大小写失败了,尝试上传php3,phtml等其他扩展名文件绕过黑名单限制

image

image


PASS 04     上传.htaccess文件绕过

image

通过上传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[空格]

image


PASS 07       Windows特性文件命名规则

原理同pass 06,通过Windows文件命名规则绕过,抓包将文件改为1.php.即可

综合pass06和pass07,碰到此类型的都可以将文件修改为1.php[空格].


PASS 08      Windows特性   ::$DATA绕过

在php+Windows的情况下:如果文件名+"::$DATA" 会把 "::$DATA"之后的数据当成文件流处理,不会检测后缀名且保持”::$DATA”之前的文件名

抓包修改1.php为如图所示

image

上传成功后查看链接,链接为http://192.168.135.144/upload/202004231705477566.php::$data

查看http://192.168.135.144/upload/202004231705477566.php 即为已上传文件

image


PASS 09

从源码可以看出这次拼接的路径是$file_name的值,结合Windows特性构造文件

image

image

image


PASS 10     后缀名双写绕过

通过上传1.php文件后查看文件后缀.php被过滤,猜测可能之过滤一次,尝试双写后缀名绕过,这里双写要注意:1.pphphp和1.phphpp产生的文件是不同的,过滤是从左往右的,所以1.phphpp会生成文件1.hpp

image


PASS 11     %00截断绕过

通过测试得知是后端白名单限制,对内容并未过滤

image

image

代码分析发现最终返回的图片链接是”存储路径名+重命名后的文件名“,看到这个我们可以联想到使用%00截断路径。

截断条件:1.php版本小于5.3.4        2.php.ini的magic_quotes_gpc为OFF状态(默认为OFF)

image

image

访问链接http://192.168.135.144/upload/1.php  上传成功

image


PASS 12     %00截断绕过

image

同pass 11一样使用00截断绕过,但这里是通过POST方式,由于POST不像GET可以自动解码%00,所以需要手动解码,如下

image

image

访问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

802776a027b4b20d43c42b91f8e7ce2a

PNG和JPG通过脚本可以生成,使用方法:

1.先将一张正常的jpg图片上传,上传后将服务器存储的二次渲染的图片保存下来。

2.将保存下来经过服务器二次渲染的那张jpg图片,用脚本进行处理生成payload.jpg

3.然后再上传payload.jpg


PASS 17  利用竞争条件绕过

可以从代码看到,文件是先上传再判断是否是合法文件,不是则将文件删除

image

绕过思路:可以上传一个php文件,文件的功能是写一句话木马,然后再重复访问该php文件,目的是卡在删除之前执行该文件,上传的php文件代码如下:

<?php

fputs(fopen('eval.php','w'),'<?php eval($_POST[cmd]);?>');

?>

<?php $f= fopen ("shell.php","w") ; fputs ($f,'<?php phpinfo();?>'); ?>


PASS 18   条件竞争上传图片马


PASS  19   利用/.达到00截断的效果

move_uploaded_file会忽略掉文件末尾的/.

image

因此可以构造smile.php/. 达到00截断的作用image.png



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

image.png

image.png

posted @ 2020-04-24 15:50  我要变超人  阅读(1206)  评论(0编辑  收藏  举报