• owasp top10 之文件上传漏洞简析


    0x01:

    文件上传漏洞起因于,上传程序没有对上传文件格式进行正确判断,导致可执行程序上传到网站目录。

    常见的验证上传文件有两种:1.js本地验证,通过js获取上传文件后缀名,并和白名单比较,匹配则上传成功。由于js代码是本地验证,存在绕过风险(去除js代码,构造表单数据,直接绕过)。

    2.后端程序验证,通过post数据到file_upload()函数,$_FILES['file']['type']判断上传程序后缀名.

    function file_upload(){

      $file_name = $_FILES['file']['name'];

      $file_type = $_FILES['file']['type'];

      $file_tmp = $_FILES['file']['tmp_name']; //临时文件存放位置

      //判断文件后缀

     问题1. if($file_type === 'image/jpg' || $file_type === 'image/jpeg'){ //jpg和jpeg类型,详见wiki  

     问题2.     $file_new_type = '.jpg';

        }

     问题4.      $file_name = substr(md5(time()),0,10);

       move_uploaded_file($file_tmp,$file_name.$file_type) ;

    }

    关于PHP处理文件流,详见w3chool php file

    问题1.$file_type获取文件后缀名,正常上传jpg时,$file_type ='image/jpg' 文件格式,上传php文件时,$file_type ='application/octet-stream'(任意二进制流)。这里的image/jpg,application/octet-stream属于MIME(Multipurpose Internet Mail Extensions),在浏览器里上传抓包时,有个content-type:image/jpg,值得就是header里MIME类型(问题3).

    通过获取$file_type里的值,和白名单(image/jpg,image/jpeg)比较,如果值相同,说明后缀名是jpg(不考虑问题3)。

    问题3(MIME头欺骗).既然获取MIME里的文件类型和白名单比较,通过修改数据包中Content-type:image/jpg(修改MIME类型),上传文件。

    上传a.php,burpsuite截断数据包,修改content-type:application/octet-stream => image/jpg,然后转发。这时,$file_type='image/jpg',本来上传的php文件,获取的文件类型为二进制流,现在修改MIME后变成image/jpg。如果直接用$file_type作为文件的后缀名,就会造成a.php文件直接存储到网站目录中,造成getshell。

    问题2.获取MIME类型为image/jpg,并不代表无法解决MIME欺骗问题,这里采用文件重命名,$file_type = jpg,那么$file_new_type = '.jpg';通过拼接文件名,即使上传的php文件,最后存储到网站目录里的也是jpg文件类型。

    0x02:

    文件上传漏洞产生来源于过滤不严,很多人采用strpos($str,'.')这种方式截取文件后缀名,然后就出现了xx.php;.jpg之类的畸形文件名(问题4)。最简单防护方式就是直接重命名文件名(全部),可能有人觉得问题2里,写多个判断语句会很麻烦,代码能安全一点,多写点不费事。

    swicth($file_type){

      case 'image/jpg':

      $file_new_type ='.jpg';break;

      case 'image/jpeg':

      $file_new_type ='.jpeg';break;

      ....

      default:

      $file_new_type = false;  

    }

    这里获取文件后缀名之后,重命名文件,有人担心,含有一句话代码的图片存储到网站里,不用考虑上传的是什么文件,当程序判断文件属于白名单里的后缀时,直接使用白名单里后缀写法,这样即使这个文件含有一句话,但服务器会把它当作图片处理,并不会执行里的代码(问题5)

    文件名重命名一般采用:upload/时间/时间种子的MD5.后缀名

    具体代码:

    $file_save_directory = 'upload'.date('Y-m-d',time()); //命名存储文件夹名

    if(!file_exists($file_save_directory)){

      mkdir($file_save_directory); //如果不存在 创建文件夹

    }

    $file_new_name = substr(md5(time()),0,10).$file_new_type; //重命名文件名字

    $result = move_uploaded_file($file_tmp,$file_save_directory.'/'.$file_new_name);

    if($result){echo "upload success"} 

    0x03

    php上传文件漏洞已经有很多年历史了,大牛前几天发出了个CVE-2006-7243的php空字符处理问题(webshell.cc),由于php处理a.phpx00.jpg时,会保存成a.php文件,导致畸形文件名的php文件能上传成功,有兴趣的可以搭环境测试下。

    文件上传的同时伴随着文件名解析漏洞。IIS/Apache/Nginx,对畸形文件名处理错误,导致a.php;jpg/a.php .jpg(0x00截断)上传成功并解析

    参考:wooyun php安全编码 

     http://zone.wooyun.org/content/1910 php上传缺陷

  • 相关阅读:
    在Web服务调试时,出现IIS配置错误的相应解决办法
    Eclipse解决Launch error: Failed to connect to remote VM [duplicate]
    在Eclipse中应该怎样去修改Android应用程序的包名(注意按步骤修改)
    用Fragment实现Tab页面切换效果初步总结
    与像素无关的dp单位与像素单位px之间的转换
    在Andorid开发项目中遇到的Bug记录(续)
    java邮件
    图片上传实例
    java多线程总结一:线程的两种创建方式及优劣比较
    java多线程总结二:后台线程(守护线程)
  • 原文地址:https://www.cnblogs.com/developd/p/4662992.html
Copyright © 2020-2023  润新知