zl程序教程

您现在的位置是:首页 >  其他

当前栏目

文件上传漏洞--进阶版 整理笔记

漏洞文件上传笔记 -- 整理 进阶
2023-09-27 14:28:02 时间

文件上传漏洞

总结

对于恶意文件上传的防范,大体分为:

前端校验

(1)前端检测文件后缀。

常用绕过:

  • 1.bp抓包后改包

  • 2.删除前端js校验函数

  • 3.构造上传表单

后端校验

(1)后缀名检测

通过函数pathinfo()获取文件后缀,将后缀转为小写后判断是不是php。一般防范思路大体分为两种,黑名单和白名单。

下面先来说一下黑名单:

1.黑名单–名单列表绕过(黑名单之外的后缀名)

有些中间件允许解析其他文件后缀名,所以上传一个后缀名为php3、phtml的文件即可,这些文件也会以php格式解析。

(还有一种是php大小写绕过,但后端拿到文件名,一般第一步就是全部转换为小写,所以这种方法没有单独列出来。)

2.黑名单–Windows特性
一些特殊的文件名命名方式在Windows下是不被允许的,利用BurpSuite抓包修改后缀名,绕过验证后上传文件,windows会自动去掉后面添加的,但要注意Unix/Linux系统没有这个特性。

注意:只能用于服务器是Windows类型的。

比如:

末尾的点(.)    【1.php.】
空格( )      【1.php  】
::$DATA        【1.php::$DATA】

以上这些上传成功后,文件名都会变成 1.php 。

3.利用apache解析特性

​ 结合Apache文件解析机制,从右向左开始解析文件后缀,若后缀名不可识别,则继续判断直到遇到可解析的后缀为止。

再来说一下白名单,这种情况一般要配合文件包含或者文件解析漏洞。

下面说一种不靠文件包含的手法:

.htaccess文件攻击
原理: .htaccess文件是Apache服务器中的分布式配置文件(IIS中不存在该文件),该配置文件会覆盖Apache 服务器的全局配置,作用于当前目录及其子目录。
如果一个Web应用允许上传.htaccess文件,那就意味着攻击者可以更改Apache的配置,这是十分危险。

攻击思路是先上传 .htaccess 文件,然后再上传恶意文件。

前提:在httpd.conf配置文件中,AllowOverride参数就是指明Apache服务器是否去找.htacess文件作为配置文件,如果设置为none,那么服务器将忽略.htacess文件;如果设置为AlI,那么所有在.htaccess文件里有的指令都将被重写,即允许.htaccess文件覆盖掉Apache的配置。 image-20220805175150513

.htaccess文件配置:

SetHandler application/ x-httpd-php
符合php语法的所有文件都能以php格式解析

SetHandler application/x-httpd-php .jpg
符合php语法的所有 .jpg 的文件都能以php格式解析(当然,只解析符合php语法的那段代码)


AddHandler php5-script .php
匹配文件名中的关键字
比如:当文件名[info.php.png]中包含关键字[.php],并且.htaccess文件内容如上,info.php.png中的代码会被执行。

<FilesMatch "sxf">
setHandler application/x-httpd-php</FilesMatch>
匹配文件名,对符合文件名的文件以php方式解析。

(2)MIME检测

MIME (Multipurpose Internet Mail Extensions)是描述消息内容类型的因特网标准。

常见的MIME类型如下:

文件扩展名Mime-Type
.js            application/x-javascript
.html          text/html
.jpg           image/jpeg
.png           image/png
.pdf           application/pdf

绕过比较简单,直接利用bp抓包,修改 Content-Type 值就可以了。

(3)文件内容检测

检测思路:

首先是检测图片用到的 getimagesize() 函数。可以利用以下代码来判断文件是不是图片:

if( !getimagesize($_FILES["file"]["tmp_name"]))
{
exit("不允许的文件");
}

然后是文件幻数检查,其实就是文件头信息,用来标识不同类型文件的。

常见的文件幻数:

JPG : FF D8 FF EO 00 10 4A 46 49 46
GIF : 47 49 46 38 39 61 (GIF89a)
PNG: 89 50 4E47

绕过思路:

一种是在php代码前添加文件幻数

还有一种1用的做多的,就是制作图片马。直接利用cmd里面的copy命令就可以。

(4)00截断检测和绕过

主要有两种类型,一种get型,一种post型。

对于get型,抓包改第一行,其实就是相当于改url:

在这里插入图片描述

对于post型,抓包后要改进制那个东西,就是bp的hex,某个地方改成00,其实就是相当于空格:

在这里插入图片描述

(5)条件竞争

本质上就是非法文件能上传,上传成功后服务器再检测文件合法性,如果判断非法,再删除文件。

而这个过程是会有时间差的,在文件上传之后,被删除之前赶快利用。

这个非法文件可以写生成新的木马文件。

这样非法文件被删了,新生成的木马文件还在服务器上。

<?php
fputs(fopen( ' ../shel1.php' , 'w '), '<?php phpinfo(); ?> ');
?>
除了上面的phpinfo,还可以写木马,不过为了躲过服务器杀毒软件的查杀,一定要尽量做多一些木马免杀技术。

pikachju闯关

(1)客户端检验

<script>
    function checkFileExt(filename)
    {
        var flag = false; //状态
        var arr = ["jpg","png","gif"];
        //取出上传文件的扩展名
        var index = filename.lastIndexOf(".");
        var ext = filename.substr(index+1);
        //比较
        for(var i=0;i<arr.length;i++)
        {
            if(ext == arr[i])
            {
                flag = true; //一旦找到合适的,立即退出循环
                break;
            }
        }
        //条件判断
        if(!flag)
        {
            alert("上传的文件不符合要求,请重新选择!");
            location.reload(true);
        }
    }
</script>

这里是单纯的前端验证,和之前的一样,前端验证等于没有。直接抓包就ok了,或者ban掉js的运行。

(2)MIME检查

    //验证一下MIME类型
    if(!in_array($_FILES[$key]['type'], $mime)){
        $return_data['error']='上传的图片只能是jpg,jpeg,png格式的!';
        $return_data['return']=false;
        return $return_data;
    }

这里直接通过抓包,修改content/type为要求的类型就可以了。其他都可以不变。

(3)getimagesize

//先验证后缀名
    if(!in_array(strtolower($arr_filename['extension']),$type)){//转换成小写,在比较
        $return_data['error']='上传文件的后缀名不能为空,且必须是'.implode(',',$type).'中的一个';
        $return_data['return']=false;
        return $return_data;
    }
    
    //验证MIME类型,MIME类型可以被绕过
    if(!in_array($_FILES[$key]['type'], $mime)){
        $return_data['error']='你上传的是个假图片,不要欺骗我xxx!';
        $return_data['return']=false;
        return $return_data;
    }
    //通过getimagesize来读取图片的属性,从而判断是不是真实的图片,还是可以被绕过的
    if(!getimagesize($_FILES[$key]['tmp_name'])){
        $return_data['error']='你上传的是个假图片,不要欺骗我!';
        $return_data['return']=false;
        return $return_data;
    }

这里的关键是getimagesize()来判断文件是不是图像。这里检查的是文件头,一般检查两个字节。

解决方法是copy合成图片马,图片在前,代码在后。