CC1,3,6回顾
前言
前面陆续学习了CC1,CC3,CC6,以及TemplatesImpl以及改造,有点乱,正所谓温故而知新嘛,所以这篇就回顾一下,捋一捋,解决一些细节问题。
CC1
由于CC1要介绍CC链的几个关键类,所以写了三篇
InvokerTransformer,其transform可以执行任意方法,ConstantTransformer作用是拿到一个危险类,如RunTime等等,ChainedTransformer作用是将几个Transformer串联起来
这三种搭配就可以执行任意方法
-
TransformedMap:用来修饰Map,被修饰过的Map在添加新的元素时,将可以执??个回调,也就是说可以调用其他的tramsform -
AnnotationInvocationHandler:第四点说了,触发漏洞的核心是向Map加入新的元素,在实际反序列化利用的时候,我们需要找到一个类,它在反序列化的readObject逻辑里有类似的写入操作。这个类刚好符合条件。
到这儿,算是一条完整的CC利用链了。
LazyMap:作用和TransformedMap类似,都是为了执行transform,区别就是TransformedMap是在写入元素的时候执行会transform,而LazyMap是在其get方法中执行的factory.transform- 动态代理:使用了一个动态代理的方法来调用``LazyMap#get
,原因是当我们调用某个动态代理对象的方法时,都会触发代理类的invoke`方法,并传递对应的内容
分析一下利用过程:这里1,2,3,4,5是一条利用链,逻辑很清晰。1,2,3,6,7是一条利用链。这里还是比较绕的,分析一下利用过程:
只需要找到某个地方调用了LazyMap#get方法,并且传递了任意值。
首先在readObject时,会触发AnnotationInvocationHandler#readObject方法,其中调用了this.memberValues.entrySet
而this.memberValues是构造好的proxyMap,由于这是一个代理对象,所以调用其方法时,会去调用其创建代理时设置的handler的invoke方法
proxyMap设置的handler为下面这个handler,同样是InvocationHandler这个类,接着会调用他的invoke方法
InvocationHandler#invoke的78行代码中调用了this.memberValues#get,此时的this.memberValues为之前设置好的lazymap,所以这里调用的是lazymap#get,从而触发后边的rce链。
代理后的对象叫做proxyMap,但我们不能直接对其进行序列化,因为我们入口点是 sun.reflect.annotation.AnnotationInvocationHandler#readObject ,所以我们还需要再用 AnnotationInvocationHandler对这个proxyMap进行包裹:
这里还是比较绕的,因为设置了两个handler,但是第一个handler是为了触发lazymap#get,而第二个handler实际上只是为了触发代理类所设置handler的invoke方法
接着解释一些细节的问题:
-
为什么这用反射的方式来创建AnnotationInvocationHandler的实例?
因为AnnotationInvocationHandler并不是public类,所以无法直接通过new的方式来创建其实例。
2.为什么创建handler时传入的第一个参数是Retention.class?
因为在创建实例的时候对传入的第一个参数调用了isAnnotation方法来判断其是否为注解类:
public boolean isAnnotation() {
return (getModifiers() & ANNOTATION) != 0;
}
而Retention.class正是java自带的一个注解类,所以这里可以直接用上,当然要是换成其他注解类也是ok的。
CC6
CommonsCollections1利用链,两种方法,LazyMap以及TransformedMap,但是在Java 8u71以后,这个利?链不能再利?了,主要原因是 sun.reflect.annotation.AnnotationInvocationHandler#readObject的逻辑变化了
所以关注点如何调?LazyMap#get()?
找到的类是org.apache.commons.collections.keyvalue.TiedMapEntry ,在其getValue?法中调?了 this.map.get,?其hashCode?法调?了getValue?法
又在 java.util.HashMap#readObject中就可以找到 HashMap#hash()的调?
/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashMap#readObject
java.util.HashMap#hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
*/
而ysoserial中使用HashSet.readObject()来调用
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
逻辑也很清晰
这条链是Java7和8高版本通杀
CC3
首先利?TemplatesImpl链是可以通过TemplatesImpl#newTransformer()执行代码的。
在一个为了绕过?些规则对InvokerTransformer的限制。所以CC3并没有使?到InvokerTransformer来调?任意?法,?是?到了另?个 类, com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter
这个类的构造?法中调?(TransformerImpl) templates.newTransformer(),免去了我们使?InvokerTransformer??调?newTransformer()?法这?步
?到?个新的Transformer,就是 org.apache.commons.collections.functors.InstantiateTransformer 。InstantiateTransformer也是?个实现了Transformer接?的类,他的作?就是调?构造?法.
利?InstantiateTransformer来调?到TrAXFilter的构造?法,再利?其构造?法?的templates.newTransformer()调?到TemplatesImpl?的字节码
小结
知识点比较多,每一个都捋清楚后,就可以重分发散思维,各种组合利用