2017年10月24日,Typecho被爆出install.php文件存在后门可以直接执行任意代码导致使用此系统的网站直接被getshell。
攻击难度:低。
危害程度:高。
官方修复情况如下:
https://github.com/typecho/typecho/commit/e277141c974cd740702c5ce73f7e9f382c18d84e
什么是Typecho?
Typecho 是一款博客程序,它在 GPL version 2 许可证下发行,基于 PHP (需要 PHP5 以上版本)构建,可以运行在各种平台上,支持多种数据库(Mysql, PostgreSQL, SQLite),在国内使用较广。
影响的版本
GitHub上2017年10月24日之前的所以版本。
技术分析
此漏洞的根源在于系统的安装文件install.php,因为在系统安装完之后是不会自动删除install.php文件的。
在install.php文件中,当设置了正确的referer(网站url即可),并且finish=1,然后就会执行下面这样一段代码:
在这里系统从cookie中获取了键为__typecho_config的内容,然后base64解密并且使用不安全的unserialize函数反序列化,那么我们很容易想到:如果在cookie中的__typecho_config中构造特定的数据是不是就可以执行任意PHP代码了?
下面我们就要分析系统代码,寻找并构造可以被执行的特定代码。
注意上面的代码,可以看到被反序列化后的内容$config[‘adapter’]作为构造参数进入了Typecho_Db实例中,继续跟进Db.php文件中Typecho_Db类的构造函数:
这里的$adapterName就是$config[‘adapter’],然后$adapterName进行了一个字符串拼接操作继续赋值给$adapterName。
到这里如果有经验的大佬或者脑回路够大的话会想到,如果$adapterName是一个实例对象的话,那么这里进行字符串操作就会自动调用当前实例的__toString()魔术方法,当然这也有要对对象注入有一定的了解。
不过你不了解对象注入、没有太多经验、脑回路也不够大的话那么我们审计到这里就先打一个问号,保存疑点,然后继续。
当你审计到Request.php的时候,在Typecho_Request类中发现这样一个疑点:
Call_user_func这个危险函数里面进入了两个变量,而且$filter变量是从当前类Typecho_Request的属性$this->_filter数组中遍历过来的,$value是怎么来的呢?继续看下面一段代码:
$value是从前类Typecho_Request的属性$this->_params数组中取出对应$key的值,这个$key又是什么呢?继续看下面的代码:
$key是从魔术方法__get()中进来的。
这里的魔术方法__get()是当通过类实例访问其属性的时候调用的,比如:
$payload = new Typecho_Request();
echo $payload->screenName;
这里访问类实例$payload的screenName属性时就会调用上面的魔术方法__get(),然后获取属性screenName具体的内容。
那么当Typecho_Request类被实例化的时候,它里面的属性$this->_params和$this->_filter被设置为恶意的内容,当访问$this->_params属性的内容的时候我们的恶意内容就会进入call_user_func危险函数,就可以导致任意代码执行了。
下一个问题:那里才能调用Typecho_Request类实例的$this->_params属性内容呢?继续留下疑点,然后继续分析。
在文件Feed.php中的Typecho_Feed类中定义了一个__toString()魔术方法,因为__toString()魔术方法是当其所属类实例被进行字符串操作的时候才会被调用,所以这里的Typecho_Feed肯定要被实例化然后进行字符串操作才可以的执行到__toString()里面的内容的。里面有这样一段代码:
当属性$this->_type=“ATOM 1.0”的时候,循环变量属性$this->_items的内容,然后访问$item[‘author’]的属性screenName。
又一个疑点:这里的$item[‘author’]是从属性$this->_items遍历过来的,那么要访问$item[‘author’]的属性的话,那么$item[‘author’]这个时候必定是一个类实例。
那么到这里我们将三个疑点结合起来:
第一个疑点中的可控变量$adapterName进行字符串操作时,我们将$adapterName赋值为文件Feed.php中的Typecho_Feed类实例的话,这里就会调用Typecho_Feed类的__toString魔术方法;
第二个疑点中我们把属性$this->_params和$this->_filter被设置为恶意的内容的Typecho_Request类实例赋值给第三个疑点中的$item[‘author’],当访问$item[‘author’]的属性screenName的时候就会执行到Request.php中的call_user_func危险函数,触发恶意代码的执行。
具体过程伪代码如下:
最后将构造好的内容序列化在base64编码赋值给cookie就好了。
防护方案
请升级到官方的最新版即可。
参考链接
https://github.com/typecho/typecho/issues/619
声 明
==========
本安全公告仅用来描述可能存在的安全问题,绿盟科技不为此安全公告提供任何保证或承诺。由于传播、利用此安全公告所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,绿盟科技以及安全公告作者不为此承担任何责任。绿盟科技拥有对此安全公告的修改和解释权。如欲转载或传播此安全公告,必须保证此安全公告的完整性,包括版权声明等全部内容。未经绿盟科技允许,不得任意修改或者增减此安全公告内容,不得以任何方式将其用于商业目的。
关于绿盟科技
============
绿盟科技(NSFOCUS Co., Ltd.)是中国网络安全领域的领导企业,致力于网络和系统安全问题的研究、高端网络安全产品的研发、销售与网络安全服务,在入侵检测/保护、远程评估、 DDoS攻击防护等方面提供具有国际竞争能力的先进产品,是国内最具安全服务经验的专业公司。有关绿盟科技的详情请参见: http://www.nsfocus.com