• 尽最大可能分析上传源码及漏洞利用方式


    0x00 简单源码分析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    <?php
    if ((($_FILES["file"]["type"] == "image/gif")       //检测Content-type值
    || ($_FILES["file"]["type"] == "image/jpeg")
    || ($_FILES["file"]["type"] == "image/pjpeg"))
    && ($_FILES["file"]["size"] < 20000))              //检测文件大小
      {
      $ext = end(explode('.', $_FILES["file"]["name"]));  //获取最后“.”的后缀
      if($ext === 'php')                          //检测是否为php后缀
        {
        exit('error');
        }
      if ($_FILES["file"]["error"] > 0)           //返回上传错误码
        {
        echo "Return Code: " . $_FILES["file"]["error"] . "<br />";
        }
      else                                                  //返回上传成功信息
        {
        echo "Upload: " . $_FILES["file"]["name"] . "<br />";
        echo "Type: " . $_FILES["file"]["type"] . "<br />";
        echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
        echo "Temp file: " . $_FILES["file"]["tmp_name"] . "<br />";
     
        if (file_exists("upload/" . $_FILES["file"]["name"]))  //检测文件是否存在
          {
          echo $_FILES["file"]["name"] . " already exists. ";
          }
        else                          //将上传的临时文件转移到指定存放文件夹
          {
          move_uploaded_file($_FILES["file"]["tmp_name"],
          "upload/" . $_FILES["file"]["name"]);
          echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
          }
        }
      }
    else
      {
      echo "Invalid file";              //返回无效文件的错误信息
      }
    ?>

    0x01 详细分析过程

    1) 直接使用用户上传文件名,没有过滤特殊字符,存在漏洞

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if ((($_FILES["file"]["type"] == "image/gif")            //文件类型检测
    || ($_FILES["file"]["type"] == "image/jpeg")
    || ($_FILES["file"]["type"] == "image/pjpeg"))
    && ($_FILES["file"]["size"] < 20000))
      {
      $ext = end(explode('.', $_FILES["file"]["name"]));  //文件后缀检测
      if($ext === 'php'){
         
        exit('error');
      }
     
          ......                                      //省略了中间的一些代码

    以下代码的作用是,将上传到临时文件夹的文件移到upload的目录下

    1
    2
    3
    4
    5
    6
    else                                            
     {
     move_uploaded_file($_FILES["file"]["tmp_name"],
     "upload/" . $_FILES["file"]["name"]);
     echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
     }

    1.1分析:

    从以上代码可以看出,可以上传图片文件,对文件拓展名检测是通过end(explode(‘.’,$_FILES[“file”][“name”]))函数实现(在这里先不说文件类型验证的问题)explode(‘.’,$_FILES[“file”][“name”])用来把上传的文件名作为字符串,以.(点)来分割字符串来生成数组,而end()函数则是将数组内部指针指向最后一个元素,并返回该元素的值,例如,当上传x.php文件时,最终就会获取到php。

    而对于$_FILES里面获取变量,是直接来自http request请求,它跟普通获取其它get,post变量一样。 比如在post上传时,我们可以通过抓包来截获(常用神器burpsuite)这一过程,由于在上传的检测中没有对文件名进行检测和过滤及处理,因此,我们可以将name构造一个特殊文件名,然后,再将post数据提交,就可以达到上传绕过对文件扩展名的检测。

    1.2利用:

    比如我们可以在本地上将一个php文件命名为x.php.jpg在上传文件时,抓包post,将filename修改为x.php.jpg再提交post数据,那么在保存我们修改后的文件时,后面的所有字符将(如.jpg)被自动截断,最终生成我们想要目标文件格式(如本例的x.php),以至于可以上传任意恶意的php脚本。从网上得到说明Php4的版本可以利用这个漏洞,php5版本以上会自动过滤掉’”/0”,另外很多asp,jsp也存在此类截断上传的漏洞。

    2)文件类型验证不严格,存在漏洞

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    if ((($_FILES["file"]["type"] == "image/gif")
    || ($_FILES["file"]["type"] == "image/jpeg")
    || ($_FILES["file"]["type"] == "image/pjpeg"))
    && ($_FILES["file"]["size"] < 20000))
      {
      $ext = end(explode('.', $_FILES["file"]["name"]));
      if($ext === 'php'){  
        exit('error');
      }

    2.1分析:

    从代码可以看出是通过读取文件的type直接来做文件类型的判断,同样我们可以通过抓取post数据,将Content-type值修改为允许上传的MIME类型,在这里有image/gif等三种,从而绕过对文件type的检查,虽然之后代码对文件扩展名进行了检测(那两个个函数对文件扩展名检测的大慨过程就是判断文件名最后”.”的最后字符,example.php.bak最终得到是bak),并判断是否是php后缀名。

    2.2利用:

    1.如果没有对apache默认支持解析文件方式进行修改时(即apache解析漏洞,很多网站管理员由于安全意识薄弱或其他情况往往没有修改),那么在绕过对type的检测之后,最简单的利用方式就是我们可以直接上传一个恶意的名为x.php.ext,这里的ext可以是多种,只要不是php和apache可以解析其他扩展名(如txt后缀)就可以,那么按照apache默认从右往左直到遇到可支持解析的文件的解析方式,那么就会把x.php.ext当成x.php来解析。

    2.在绕过对文件type检查之后,我们还可以将本地的x.php文件修改为x.php1,x.php3,x.php4或者x.php5再上传,默认的apache服务器将会解析为php。

    3)使用php的全等于来判断是否为php文件类型,存在漏洞

    1
    2
    3
    4
    $ext = end(explode('.', $_FILES["file"]["name"]));
    if($ext === 'php'){    
        exit('error');
      }

    3.1分析:

    我们知道在php语法中全等于”===”的作用是先判断等号左右两边的数据类型是否一样,再判断等号两边的值是否相等,如果都相等返回true,否者返回false。

    3.2利用:

    在明白全等于”===”的判断原理之后,我们就可以进行利用了,还是以本地的x.php举例,我们可以将x.php修改为Php, x.PHp, PHP...在绕过对type的检测之后再上传,以上传的x.PHP来分析,首先上传截获到的是PHP后缀,此时$ext=PHP,再将进行下一步的验证,$ext和php都是相同的数据类型,但是在验证它们值时却不相等,从而绕过上传。

    而默认的web应用程序都是默认将Php,x.PHp,PHP...解析为php执行。

    4)对上传文件内容没有做检测,存在漏洞

    4.1分析:

    从upload.php源代码分析来看,在整个过程没有对上传文件内容进行检测,过滤和处理,可以通过上传图片木马或其他方式来到达恶意上传的目的。

    4.2利用:

    1.如果的网站是用Nginx的Web应用程序且版本 <8.03,那我们就可以利用Nginx默认开启Fast-CGI而造成的畸形解析漏洞,以下是具体利用方式说明。在默认Fast-CGI开启状况下,我们可以上传一个名为x.jpg,其内容为

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

    的文件,之后我们再访问x.jpg/.php这个网站路径,在这个目录下就会生成一句话木马shell.php。

    2.如果的网站是用Nginx的Web应用程序且版本在(0.5.,0.6.,0.7,0.8<=0.7.65<=0.8.37)其中,那我们还可以利用Nginx空字节代码执行漏洞来达到上传任意恶意代码并执行。具体利用方法是:将x.jpg图片中嵌入PHP代码然后通过访问x.jpg%00.php来执行其中的恶意代码。

    3.如果网站的Apache Web应用程序中.htaccess可被执行且可被上传,那可以尝试在.htaccess中写入:
    <FilesMatch "example.jpg"> SetHandler application/x-httpd-php 
    这段代码的意思就是将把目录下的所有后缀为jpg的文件当做可执行的php脚本进行解析并执行。因此,我们可以上传一个x.jpg的木马, 这样x.jpg就可解析为php文件。

    转载请注明来自4ido10n's Blog文章《尽最大可能分析上传源码及漏洞利用方式》

  • 相关阅读:
    js 截取指定的字符串
    WebSocket实例 Vue中使用websoket
    Vue 水半球样式、圆形水进度条、在线编辑
    Elasticsearch学习笔记3 -- 文档操作
    Elasticsearch学习笔记2 -- 索引库的操作
    Elasticsearch学习笔记1 -- 安装elasticsearch
    Docker学习笔记5 -- Docker-compose
    Docker学习笔记4 -- Dockerfile
    Docker学习笔记3 -- 数据卷
    Docker学习笔记2 -- 常用命令
  • 原文地址:https://www.cnblogs.com/daban/p/5680525.html
Copyright © 2020-2023  润新知