漏洞分析|Adobe ColdFusion WDDX 序列化漏洞利用

0x01 概述

在上一篇有关 Adobe ColdFusion 序列化漏洞(CVE-2023-29300)的文章中,我们对已公开的 JNDI 利用链(CVE-2023-38204)进行了复现。JNDI 利用链受目标出网的限制,在不出网的情况下无法很好地利用。本文中我们将分享不出网的利用方式,提出 C3P0 和 JGroups 两条基于服务错误部署的新利用链。经过测试,C3P0 存在被利用的可能,JGroups 利用成功率为 0.1%。尽管能被利用成功的概率较低,我们也已经在 Goby 中实现了 C3P0 和 JGroups 利用链的完整利用,完全支持命令执行以及结果回显功能。

0x02 Apache Felix

ColdFusion 通过自身实现的FelixClassloader来调用BundleClassLoader#loadClass()方法,用于启动和禁用后台一个叫做 Package Manager 的服务下载的插件,动态加载 bundles 文件夹下的各种 Jar 包。
我们可以看到这些 Jar 包的 MANIFEST 文件中多了不少字段:

Manifest-Version: 1.0
Bnd-LastModified: 1490514990031
Build-Jdk: 1.8.0_111
Built-By: uriel
Bundle-Description: Java reflect give poor performance on getter setter an constructor calls, accessors-smart use ASM to speed up those calls.
Bundle-DocURL: http://www.minidev.net/
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion: 2
Bundle-Name: accessors-smart
Bundle-SymbolicName: net.minidev.accessors-smart
Bundle-Vendor: Chemouni Uriel
Bundle-Version: 1.2
Created-By: Apache Maven Bundle Plugin
Export-Package: net.minidev.asm;version="1.2.0";uses:="org.objectweb.asm",net.minidev.asm.ex;version="1.2.0"
Import-Package: net.minidev.asm.ex;version="[1.2,2)",org.objectweb.asm;version="[5.0,6)"
Tool: Bnd-3.3.0.201609221906

搜索可知,Apache Felix 是 OSGi(Open Service Gateway Initiative,开放服务网关协议)的一种开源实现框架,通过为 Jar 包添加 metadata 来定义哪些类暴露,哪些类隐藏,来实现依赖的模块化,其控制单元就叫做 bundle。
其中最重要的就是Export-PackageImport-Package两个字段,分别用于告诉 OSGi 自己对外提供哪些类,引用了其它包的哪些类。如果没有这两个字段,OSGi 或者说它的实现 Felix 就无法正常工作。

0x03 构造利用链

3.1 Felix ClassLoader

ColdFusion 在进行 WDDX 序列化的过程中,将调用BundleClassLoader来对目标类进行加载。实现的findClass()方法如下:

protected Class findClass(String name) throws ClassNotFoundException {Class clazz = this.findLoadedClass(name);if (clazz == null) {// ...String actual = name.replace('.', '/') + ".class";byte[] bytes = null;List<Content> contentPath = this.m_wiring.m_revision.getContentPath();Content content = null;for(int i = 0; bytes == null && i < contentPath.size(); ++i) {bytes = ((Content)contentPath.get(i)).getEntryAsBytes(actual);content = (Content)contentPath.get(i);}if (bytes != null) {String pkgName = Util.getClassPackage(name);Felix felix = this.m_wiring.m_revision.getBundle().getFramework();Set<ServiceReference<WeavingHook>> hooks = felix.getHookRegistry().getHooks(WeavingHook.class);Set<ServiceReference<WovenClassListener>> wovenClassListeners = felix.getHookRegistry().getHooks(WovenClassListener.class);WovenClassImpl wci = null;// ...try {clazz = this.isParallel() ? this.defineClassParallel(name, felix, wovenClassListeners, wci, bytes, content, pkgName) : this.defineClassNotParallel(name, felix, wovenClassListeners, wci, bytes, content, pkgName);} catch (ClassFormatError var17) {// ...}// ...}}return clazz;
}

此处会将全限类名转换为相对文件路径,如传入javax.sql.ConnectionPoolDataSource,则会尝试读取相对路径javax/sql/ConnectionPoolDataSource.class文件中的字节码,之后再去defineClassParallel()方法中调用defineClass()。由于这种特殊的类加载模式,即使ConnectionPoolDataSource存于rt.jar,也会因为无法定位 class 文件而抛出NoClassDefFoundError

java.lang.NoClassDefFoundError: javax/sql/ConnectionPoolDataSourceat java.lang.ClassLoader.defineClass1(Native Method)at java.lang.ClassLoader.defineClass(ClassLoader.java:760)at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2338)at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClassParallel(BundleWiringImpl.java:2156)at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2090)at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1556)at org.apache.felix.framework.BundleWiringImpl.access$300(BundleWiringImpl.java:79)at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1976)at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
...

不过还有一种可能,如果目标类已提前被加载,ClassLoader#findLoadedClass()就会直接返回目标类,也不会进入抛出错误的分支。那么会不会有人部署服务时不走寻常路,将原本散落各处的依赖包全部集中到了自定义的 lib 中呢?
本着遵循客观事实的原则,我们进行了利用测试,结果表明的确存在可以利用的目标:
image.png
image.png
无一例外,这些目标都手动更改了服务的依赖包路径。相比使用 Package Manager 服务,他们更愿意自己手动管理依赖,这也将绕过BundleClassLoader的依赖加载机制,留给我们相当大的操作空间。

3.2 C3P0

WrapperConnectionPoolDataSourceBase#setUserOverridesAsString()方法为入口,构造的调用链如下,最后将传入的字节解码并调用原生反序列化。

WddxDeserializer-> deserialize()...WrapperConnectionPoolDataSourceBase-> setUserOverridesAsString()VetoableChangeSupport-> fireVetoableChange()VetoableChangeListener-> vetoableChange()C3P0ImplUtils-> parseUserOverridesAsString()SerializableUtils-> fromByteArray()-> deserializeFromByteArray()ObjectInputStream-> readObject()

parseUserOverridesAsString()方法将截取并 Hex 解码传入的字节流,因此我们构造原生序列化流时需要相应地填写占位和进行编码。

    public static Map parseUserOverridesAsString(String userOverridesAsString) throws IOException, ClassNotFoundException {if (userOverridesAsString != null) {String hexAscii = userOverridesAsString.substring("HexAsciiSerializedMap".length() + 1, userOverridesAsString.length() - 1);byte[] serBytes = ByteUtils.fromHexAscii(hexAscii);return Collections.unmodifiableMap((Map)SerializableUtils.fromByteArray(serBytes));}// ...}

_5db20be14d804ed14721d4d90a25560c_-1996400489_图片.gif

3.3 JGroups

和 C3P0 类似,JGroups 的ReplicatedTree#setState()方法接受字节数组参数,并调用原生反序列化,利用链如下。

WddxDeserializer-> deserialize()...ReplicatedTree-> setState()Util-> objectFromByteBuffer()-> oldObjectFromByteBuffer()ObjectInputStream-> readObject()

由于setState()方法接收的参数不是基本类型,我们需要利用<binary>标签触发BinaryHandler来传入字节数组,并进行 base64 编码。

public void onEndElement() throws WddxDeserializationException {this.setValue(Base64Encoder.decode(this.m_buffer.toString()));this.setType(-3, "VARBINARY");
}

objectFromByteBuffer()方法将根据传入的第一个字节,调用不同的readObject(),因此构造原生序列化流时还需要在首位添加一个0x2

public static Object objectFromByteBuffer(byte[] buffer, int offset, int length) throws Exception {// ...ByteArrayInputStream in_stream = new ByteArrayInputStream(buffer, offset, length);byte b = (byte)in_stream.read();// ...try {ObjectInputStream ois;switch (b) {// ...case 2:in = new ObjectInputStream(in_stream);retval = ((ObjectInputStream)in).readObject();break;// ...}// ...}// ...
}

aaa.jpg_a5b5e3b901682635665925c370e2e751_-696553035_图片(1).gif

0x04 总结

通过深入挖掘 CVE-2023-29300 的利用方式,我们摸清了产品更多的细节,如BundleClassLoader的类加载机制,并最终提出了两条不出网的利用链:C3P0 和 JGroups。虽然在默认部署环境中无法成功利用,我们最开始也不相信有人会手动破坏依赖管理机制,但事实是规则总有人打破,而这也让攻击者得以趁虚而入。
希望在阅读本篇文章后,能为大家带来一些新思路的启发。

0x05 参考链接

https://helpx.adobe.com/security.html
https://felix.apache.org/documentation/index.html


Goby 欢迎表哥/表姐们加入我们的社区大家庭,一起交流技术、生活趣事、奇闻八卦,结交无数白帽好友。

也欢迎投稿到 Goby(Goby 介绍/扫描/口令爆破/漏洞利用/插件开发/ PoC 编写/ IP 库使用场景/ Webshell /漏洞分析 等文章均可),审核通过后可奖励 Goby 红队版,快来加入微信群体验吧~~~

文章来自Goby社区成员:M1sery@白帽汇安全研究院,转载请注明出处。
微信群:公众号发暗号“加群”,参与积分商城、抽奖等众多有趣的活动
获取版本:https://gobysec.net/sale

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/123299.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线性代数的学习和整理20,关于向量/矩阵和正交相关,相似矩阵等

目录 1 什么是正交 1.1 正交相关名词 1.2 正交的定义 1.3 正交向量 1.4 正交基 1.5 正交矩阵的特点 1.6 正交矩阵的用处 1 什么是正交 1.1 正交相关名词 orthogonal set 正交向量组正交变换orthogonal matrix 正交矩阵orthogonal basis 正交基orthogonal decompositio…

iOS 16.4更新指南:问题解答与新功能一览

我应该更新到iOS 16.4吗&#xff1f;这是许多iPhone用户在新更新可用时问自己的一个常见问题。最新的iOS版本提供了各种功能和改进&#xff0c;因此更新的诱惑力很大。 但是&#xff0c;在更新之前&#xff0c;你应该考虑几个因素&#xff0c;以确保安装过程顺利成功。这些因素…

入门深度学习你不得不关注的小知识:什么是HuggingFace?

入门深度学习你不得不关注的小知识&#xff1a;什么是HuggingFace&#xff1f; 文章目录 入门深度学习你不得不关注的小知识&#xff1a;什么是HuggingFace&#xff1f;来自何方&#xff1f;核心在线平台HuggingFace Spaces社区总结 HuggingFace 是一个专注于自然语言处理&…

【Java SE】抽象类与接口

目录 【1】抽象类 【1.1】抽象类概念 【1.2】抽象类语法 【1.3】抽象类特性 【1.4】抽象类的作用 【2】接口 【2.1】接口的概念 【2.2】语法规则 【2.3】接口使用 【2.4】接口特性 【2.5】实现多个接口 【2.6】接口间的继承 【2.7】接口使用实例 【2.8】Clonable …

mybatis 数据库字段加密

目录 1、引入依赖 2、添加配置 3、指定加密字段 4、测试&#xff0c;效果 1、引入依赖 <dependency><groupId>io.github.whitedg</groupId><artifactId>mybatis-crypto-spring-boot-starter</artifactId><version>1.2.3</version>…

【前端】WebWorker 在前端SPA框架的应用

一、什么是WebWorker 概念&#xff1a; Web Worker是一种在Web浏览器中运行的JavaScript脚本&#xff0c;它可以在后台线程中运行&#xff0c;而不会阻塞主线程。这意味着Web Worker可以在后台执行复杂的计算任务&#xff0c;而不会影响用户界面的响应性能 除了标准的JavaScri…

Spring Bean 别名处理原理分析

今天来和小伙伴们聊一聊 Spring 中关于 Bean 别名的处理逻辑。 1. Alias 别名&#xff0c;顾名思义就是给一个 Bean 去两个甚至多个名字。整体上来说&#xff0c;在 Spring 中&#xff0c;有两种不同的别名定义方式&#xff1a; 定义 Bean 的 name 属性&#xff0c;name 属性…

Python 内置函数详解 (1) 数学运算

近期在外旅游,本篇是出发前定时发布的,不完整,旅游回来后再补充。 Python 内置函数 Python3.11共有75个内置函数,其来历和分类请参考:Python 新版本有75个内置函数,你不会不知道吧_Hann Yang的博客-CSDN博客 函数列表 abs aiter all …

【LeetCode-中等题】90. 子集 II

文章目录 题目方法一&#xff1a;递归加回溯&#xff08;去重版&#xff09;![在这里插入图片描述](https://img-blog.csdnimg.cn/abc4e8d0e3f940fcbdcb072acf80734e.png) 题目 本题nums数组存在重复元素&#xff0c;所以本题会涉及一个去重操作&#xff1a; 子集无需去重版本&…

系统学习Linux-zabbix监控平台

一、zabbix的基本概述 zabbix是一个监控软件&#xff0c;其可以监控各种网络参数&#xff0c;保证企业服务架构安全运营&#xff0c;同时支持灵活的告警机制&#xff0c;可以使得运维人员快速定位故障、解决问题。zabbix支持分布式功能&#xff0c;支持复杂架构下的监控解决方…

MATLAB R2023a完美激活版(附激活补丁)

MATLAB R2023a是一款面向科学和工程领域的高级数学计算和数据分析软件&#xff0c;它为Mac用户提供了强大的工具和功能&#xff0c;用于解决各种复杂的数学和科学问题。以下是MATLAB R2023a Mac的一些主要特点和功能&#xff1a; 软件下载&#xff1a;MATLAB R2023a完美激活版 …

Lua语法结构

Lua基础 注释 print("hello.") -- 单行注释的写法 --[[ 多行注释的写法 --]]标识符 关键字 **and **break**do **else**elseif ****end **falsefor**function **ifinlocalnilnotorrepeatreturnthentrueuntil**while ** 数据类型 nil** boolean**** number**** st…

Excel VSTO开发10 -自定义任务面板

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 10 自定义任务面板 自定义任务面板&#xff08;有些地方称为侧边面板&#xff09;即CustomTaskPane&#xff0c;这个类在Microsoft…

软件架构设计(六) 软件架构风格-MDA(模型驱动架构)

概念 模型驱动架构MDA, 全称叫做Model Driven Architecture。 Model:表示客观事物的抽象表示Architecture:表示构成系统的部件,连接件及其约束的规约Model Driven: 使用模型完成软件的分析,设计,构建,部署和维护等 开发活动MDA起源于分离系统规约和平台实现的思想。之前…

C++------vector【STL】

文章目录 vector的介绍及使用vector的介绍vector的使用 vector的模拟实现 vector的介绍及使用 vector的介绍 1、vector是表示可变大小数组的序列容器。 2、就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问和数…

js数据类型?如何判断js数据类型?

在JavaScript中&#xff0c;有以下几种数据类型&#xff1a; 基本数据类型&#xff08;Primitive Data Types&#xff09;&#xff1a; String&#xff08;字符串&#xff09;&#xff1a;表示文本数据&#xff0c;使用引号&#xff08;单引号或双引号&#xff09;括起来。Numb…

linux运维(二)内存占用分析

一、centos内存高&#xff0c;查看占用内存, top命令详解 1.1: free 命令是 free 单位K free -m 单位M free -h 单位Gfree最常规的查看内存占用情况的命令 1.2: 参数说明 total 总物理内存 used 已经使用的内存 free 没有使用的内存 shared 多进程共享内存 buff/cache 读写…

《TCP/IP网络编程》阅读笔记--基于 TCP 的半关闭

目录 1--基于TCP的半关闭 1-1--TCP单方面完全断开的问题 1-2--shutdown()函数 1-3--半关闭的必要性 2--基于半关闭的文件传输程序 1--基于TCP的半关闭 1-1--TCP单方面完全断开的问题 Linux 系统中的 close 函数会将 TCP Socket 的连接完全断开&#xff0c;这意味着不能收…

el-table自适应列宽实现

【背景小记】 el-table的el-table-column如果不指定width的话&#xff0c;会自动设定一个宽度&#xff0c;表格内容会自动换行&#xff0c;对强迫症用户来说非常不友好&#xff0c;为了追求完美用户体验&#xff0c;所以这里需要实现两个效果&#xff1a; 1. 强制表格内容不换…

CAS策略

CAS CAS&#xff08;Compare And Swap&#xff09;比较并交换 CAS是多线程环境下对共享变量进行修改时的一种策略&#xff0c;主要存在三个参数&#xff1a;当前值、预估值、结果 CAS采用的策略是当一个线程要对共享变量进行修改时&#xff0c;需要获取内存中共享变量的值作…