您当前的位置: 首页 > 

合天网安实验室

暂无认证

  • 0浏览

    0关注

    748博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

typecho老版本的反序列化研究

合天网安实验室 发布时间:2018-11-21 20:19:00 ,浏览量:0

虽然自己也水了些CVE,但是并没有自己满意的、漂亮的漏洞利用链,今天呢主要是自己还没审出过反序列化漏洞,所以找了typecho老版本来审一下。

正文

在install.php第246行会反序列化操作

$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));
$type = explode('_', $config['adapter']);
$type = array_pop($type);

进Typecho_Cookie类看一下get方法

    public static function get($key, $default = NULL)
    {
        $key = self::$_prefix . $key;
        $value = isset($_COOKIE[$key]) ? $_COOKIE[$key] : (isset($_POST[$key]) ? $_POST[$key] : $default);
        return $value;
    }

这里很显然是一个获取值的。

继续看一下怎么进入到这个反序列化,这里php夹杂着html代码,不太方便看,我简单处理一下

首先

if (!isset($_GET['finish']) && file_exists(__TYPECHO_ROOT_DIR__ . '/config.inc.php') && empty($_SESSION['typecho'])) {
    exit;
}
// 挡掉可能的跨站请求
if (!empty($_GET) || !empty($_POST)) {
    if (empty($_SERVER['HTTP_REFERER'])) {
        exit;
    }
    $parts = parse_url($_SERVER['HTTP_REFERER']);
    if (!empty($parts['port']) && $parts['port'] != 80 && !Typecho_Common::isAppEngine()) {
        $parts['host'] = "{$parts['host']}:{$parts['port']}";
    }
    if (empty($parts['host']) || $_SERVER['HTTP_HOST'] != $parts['host']) {
        exit;
    }
}

这里是判断是否已经安装的,一般其他cms的写法是只判断是否已经存在了lock文件,但是这里有个可控参数,也就是我们还能进入这个install.php页面。

继续往下走,可以直接进入反序列化操作

这里还需要魔术方法,可以参考我总结的另外一篇文章 http://p0desta.com/2018/04/01/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%80%BB%E7%BB%93/

$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));
Typecho_Cookie::delete('__typecho_config');
$db = new Typecho_Db($config['adapter'], $config['prefix']);
$db->addServer($config, Typecho_Db::READ | Typecho_Db::WRITE);
Typecho_Db::set($db);

这里我首先跟的是 $db->addServer,但是当我跟到 Config.php第62到81行的时候

    public function setDefault($config, $replace = false)
    {
        if (empty($config)) {
            return;
        }
        /** 初始化参数 */
        if (is_string($config)) {
            parse_str($config, $params);
        } else {
            $params = $config;
        }
        /** 设置默认参数 */
        foreach ($params as $name => $value) {
            if ($replace || !array_key_exists($name, $this->_currentConfig)) {
                $this->_currentConfig[$name] = $value;
            }
        }
    }

只发现到这里如果类当做数组遍历的时候会触发 cureent方法,但是我全局搜 current方法并没有找到可以利用的地方。

然后继续跟一下

$db = new Typecho_Db($config['adapter'], $config['prefix']);

跟到 Db.php第114行到135行

    public function __construct($adapterName, $prefix = 'typecho_')
    {
        /** 获取适配器名称 */
        $this->_adapterName = $adapterName;
        /** 数据库适配器 */
        $adapterName = 'Typecho_Db_Adapter_' . $adapterName;
        if (!call_user_func(array($adapterName, 'isAvailable'))) {
            throw new Typecho_Db_Exception("Adapter {$adapterName} is not available");
        }
        $this->_prefix = $prefix;
        /** 初始化内部变量 */
        $this->_pool = array();
        $this->_connectedPool = array();
        $this->_config = array();
        //实例化适配器对象
        $this->_adapter = new $adapterName();
    }

危险的地方在于

$adapterName = 'Typecho_Db_Adapter_' . $adapterName;

因为 $adapterName方法是可控的,被当做字符串拼接了,那么就会触发 toString方法,简化一下

            
关注
打赏
1665306545
查看更多评论
0.0384s