0x00  前言

今天早上看到了国内几家安全媒体发了Joomla RCE漏洞的预警,漏洞利用的EXP也在Github公开了。我大致看了一眼描述,觉得是个挺有意思的漏洞,因此有了这篇分析的文章,其实这个漏洞的分析老外在博客中也写过了,本质上这是一个Session反序列化导致的RCE漏洞,由于Joomla对于Session的特殊处理,导致漏洞触发并不需要登陆。因此成了Pre-auth RCE.

0x01 漏洞环境搭建

代码下载: https://github.com/joomla/joomla-cms/releases/tag/3.4.6

下载安装就好,要求php 5.3.10 以上,其他跟着提示走就ok 。

0x02 漏洞原理分析

  PHP对Session的存储是默认放在文件中,当有活动会话产生使用到Session时候,将会在服务端php设置好的路径写入一个文件,文件的内容为默认序列化处理器序列化后的数据。在Joomla中则改变了PHP的默认处理规则,将序列化之后的数据存放在数据库中,这步操作对应的处理函数为\libraries\joomla\session\storage\database.php 中的write:

    /**
* Write session data to the SessionHandler backend.
*
* @param string $id The session identifier.
* @param string $data The session data.
*
* @return boolean True on success, false otherwise.
*
* @since 11.1
*/
public function write($id, $data)
{
// Get the database connection object and verify its connected.
$db = JFactory::getDbo(); $data = str_replace(chr(0) . '*' . chr(0), '\0\0\0', $data); try
{
$query = $db->getQuery(true)
->update($db->quoteName('#__session'))
->set($db->quoteName('data') . ' = ' . $db->quote($data))
->set($db->quoteName('time') . ' = ' . $db->quote((int) time()))
->where($db->quoteName('session_id') . ' = ' . $db->quote($id)); // Try to update the session data in the database table.
$db->setQuery($query); if (!$db->execute())
{
return false;
}
/* Since $db->execute did not throw an exception, so the query was successful.
Either the data changed, or the data was identical.
In either case we are done.
*/
return true;
}
catch (Exception $e)
{
return false;
}
}

这里我故意将注释也贴出来,很明显作者的注释意思也写得十分明确。然后取值的时候使用的操作对应的函数是read:

/**
* Read the data for a particular session identifier from the SessionHandler backend.
*
* @param string $id The session identifier.
*
* @return string The session data.
*
* @since 11.1
*/
public function read($id)
{
// Get the database connection object and verify its connected.
$db = JFactory::getDbo(); try
{
// Get the session data from the database table.
$query = $db->getQuery(true)
->select($db->quoteName('data'))
->from($db->quoteName('#__session'))
->where($db->quoteName('session_id') . ' = ' . $db->quote($id)); $db->setQuery($query); $result = (string) $db->loadResult(); $result = str_replace('\0\0\0', chr(0) . '*' . chr(0), $result); return $result;
}
catch (Exception $e)
{
return false;
}
}

从代码中可以看出,在存入数据库之前,会将传入数据中的chr(0) . '*' . chr(0) 替换为\0\0\0, 原因是mysql数据库无法处理NULL字节,而protected 修饰符修饰的字段在序列化之后是以\x00\x2a\x00开头的。然后从数据库中取出来的时候,再将字符进行替换还原,防止无法正常反序列化。

但是这样会导致什么样的问题呢?我们首先需要了解一下PHP的序列化机制,PHP在序列化数据的过程中,如果序列化的字段是一个字符串,那么将会保留该字符串的长度,然后将长度写入到序列化之后的数据,反序列化的时候按照长度进行读取。那么结合上边说到的问题,如果写入数据库的时候,是\0\0\0, 取出来的时候将会变成chr(0) . '*' . chr(0), 这样的话,入库的时候生成的序列化数据长度为6(\0\0\0), 取出来的时候将会成为3(N*N, N表示NULL),这样在反序列化的时候,如果按照原先的长度读取,就会导致后续的字符被吃掉!那这样有什么问题呢?这里需要简单说一下PHP反序列化的特点,PHP按照长度读取指定字段的值,读取完成以分号结束,接着开始下一个,如果我们能够控制两个字段的值,第一个用来吃掉第一个字段和第二个字段中间的部分,第二个字段用来构造序列化利用的payload,那么执行将会把第一个字段开头的部分到第二个字段开始的为止当成第一个字段的内容,第二个字段内容逃逸出来被反序列化!!

说了这么多,对于理解这个漏洞已经足够了,因此我写了一个伪代码来帮助理解:

<?php

// pop 利用链
class Evil {
public $cmd; public function __construct($cmd) {
$this->cmd = $cmd;
} public function __destruct() {
// var_dump($this->cmd);
system($this->cmd);
} } // 模拟真实的登陆处理逻辑
class User {
public $username;
public $password; public function __construct($username, $password) {
$this->username = $username;
$this->password = $password;
} // public function __destruct() {
// var_dump($this->username);
// var_dump($this->password);
// }
} function write($id, $data) {
$data = str_replace(chr(0) . '*' . chr(0), '\0\0\0', $data);
$arr = array($id => $data);
file_put_contents("db.txt", json_encode($arr));
} function read($id) {
$data = file_get_contents("db.txt");
$result = json_decode($data, true);
$result = str_replace('\0\0\0', chr(0) . '*' . chr(0), $result[$id]);
return $result;
} // 发送的username 值
$username = "\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"; $password = 'AAAA";'; // padding // 构造一个fake password字段,将其内容设置为一个恶意构造的对象
$shellcode = 's:8:"password";O:4:"Evil":1:{s:3:"cmd";s:4:"calc";}'; $password = $password . $shellcode; write("123", serialize(new User($username, $password))); var_dump(unserialize(read("123"))); ?>

我将这里的write和read函数简化,数据库操作部分使用文件代替,重点我们解释一下payload的构造部分:

这里使用9组\0\0\0作为第一个参数username的值,这样的话,长度将会是54,反序列化处理时候将会变成27,吃掉后续的27个字符才是username的值。

O:4:"User":2:{s:8:"username";s:5:"admin";s:8:"password";s:7:"payload";}
";s:8:"password";s:7:" 的长度为22,\0处理完成后本身会剩下27,这样的话一共是49,还会吃掉5个字符,我们应该补5个。但是并不是这样,因此这里我写
的password的值是payload,长度是7,实际上我们的payload长度会超过10,因此生成的序列化数据就不是0-9一位数了,至少是两位数,我这里的测试案例
是刚好两位数。因此补4个字符就可以了。接着是后续的payload.关于payload的查找和利用可以参考老外的文章,这里不再赘述。 接着还有最后一个问题,反序列化触发点在哪里?这里又牵扯到Joomla的一个特性,一个未登陆的用户如果进行登陆,那么他的登陆信息也会被序列化之后存入到数据库之中。
因此这里选择登陆框进行攻击! 最后贴上一张伪代码测试成功的图:

Joomla中详细的处理流程和代码分析我就不写了,自己动手调试吧~~

0x03 参考资料

1. https://blog.hacktivesecurity.com/index.php?controller=post&action=view&id_post=41

2. https://raw.githubusercontent.com/momika233/Joomla-3.4.6-RCE/master/Joomla-3.4.6-RCE.py

Joomla 3.0.0 - 3.4.6 RCE漏洞分析记录的更多相关文章

  1. 【代码审计】YUNUCMS_v1.0.6 前台反射型XSS跨站脚本漏洞分析

      0x00 环境准备 QYKCMS官网:http://www.yunucms.com 网站源码版本:YUNUCMSv1.0.6 程序源码下载:http://www.yunucms.com/Downl ...

  2. 【代码审计】eduaskcms_v1.0.7前台存储型XSS漏洞分析

      0x00 环境准备 eduaskcms官网:https://www.eduaskcms.xin 网站源码版本:eduaskcms-1.0.7 程序源码下载:https://www.eduaskcm ...

  3. Sunlogin RCE漏洞分析和使用

    介绍   前两天网上曝出了关于向日葵远控工具(Sunlogin)Windows个人版的RCE漏洞POC.因为利用简单并且网上出现了公开的自动化扫描脚本,所以测试的人很多,也出现了一些真实攻击.漏洞的问 ...

  4. 向日葵远程RCE漏洞分析及漏洞利用脚本编写

    0x00 漏洞概述 向日葵是一款免费的,集远程控制电脑.手机.远程桌面连接.远程开机.远程管理.支持内网穿透等功能的一体化远程控制管理软件.如果想要手机远控电脑,或者电脑远控手机可以利用向日葵:如果是 ...

  5. Windows RDP的RCE漏洞分析和复现(CVE-2019-0708)

    0x00 漏洞描述 Windows系列服务器于2019年5月15号,被爆出高危漏洞,该漏洞影响范围较广如:windows2003.windows2008.windows2008 R2.windows ...

  6. Spring Core rce漏洞分析(CVE-2022-22965)

    漏洞描述: Springmvc框架参数绑定功能,绑定了请求里的参数造成变量注入,攻击者可以实现任意文件写入,漏洞点spring-beans包中. 漏洞编号: CVE-2022-22965 影响范围: ...

  7. Joomla CMS 3.2-3.4.4 SQL注入 漏洞分析

    RickGray · 2015/10/26 11:24 昨日,Joomla CMS发布新版本3.4.5,该版本修复了一个高危的SQL注入漏洞,3.2至3.4.4版本都受到影响.攻击者通过该漏洞可以直接 ...

  8. Nuxeo 认证绕过和RCE漏洞分析(CVE-2018-16341)

    简介 Nuxeo Platform是一款跨平台开源的企业级内容管理系统(CMS).nuxeo-jsf-ui组件处理facelet模板不当,当访问的facelet模板不存在时,相关的文件名会输出到错误页 ...

  9. Struts S2-048 RCE漏洞分析

    应该是S2-048目前最详细的一篇了.. 漏洞影响 Struts 2.3.x系列中的Showcase应用 使用了struts1 插件,并在使用ActionMessages时将客户端可控的参数拼接传递给 ...

随机推荐

  1. Fluent Ribbon Control Suite和AvalonDock 控件库

    Fluent Ribbon Control Suite 是一个Ribbon控件,可以用来创建Office 2010 样式的用户界面,支持MVVM,最近快要更新了,将会有Office 2013 样式的主 ...

  2. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-3.微信Oauth2.0交互流程讲解

    笔记 3.微信Oauth2.0交互流程讲解     简介:讲解微信Oauth2.0交互流程              参考:https://open.weixin.qq.com/cgi-bin/sho ...

  3. 《计算机系统要素》第四章 类汇编语言 Hack

    这章通过学习书中自己设计的Hack语言的使用,弄懂汇编语言的工作原理. 汇编语言最接近底层了,因为每个指令对应一个二进制编码. 当这些指令都变成...0101011100101...的形式后,内存Me ...

  4. mongodb全文搜索

    mongodb 的 enterprise 集合存储企业信息: { "_id" : ObjectId("5d62b2a4380d051cfc00565b"), & ...

  5. oracle数据ORA-03113:通信通道的文件到达结尾的简单处理方式

    <ORA-03113:通信通道的文件结尾>错误处理: 出现的主要原因是由于归档日志空间不够了. 解决办法: --以sysdba方式登录 sqlplus / as sysdba --关闭数据 ...

  6. centos6 安装tensorflow

    1.升级python2.6.6 至 python2.7.12+ 升级时./configure --prefix=/usr/local/python27 --enable-unicode=ucs4 2. ...

  7. Linux学习—redis安装配置及远程连接

    1.下载安装包并解压 进入文件夹/usr/local cd /usr/local 下载redis安装包: wget http://download.redis.io/releases/redis-.t ...

  8. CentOS7怎么安装图形界面

    step1: 进入下载页,选择阿里云站点进行下载 Actual  Country 国内资源                   Nearby Countries  周边国家资源 阿里云站点:http: ...

  9. 【Python】【demo实验22】【练习实例】【猴子吃桃问题】

    原题: 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到第10天早上想再吃时,见只 ...

  10. 【LOJ】#3121. 「CTS2019 | CTSC2019」无处安放

    第一次有耐心去研究一道题答-- 以前看到题答要么扔要么就水能简单手玩出来的 1 2可以手玩出来,快乐! 4呢发现3 3比较格路,就把3 3都配了,一边带个4的除了4 4都塞满这么放进去,然后把一边带2 ...