了解类是如何加载的
1 | //返回的系统类加载器也是AppClassLoader |
调试得知,最终是调用了ClassLoader.defineClass
方法加载的字节码文件
尝试加载任意目录的字节码文件;
1 | URLClassLoader cl = new URLClassLoader(new URL[]{new URL("file:///E:\\tmp\\")}); |
尝试直接利用反射调用ClassLoader.defineClass方法加载字节码文件
注意:倒数第二行,传递参数时;类名”Calc”也可以为空
GPT解释:将类名传入为null,这实际上是在告诉虚拟机不要使用类名来验证类定义,而是直接使用字节码数据进行类的定义。这种情况下,虚拟机会直接使用字节码数据来创建Class对象,然后将其加载到虚拟机中。
1 | ClassLoader cl = ClassLoader.getSystemClassLoader(); |
直接正着看CC3链;
TemplatesImpl
构造函数为空(并没有给一些属性值赋值)
1 | public TemplatesImpl() { } |
TemplatesImpl
下的public
修饰的newTransformer
方法,调用了getTransletInstance
方法
1 | public synchronized Transformer newTransformer() |
getTransletInstance
方法调用了defineTransletClasses
方法
1 | private Translet getTransletInstance() |
注意:
前提是_name
不为空,属性值默认是为空的,再加上构造函数什么也没干(并没有给一些属性值赋值);
所以需要反射修改_name
的值,使得值不为空
在getTransletInstance方法中还有一个实例化的操作:_class[_transletIndex].newInstance();
defineTransletClasses
方法中调用了defineClass
方法
1 | private void defineTransletClasses() |
注意:
_bytecodes
其实就是我们要加载的恶意的字节码数组,所以肯定要反射赋值;
还需要注意不能使得_tfactory
为空,否则在调用方法是会报空指针异常;
但是_tfactory
被”transient”修饰了,其实也无需担心;因为在readObject中为_tfactory 赋值了;”_tfactory = new TransformerFactoryImpl();”
还有_auxClasses
属性也调用了一个方法,也被”transient”修饰了,并且readObject
并没有对_auxClasses
属性有赋值的操作;再加上_transletIndex
默认值为-1;最后一个if语句会为真,也会抛出异常,所以尝试使得superClass.getName().equals(ABSTRACT_TRANSLET)
为真,这样就不会走到else中,也会修改_transletIndex
的值为0;
要使得字节码文件中的类的父类是AbstractTranslet
1 | private static String ABSTRACT_TRANSLET = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"; |
defineClass
最后会调用ClassLoader.defineClass
;字节码加载完之后,回到getTransletInstance
方法中调用newInstance
方法,实现实例化;
1 | Class defineClass(final byte[] b) { |
Gadget chain:
1 | ObjectInputStream.readObject() |
先生成一个字节码文件
再构造代码块中写要执行的命令(再空参函数中写也没问题);然后继承AbstractTranslet
类,这是一个抽象类,还要实现抽象方法
1 | import com.sun.org.apache.xalan.internal.xsltc.DOM; |
然后反射就是修改一下TemplatesImpl
的属性值
1 | TemplatesImpl templates = new TemplatesImpl(); |
最后还是利用CC1后半部分的链调用templates的newTransformer方法,后部分链用CC6应该可以;
1 | package demo1; |
上面的poc最后是用InvokerTransformer
类的transform调用的templates的newTransformer方法;
如果waf过滤了”InvokerTransformer”
还有一种方法可以通过InstantiateTransformer
类的transform
调用TrAXFilter
的构造方法类调用templates的newTransformer方法;
TrAXFilter
调用了newTransformer
方法,而且templates是可控的
1 | public TrAXFilter(Templates templates) throws |
1 | TemplatesImpl templates = new TemplatesImpl(); |
InstantiateTransformer
的transform方法,可以调用任意一个类的有参构造方法,所以就可以尝试调用TrAXFilter
的构造方法,并把templates传递过去
1 | public InstantiateTransformer(Class[] paramTypes, Object[] args) { |
最后将poc中的transformers数组改成下面这样,也是可以的;
1 | Transformer[] transformers = { |