前言

最近开始实习,要开始早睡早起,改善作息了~

实习主要是负责漏洞复现方面的工作,这样也蛮好,可以沉下心去审计是件很开心的事情 : )

环境搭建

在 cnvd 上看到这个 cms 的一个文件上传漏洞,白天的时候审了一下,这里总结下漏洞发生的原因。

01

迁出该 cms 的 v1.0 分支。

1
2
git clone git@github.com:lrjxgl/deituiCMs.git
git checkout 55f7

代码审计

还是从 index.php 开始,跟一遍代码逻辑。

index.php

1
2
// line 45
require("./skymvc/skymvc.php");

跟进 /skymvc/skymvc.php,其中对 gpc 中的数据做了 addslashes 处理。

02

主要关注 /skymvc/skymvc.php 中的路由逻辑。

03

在 /source/index/ 目录下主要是前台相关逻辑的代码,在 /source/admin/ 目录下是后台相关逻辑的代码。这里我们可以调用 /source/index/ 中某 xxControl 类中的 onxx 方法。

在 /source/index/ 目录下发现和上传相关的类文件为 upload.ctrl.php,类名为 uploadControl,其中有很多和上传相关的方法。大部分方法中都调用了 uploadfile 函数去处理上传相关的行为,随便拿一个 onUpload 方法来看。

04

跟进 upload 类的 uploadfile 方法。

05

先通过 umkdir 函数创建目录,接着取出文件后缀名存入 f_type 变量,之后就没有对 f_type 变量进行检查,直接拼接到最后的文件名 uploadfile 变量中,并调用 move_file 方法上传文件。

可以看到,实际上,中间有一段对文件类型进行验证的代码,跟进 getTrueType 方法。

06

其中可以看到验证文件类型的方式,而该方式可以被绕过。当我们在一张正常的图片后面加上<?php phpinfo();?>时,在该检测中仍然会被认为是一张图片。

在 getTrueType 方法中调用了 getfiletype 方法取出文件类型的简短名字。

07

取出文件类型名后,回到 uploadfile 方法的检测逻辑中。

1
2
3
4
5
$fileType=$this->getTrueType($FILE['tmp_name']); 
if(!in_array($fileType,$this->sysallowtype) || !in_array($fileType,$this->allowtype)){
@unlink($FILE['tmp_name']);
return array('err'=>'文件格式'.$fileType.'禁止上传','filename'=>$FILE['name']);
}

sysallowtype 和 allowtype 属性的值定义在 upload 类的开头。

1
2
public $allowtype=array("gif","jpg","bmp","png",'jpeg');
public $sysallowtype=array('gif','jpg','bmp','png','jpeg','txt','mpeg',"mp4","ogg",'avi','rm','rmvb','wmv','flv','mp3','wav','wma','swf','doc','pdf','zip','tar','svg');

总结一下就是,我们可以控制上传文件的后缀名,因为 uploadfile 方法并没有对该值进行检测和过滤。只是对文件类型进行白名单检测,而在图片后面添加 php 代码仍然可以通过白名单检测。

漏洞复现

先写个上传文件表单。

08

上传一张正常图片,抓包后在图片内容后面添加恶意代码。

09

在 Response 中可以取到上传文件路径。

10

该文件在 /attach/ 目录下,具体路径和日期有关。

11

漏洞补丁

在最新的 v1.2 中,可以看到在 /skymvc/library/cls_upload.php 文件的 upload 类的 uploadfile 方法中,添加了对文件后缀 f_type 变量的过滤。

12

尽管如此,但是文件类型还是 getTrueType 方法进行检测,所以我们还是可以上传一个结尾添加了恶意代码的图片,只不过后缀是白名单中的合法后缀。不过,如果我们找到一个文件包含的利用点,该上传文件仍然存在被用于 getshell 的风险。

13