一、CC2简介
CommonsCollections2
在JDK1.8 8u71版本以后,对AnnotationInvocationHandler的readobject进行了改写。导致高版本中利用链无法使用。
所以cc2版本就没用使用AnnotationInvocationHandler而使用了TemplatesImpI+PriorityQueue 来构造利用链的。
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
这个内置类, 这个类的骚操作就是,在调用他的 newTransformer 或者 getOutputProperties (这个方法内部会调用 newTransformer) 时,会动态从字节码中重建一个类.
这就使得如果我们能操作字节码, 就能在创建类时执任意 java 代码.
二、Gadget chain
1 | ObjectInputStream.readObject() |
1.1 链条方法概要(Re)
Runtime.exe():
- Java的运行时命令执行类,可以调用系统程序
Method.invoke(obj,args):
Params:
obj – the object the underlying method is invoked from
args – the arguments used for the method call
Returns:
the result of dispatching the method represented by this object on obj with parameters arg
InvokerTransformer.transform(input): 通过反射机制调用传入对象的方法
- Transforms the input to result by invoking a method on the input.
Params:
- input – the input object to transform
Returns:
- the transformed result, null if null input
**TransformingComparator.compare(obj1,obj2)**:返回两个对象通过transformer后的值的比较的结果,里面会调用rtansformer
- ```
//TransformingComparator类实现了Serializable接口
public class TransformingComparator<I, O> implements Comparator, Serializable1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- Returns the result of comparing the values from the transform operation.
- Params:
- obj1 – the first object to transform then compare
- obj2 – the second object to transform then compare
- Returns:
negative if obj1 is less, positive if greater, zero if equal
- **PriorityQueue.readObject()**: 序列化的入口
## 1.2 完整链
```java
ObjectInputStream.readObject()
|
PriorityQueue.readObject()
|
PriorityQueue.heapify
|
PriorityQueue.siftDown
|
PriorityQueue.siftDownUsingComparator
|
TransformingComparator.compare()
|
InvokerTransformer.transform()
|
TemplatesImpl.getTransletInstance()
|
->(动态创建的类)cc2.newInstance()->Runtime.exec()
- ```
1.3 TemplatesImpI类分析
这个类用来加载我们的恶意类
1.getTransletInstance()方法
1 | //This method generates an instance of the translet class that is wrapped inside this Template. The translet instance will later be wrapped inside a Transformer object. |
3.defineTransletClasses()方法
1 | //Defines the translet class and auxiliary classes. Returns a reference to the Class object that defines the main class |
从以上两个类中梳理出的思路:
getTransletInstance()方法想要创建某个类的实例,可是发现当前的类为空,所以它使用了defineTransletClassess()方法定义一个Java类,而defineTransletClassess()定义类的实现是又通过自定义的类加载器TransletClassLoader,该ClassLoader会将字节码文件转换为Java对象(类)。Java对象创建好之后,会判断该对象是不是AbstractTranslet的子类,如果是,将其标记为translet实例,如果不是,则将其放入hash表。
所以我们的目的是利用TransletClassLoader使用字节码构建Java对象的流程,让其生成我们想要生成的恶意类对象。
所以首先我们构造一个恶意类
1 | public class CC2 extends AbstractTranslet { |
然后构造POC
链子:
TemplatesImpl#newTransformer() ->TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()-> TransletClassLoader#defineClass()
1 | public class CC2Poc{ |
运行结果:
1.4 TransformingComparator类分析
TransformingComparator
是一个修饰器,和CC1中的ChainedTransformer
类似。
TransformingComparator中的comparator 在TransformingComparator的构造方法中,传入了两个值transformer和decorated
1 | public TransformingComparator(Transformer transformer) { |
TransformingComparator调用compare方法时,就会调用传入transformer对象的transform方法
具体实现是this.transformer在传入ChainedTransformer后,会调用ChainedTransformer#transform反射链
1 | public int compare(Object obj1, Object obj2) { |
我们在此可以构造 将反射调用的newTransformer传进去
1 | TransformingComparator comparator =new TransformingComparator(invokerTransformer); |
这样如果哪块调用了compare()就会调用this.invokerTransformer.transformer()
那么接下来如何调用compare()?这就需要PriorityQueue
登场了
1.5 PriorityQueue类分析
PriorityQueue是一个优先队列,作用是用来排序,重点在于每次排序都要触发传入的比较器comparator的compare()方法
在CC2中,此类用于调用PriorityQueue重写的readObject来作为触发入口
readObject中调用了heapify() ,hipify()的for循环长度是2才能满足条件 所以我们需要在创建好PriorityQueue之后再继续往里面add()添加元素
hipify()调用了siftDown():
siftdown()调用了siftDownUsingComparator():
siftDownUsingComparator()
又调用了comparator.compare() :
这里可以构造
1 | PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator); |
终极POC
1 | package CommonsCollections; |
参考
1.https://blog.csdn.net/weixin_43818995/article/details/122184245