zoukankan      html  css  js  c++  java
  • upload-labs

    简介

    GitHub地址:https://github.com/Tj1ngwe1/upload-labs

    mind-map_thumb[2]

    有关php文件上传

    PHP $_FILES函数详解: (https://www.cnblogs.com/laijinquan/p/8682282.html)https://www.cnblogs.com/laijinquan/p/8682282.html

    1585471120600_thumb[2]

    pass-1 前端js验证

    前端js过滤文件后缀名,页面禁用js即可

     在这里插入图片描述

    pass-2 后端MIME验证

    • Content-Type 实体头部用于指示资源的MIME类型

    • media type ,在响应中,Content-Type标头告诉客户端实际返回的内容的内容类型。

    • 常见Content-Type https://www.cnblogs.com/klb561/p/10090540.html 源码: 

     1 $is_upload = false;
     2  $msg = null;
     3  if (isset($_POST['submit'])) {
     4      if (file_exists(UPLOAD_PATH)) {
     5          if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
     6              $temp_file = $_FILES['upload_file']['tmp_name'];
     7              $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']            
     8              if (move_uploaded_file($temp_file, $img_path)) {
     9                  $is_upload = true;
    10             } else {
    11                  $msg = '上传出错!';
    12             }
    13         } else {
    14              $msg = '文件类型不正确,请重新上传!';
    15         }
    16     } else {
    17          $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
    18     }
    19  }
    • 抓包,发现Content-Type为application/...

    • 改为图片格式image/png即绕过服务器端验证

    •  在这里插入图片描述

    pass-3 黑名单验证

    提示:不允许上传.asp,.aspx,.php,.jsp后缀文件! 未知的风险太多,黑名单过滤的结果无法预测!

     在这里插入图片描述

    源码的过滤不可绕过

     在这里插入图片描述

    • 上传如php2,php3、php4、php5这些后缀的文件,但可能无法解析, 需要配置文件中有 AddType application/x-httpd-php .php .phtml .phps .php5 .pht

    • 也可以上传如cer文件

    • 黑名单未限制.htaccess,且.htaccess有效

    .htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置.通过htaccess文件,可以实现:网页301重定向、自定义404页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能

    https://blog.csdn.net/qq_45555226/article/details/104846799 - 上传.htaccess文件,内容为 SetHandler application/x-httpd-php - 再上传php5等文件

    pass 4 黑名单验证.htaccess

    1585383895249_thumb[1]

    • 禁止上传如上这么多文件类型,依然是黑名单,但未限制 .htaccess

    • 上传内容为SetHandler application/x-httpd-php的文件,任意会解析成php类型,在上传无文件后缀的shell即可

    • 前提是配置文件有效

    pass-5 黑名单验证.user.ini.

    关于.user.ini https://segmentfault.com/a/1190000011552335?utm_source=tag-newest

    • 创建一个名为.user.ini的文件内容为

       `auto_prepend_file=1.gif`
    • 创建一句话木马命名为1.gif

    • 题目提示已经有readme.php文件

    • 将1.gif和.user.ini文件上传,访问readme.php时会自动包含1.gif文件(这里上传的文件路径未改变)

    效果如图:

    1585400719063_thumb[2]

    pass-6 黑名单-大小写绕过

    • 查看源码会发现未过滤大小写

    1585400792334_thumb[1]

    • 木马改名为1.PhP即可上传

    pass-7 黑名单-文件末尾加空格绕过

    • bp抓包文件尾加俩空格

    1585402731898_thumb[1]

    pass-8 黑名单-文件末尾加.绕过

    原理: windows会对文件中的点进行自动去除,所以可以在文件末尾加点绕过

    • bp抓包改文件名为1.php.

    1585401133710_thumb[1]

    • 可直接链接1.php

      1585401723641_thumb[2]

    pass-9 黑名单-::$DATA绕过

    原理: https://www.jianshu.com/p/b1a130902b4e

    • 抓包将文件后缀改为php::$DATA

    • 1585402299441_thumb[1]

    • 文件名经过处理

    • 1585402459250_thumb[1]

    • 访upload/upload/202003282132239300.php

      1585402512016_thumb[1]

    pass-10 黑名单- .空格.绕过

    • 代码过滤不严格 抓包改文件名为1.php. .可以绕过

    1585471645005_thumb[2]

    pass-11 黑名单-双写绕过

    • 源码中采用黑名单,str_ireplace()不区分大小写替换掉黑名单中存在的后缀

     1 $is_upload = false;
     2  $msg = null;
     3  if (isset($_POST['submit'])) {
     4      if (file_exists(UPLOAD_PATH)) {
     5          $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini");
     6  7          $file_name = trim($_FILES['upload_file']['name']);
     8          $file_name = str_ireplace($deny_ext,"", $file_name);
     9          $temp_file = $_FILES['upload_file']['tmp_name'];
    10          $img_path = UPLOAD_PATH.'/'.$file_name;        
    11          if (move_uploaded_file($temp_file, $img_path)) {
    12              $is_upload = true;
    13         } else {
    14              $msg = '上传出错!';
    15         }
    16     } else {
    17          $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    18     }
    19  }
    • 重命名shell为 1.pphphp 即可绕过

    pass-12白名单- 00截断%00

    php版本要小于5.3.4,5.3.4及以上已经修复该问题

    magic_quotes_gpc需要为OFF状态

    用法: https://www.fujieace.com/penetration-test/file-upload-00.html

    原理剖析: https://cloud.tencent.com/developer/article/1378895

    • 抓包发现上传路径

    1585473418934_thumb

    • 改shell名为1.jpg

    1585473535261_thumb[1]

    • 抓包修改save_path = ../upload/1.php%00

    pass-13 白名单-00截断

    • 抓包改上传路径

    1585476817046_thumb[1]

    pass-14 检查文件头

    • 检查前两个字节看是否是图片类型

     function getReailFileType($filename){
         $file = fopen($filename, "rb");
         $bin = fread($file, 2); //只读2字节
         fclose($file);
         $strInfo = @unpack("C2chars", $bin);    
         $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
         $fileType = '';    
         switch($typeCode){      
             case 255216:            
                 $fileType = 'jpg';
                 break;
             case 13780:            
                 $fileType = 'png';
                 break;        
             case 7173:            
                 $fileType = 'gif';
                 break;
             default:            
                 $fileType = 'unknown';
            }    
             return $fileType;
     }
    • 直接用bat生成图片马,直接上传

    1585482502576_thumb

    1585482437155_thumb

    pass-15 getimagesize() 绕过

    getimagesize() : http://c.biancheng.net/view/6259.html

    • 使用getimagesize()检查图片

    1585483641665_thumb[1]

    • 绕过方法同上,制作图片马即可

    pass-16 exif_imagetype()

    exif_imagetype() : https://www.php.net/manual/zh/function.exif-imagetype.php

    • 绕过方法同上

    pass-17 二次渲染

    • 图片上传后,服务端会重新进行渲染,木马可能会遭到破坏

    1585483924172_thumb[1]

    • 绕过思路是对比原图片与上传后的图片,看看哪部分没有变

    备份链接:https://files.cnblogs.com/files/l0nmar/upload-labs%E4%B9%8Bpass.rar

    pass-18 条件竞争

    unlink:删除文件 https://www.w3school.com.cn/php/func_filesystem_unlink.asp

    PHP strrpos() 函数:https://www.w3school.com.cn/php/func_string_strrpos.asp

    strrpos() 函数查找字符串在另一字符串中最后一次出现的位置. 对大小写敏感.

    PHP move_uploaded_file() 函数 :https://www.w3school.com.cn/php/func_filesystem_move_uploaded_file.asp

     move_uploaded_file(file,newloc)
         file-必需-规定要移动的文件。
         newloc-必需-规定文件的新位置。
    • 审计源码可以发现 , `move_uploaded_file($temp_file, $upload_file)`

    $is_upload = false;
     $msg = null;
     ​
     if(isset($_POST['submit'])){
         $ext_arr = array('jpg','png','gif');
         $file_name = $_FILES['upload_file']['name'];
         $temp_file = $_FILES['upload_file']['tmp_name'];
         $file_ext = substr($file_name,strrpos($file_name,".")+1);
         $upload_file = UPLOAD_PATH . '/' . $file_name;
     ​
         if(move_uploaded_file($temp_file, $upload_file)){
             if(in_array($file_ext,$ext_arr)){
                  $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
                  rename($upload_file, $img_path);
                  $is_upload = true;
            }else{
                 $msg = "只允许上传.jpg|.png|.gif类型文件!";
                 unlink($upload_file);
            }
        }else{
             $msg = '上传出错!';
        }
     }
    • 利用思路: 在删除$upload_file之前进行访问shell

    • 随笔选一个参数爆破

    • 1585487585558_thumb[2]

    • 开始爆破后不停刷新页面,手速够快是可以刷出来phpinfo(),可以开两个爆破,一个请求页面,一个上传竞争

    pass-19 条件竞争

    • 源码如下:

    //index.php
     $is_upload = false;
     $msg = null;
     if (isset($_POST['submit']))
     {
         require_once("./myupload.php");
         $imgFileName =time();
         $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
         $status_code = $u->upload(UPLOAD_PATH);
         switch ($status_code) {
             case 1:
                 $is_upload = true;
                 $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
                 break;
             case 2:
                 $msg = '文件已经被上传,但没有重命名。';
                 break; 
             case -1:
                 $msg = '这个文件不能上传到服务器的临时文件存储目录。';
                 break; 
             case -2:
                 $msg = '上传失败,上传目录不可写。';
                 break; 
             case -3:
                 $msg = '上传失败,无法上传该类型文件。';
                 break; 
             case -4:
                 $msg = '上传失败,上传的文件过大。';
                 break; 
             case -5:
                 $msg = '上传失败,服务器已经存在相同名称文件。';
                 break; 
             case -6:
                 $msg = '文件无法上传,文件不能复制到目标目录。';
                 break;      
             default:
                 $msg = '未知错误!';
                 break;
        }
     }
     ​
     //myupload.php
     class MyUpload{
     ......
     ......
     ...... 
       var $cls_arr_ext_accepted = array(
           ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
           ".html", ".xml", ".tiff", ".jpeg", ".png" );
     ​
     ......
     ......
     ......  
       function upload( $dir ){
         
         $ret = $this->isUploadedFile();
         //is_uploaded_file() 函数检查指定的文件是否是通过 HTTP POST 上传的。如果文件是通过 HTTP POST 上传的,该函数返回 TRUE。
         if( $ret != 1 ){
           return $this->resultUpload( $ret );
        }
     ​
         $ret = $this->setDir( $dir );
         if( $ret != 1 ){
           return $this->resultUpload( $ret );
        }
     ​
         $ret = $this->checkExtension(); //检查扩展名
         if( $ret != 1 ){
           return $this->resultUpload( $ret );
        }
     ​
         $ret = $this->checkSize(); //检查大小
         if( $ret != 1 ){
           return $this->resultUpload( $ret );    
        }
         
         // if flag to check if the file exists is set to 1
         
         if( $this->cls_file_exists == 1 ){
           
           $ret = $this->checkFileExists();
           if( $ret != 1 ){
             return $this->resultUpload( $ret );    
          }
        }
     ​
         // if we are here, we are ready to move the file to destination
    $ret = $this->move();
         if( $ret != 1 ){
           return $this->resultUpload( $ret );    
        }
     ​
         // check if we need to rename the file
    if( $this->cls_rename_file == 1 ){
           $ret = $this->renameFile();
           if( $ret != 1 ){
             return $this->resultUpload( $ret );    
          }
        }
         
         // if we are here, everything worked as planned :)
    return $this->resultUpload( "SUCCESS" );
       
      }
     ......
     ......
     ...... 
     };
    
    • 对文件进行了大小,扩展名等等检查,最后重命名

    • 条件竞争会存在不重命名的情况

    • 原理不太清楚...

    pass-20 加.绕过

    • 文末加点windows下会自动忽略

    • 源码中用phpinfo()获取文件名

    1585489076824_thumb[1]

    • 加点Windows下自动忽略会使其获得的文件路径为空,从而通过验证

    1585489017100_thumb[1]

    pass-21 白名单-数组绕过

    • 源码如下:

    ```
    
     $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));
            }// 如果不是数组就用explode()分割为数组,以 .分割 
    $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 = "请选择要上传的文件!";
     }
    ```
    • 先修改MIME绕过

    • 再构造数组第一个元素为1.php,第三个为jpg

    • 拼接为1.php+空=1.php

    1585490190350_thumb[2]

  • 相关阅读:
    js引用类型赋值不改变原对象值
    VS2017启动实例调试(谷歌浏览器)闪退问题
    ext6时间控件(带时分秒)
    extjs列表中文件上传与下载(带有重命名操作)
    c# word(1) 向标签处添加文字
    关于页面加载后执行使用afterrender
    ExtJS,grid多选框列
    vue起手式
    Javascript诞生与历史
    markdown语法说明
  • 原文地址:https://www.cnblogs.com/l0nmar/p/12804174.html
Copyright © 2011-2022 走看看