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. .net 分布式锁实现

    摘要: .net分布式锁,包括redis分布式锁和zookeeper分布式锁的.net实现. 分布式锁在解决分布式环境下的业务一致性是非常有用的. 分布式锁 经常用于在解决分布式环境下的业务一致性和协 ...

  2. IDEA快捷键(修改成eclipse版)+Templates

    快捷键:使用快捷键需要下载改建的配置文件,默认eclipse版的按键还是不全的. 链接:https://pan.baidu.com/s/17H4tFh__k6rExGpAf8NRJg 密码:rnl3 ...

  3. Linux远程开发

    Linux远程开发 通常,当我们开发Linux程序时有两种方案: 在Linux上直接编写程序并进行运行测试和调试 在Windows或Mac OS X上借助工具进行远程开发 虽然我自己是在Linux环境 ...

  4. 论文阅读 | HotFlip: White-Box Adversarial Examples for Text Classification

    [code] [pdf] 白盒 beam search 基于梯度 字符级

  5. python录音并调用百度语音识别接口

    #!/usr/bin/env python import requests import json import base64 import pyaudio import wave import os ...

  6. Linux命令---ln、readlink

    ln 无参数--------创建硬链接 -s  -------------创建软链接 用法:ln  [option]  源文件  目标文件 ln test.txt test_hard.txt 只有在同 ...

  7. iptables 命令

    NAME iptables — administration tool for IPv4 packet filtering and NAT SYNOPSIS iptables -ADC 指定链的规则 ...

  8. Spring5的总体架构图

    Spring5的主体架构图 主要是四大部分:Web.Data Access/Integration.Core Container.中间层,具体见下图:

  9. 无法执行vue初始化命令

    无法执行vue初始化命令:https://www.jianshu.com/p/9eb3cf854aa8 今天vue 初始化项目时提示错误 执行命令: npm install -g vue-cli 执行 ...

  10. ABP领域层创建实体

    原文作者:圣杰 原文地址:ABP入门系列(2)——领域层创建实体 在原文作者上进行改正,适配ABP新版本.内容相同 这一节我们主要和领域层打交道.首先我们要对ABP的体系结构以及从模板创建的解决方案进 ...