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

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\0.jpg再提交post数据,那么在保存我们修改后的文件时,\0后面的所有字符将(如.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文章《尽最大可能分析上传源码及漏洞利用方式》

posted @ 2016-07-18 11:14  DaBan  阅读(1336)  评论(0编辑  收藏  举报