与CC1和CC6不同,CC1、6是Runtime命令执行,CC3是动态类加载,能够任意代码执行。
回顾:TemplatesImpl
CC3的sink点在于 defineClass()。但如果只是加载恶意类不初始化的话,是不会执行代码的,因此还需要一个 newInstance 初始化的操作。之前学习动态加载字节码的时候也了解到,defineClass()往往都是 protected类型的,实战中很少能接触到。但是有TemplatesImpl,它的内部类TransletClassLoader继承ClassLoader并重写了defineClass()方法。这里defineClass没有声明权限修饰符,所以这里的defineClass由其父类的 protected 类型变成了一个 default 类型的方法,可以被类外部调用。

调用链:
|
|
追到最前面两个方法TemplatesImpl#getOutputProperties()和TemplatesImpl#newTransformer(),这两者的作用域都是public,可以被外部调用。这里就通过newTransformer方法来调用defineClass
CC1+TemplatesImpl
CC1是利用invoke反射调用Runtime().getRuntime().exec()执行命令,不过很多时候服务器的代码当中的黑名单会选择禁用Runtime。
|
|
那么可以想到将CC1中InvokerTransformer执行的方法替换成TemplatesImpl::newTransformer()
|
|
成功执行字节码

CC6+TemplatesImpl
同理,CC6也可以和TemplatesImpl结合起来

TrAXFilter
上述都是通过TemplatesImpl.newTransformer()来加载恶意类,还可以继续往上找,看其他调用newTransformer()的地方。ysoserial作者考虑到InvokerTransforme的使用上了黑名单,于是找到另外一个类com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter。这个类的构造方法中调用了(TransformerImpl) templates.newTransformer() ,免去了我们使用 InvokerTransformer手工调用 newTransformer() 。

没有了InvokerTransformer,想要调用TrAXFilter的构造方法,会用到新的类——org.apache.commons.collections.functors.InstantiateTransformer,它实现了Transformer接口,提供调用构造方法的功能。

编写POC
替换InvokerTransformer
|
|
成功触发

参考:
- phith0n-java代码审计
- https://www.cnblogs.com/1vxyz/p/17458691.html