本文最后更新于:星期一, 四月 27日 2020, 6:09 晚上

文件上传漏洞

漏洞原理

网站WEB应用存在一些文件上传功能,如文档、头像、图片、视频上传等,但是上传文件时,服务端代码对客户端上传的文件没有进行严格的校验和过滤,就可能导致可以上传任意文件。

危害

通过这个漏洞,非法用户可以上传恶意脚本文件(webshell),通过webshell来控制整个网站,可以实现查看服务器目录、文件、执行系统命令等操作。

上传检测流程

  • 客户端
    • JavaScript检测文件扩展名
  • 服务端
    • 服务端MIME类型检测(检测Content-Type内容)
    • 服务端目录路径检测(检测Path参数相关的内容)
    • 服务端文件扩展名检测
    • 服务端文件内容检测(检测文件头或者是否包含恶意代码)

绕过方法

  1. 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检测,再抓包,将后缀名修改为可执行脚本的后缀名。

  1. 文件类型绕过

    如果服务端是通过Content-Type来判断文件类型的话,只要抓包修改它的值为允许的值就可以绕过了

  1. 服务端文件扩展名绕过

    服务端文件扩展名检测有两种检测方法:

    1. 黑名单检测

      黑名单检测会检测上传的文件是否是包含在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.");
      }
      
    2. 白名单检测

      白名单检测会只允许用户上传指定类型的文件,如: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,默认对文件解析规则如下:

    image-20200425205152383

  • .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

  1. 服务端文件内容检测绕过

    • 文件头检测

      服务端只检测了文件头,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

  2. 条件竞争绕过

    一些网站上传文件的逻辑是先允许上传任意文件,然后检查上传文件是否包含webshell,如果包含则删除该文件。这里存在条件竞争,文件上传成功后和删除文件之间存在时间差,利用这个时间差可以生成一个新的webshell

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

解析漏洞

解析漏洞是指服务器对http请求处理不当导致将非可执行的文件当作可执行的脚本来执行,一般配合文件上传功能使用。

IIS
  • IIS6.0

    目录解析

    在网站下建立的文件夹的名称中带有.asp、.asa等可执行脚本文件后缀的文件夹,其目录下的任何扩展名文件都会被IIS当作可执行脚本来解析并执行。

    www.demo.com/shell.asp/shell.jpg

    文件解析

    服务器默认不解析;后的内容,所以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


WEB     

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!