漏洞CMS
版本:V 2.0.11 https://gitee.com/hisi/hisiph
漏洞描述:
在后台上传插件处,通过上传构造的恶意zip 压缩包文件,从而获取到服务器的权限
漏洞路径
漏洞地址:/admin.php/system/plugins/import.html
漏洞代码路径:hisiphp/application/system/admin/Plugins.php
public function import()
{
if ($this->request->isPost()) {
$file = $this->request->file('file');
if (empty($file)) {
return $this->error('请上传模块安装包');
}
if (!$file->checkExt('zip')) {
return $this->error('请上传 ZIP 格式的安装包');
}
$basePath = './upload/temp/file/';
$file = $file->rule('md5')->move($basePath);
$file = $basePath.$file->getSaveName();
if (ROOT_DIR != '/') {
// 针对子目录处理
$file = realpath(str_replace(ROOT_DIR, '/', $file));
}
if (!file_exists($file)) {
return $this->error('上传文件无效');
}
$decomPath = '.'.trim($file, '.zip');
if (!is_dir($decomPath)) {
Dir::create($decomPath, 0777);
}
// 解压安装包到$decomPath
$archive = new PclZip();
$archive->PclZip($file);
if(!$archive->extract(PCLZIP_OPT_PATH, $decomPath, PCLZIP_OPT_REPLACE_NEWER)) {
Dir::delDir($decomPath);
@unlink($file);
return $this->error('导入失败('.$archive->error_string.')');
}
// 获取插件名
$files = Dir::getList($decomPath.'/upload/plugins/');
if (!isset($files[0])) {
Dir::delDir($decomPath);
@unlink($file);
return $this->error('导入失败,安装包不完整');
}
$appName = $files[0];
// 防止重复导入插件
if (is_dir(Env::get('root_path').'plugins/'.$appName)) {
Dir::delDir($decomPath);
@unlink($file);
return $this->error('插件已存在');
} else {
Dir::create(Env::get('root_path').'plugins/'.$appName, 0777);
}
// 复制插件
Dir::copyDir($decomPath.'/upload/plugins/'.$appName.'/', Env::get('root_path').'plugins/'.$appName);
// 文件安全检查
$safeCheck = Dir::safeCheck(Env::get('root_path').'plugins/'.$appName);
if ($safeCheck) {
foreach($safeCheck as $v) {
Log::warning('文件 '. $v['file'].' 含有危险函数:'.str_replace('(', '', implode(',', $v['function'])));
}
}
// 复制静态资源
Dir::copyDir($decomPath.'/upload/public/static/'.$appName, './static/plugins/'.$appName);
// 删除临时目录和安装包
Dir::delDir($decomPath);
@unlink($file);
$this->success($safeCheck ? '插件导入成功,部分文件可能存在安全风险,请查看系统日志' : '插件导入成功', url('index?status=0'));
}
$tabData = $this->tabData;
$tabData['current'] = 'system/plugins/import';
$this->assign('hisiTabData', $tabData);
$this->assign('hisiTabType', 3);
return $this->fetch();
}
代码分析:
import 函数,首先判断isPost() 方法, 也就是POST 请求
public function isPost()
{
return $this->method() == 'POST';
}
然后判断file 文件名称是否为空和后缀名,只能为zip格式
public function checkExt($ext)
{
if (is_string($ext)) {
$ext = explode(',', $ext);
}
$extension = strtolower(pathinfo($this->getInfo('name'), PATHINFO_EXTENSION));
if (!in_array($extension, $ext)) {
$this->error = 'extensions to upload is not allowed';
return false;
}
return true;
}
$file = f i l e − > r u l e ( ′ m d 5 ′ ) − > m o v e ( file->rule('md5')->move( file−>rule(′md5′)−>move(basePath); 设置文件命名类型MD5
d e c o m P a t h 变量, t r i m ( ) 函数从字符串的两端删除空白字符和其他预定义字符 D i r : : c r e a t e ( decomPath 变量, trim() 函数从字符串的两端删除空白字符和其他预定义字符 Dir::create( decomPath变量,trim()函数从字符串的两端删除空白字符和其他预定义字符Dir::create(decomPath, 0777); 创建文件夹
$archive = new PclZip(); PclZip 类主要解压zip文件
漏洞利用复现
创建zip 压缩包
用来存放恶意文件
将构造的zip压缩包上传
上传并解压的php文件路径:
/upload/temp/file/8d/2e01fe4987eb614640e9f6f4a02f57/1.php