Java反序列化学习之CommonsCollections3
前言
在分析 yesoserial CommonsCollections3 在构造Runtime类时候并未调用transform方法中的反射类,而是使用javassist创建类并执行Runtime.exec(‘evil’);
环境依旧是jdk7;commons-collections3.1
javassist知识
pom.xml(Maven下载javassist)
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.19.0-GA</version>
</dependency>
Test.java
package com.bqt.test;
public class test {
public void hello(String s) {
System.out.println(s);
}
}
Persion.java
其中需要关注的是调用makeClassInitializer().insertBefore()能够创建staic代码块,JVM加载类时会执行这些静态的代码块
import com.bqt.test.test;
import javassist.*;
import java.io.IOException;
public class Person {
public static void main(String[] args) throws CannotCompileException, IOException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.bqt.test.test");
//修改hello方法代码块
CtMethod cm = cc.getDeclaredMethod("hello", new CtClass[] { pool.get("java.lang.String") });
cm.setBody("{" + "System.out.println(\"你好:\" + $1);System.out.println(\"你好:\" + \"fuck\");" + "}");
//创建static代码块
String staticSrting = "System.out.println(\"evil run\");";
cc.makeClassInitializer().insertBefore(staticSrting);
cc.writeFile("d:/test");//保存到指定目录
cc.toClass(); //加载修改后的类,注意:必须保证调用前此类未加载
new test().hello("你大爷");
}
}
Test.class反编译结果
Ysoserial CommonsCollections3
CommonsCollections3 后半段构造与CommonsCollections1构造相同,这里主要分析框出的两处不同点。
InvokerTransformer
类替换为InstantiateTransformer
类,传入的object类为自建的templatesImpl。
new ConstantTransformer(TrAXFilter.class)
会返回一个TrAXFilter.class
对象
跟进下CreateTemplatesImpl
类具体构造
将
java.lang.Runtime.getRuntime().exec
载入static代码块设置
absTranslet
(org.apache.xalan.xsltc.runtime.AbstractTranslet
)为StubTransletPayload父类调用自建·Reflections.setFieldValue·设置
_bytecodes,_name,_tfactory
保证反序列化正常执行,并将创建的StubTransletPayload
类加载进templates
反序列化 debug
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class exp {
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("/Users/osword/Desktop/c3.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//恢复对象
ois.readObject();
ois.close();
}
}
执行tranfrom
方法这里con为TrAXFilter
类,iArgs参数为javassist
字节
newInstance
执行后会执行TrAXFilter
类构造方法,相当于PHP中__construct
方法
defineTransletClasses该方法可以看作对StubTransletPayload类(ysoserial)构造定义
跟进defineTransletClasses
代码
_class[i] = loader.defineClass(_bytecodes[i]);
通过对_class层叠加载父类和接口类.
但是defineTransletClasses
方法并未实例化传入Javassist
构造的类(ysoserial定义的StubTransletPayload类).
最后通过AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
就能成功加载Javassist构造的类.
并且Runtime.getRuntime.exec
执行在static代码块中,在类加载后就会优先执行.
总结一下javassist利用过程
TrAXFilter.TrAXFilter();
_transformer = (TransformerImpl) templates.newTransformer();
TemplatesImpl.newTransformer();
TemplatesImpl.getTransletInstance();
defineTransletClasses(); //配置javassist构造的类
loader.defineClass(_bytecodes[i]);
/*ysoserial工具
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});*/
(AbstractTranslet) _class[_transletIndex].newInstance();
//ysoserial工具 final CtClass clazz = pool.get(StubTransletPayload.class.getName())
TemplatesImpl.loadClass();//加载后优先执行staic代码块中的Runtime.getRuntime.exec()
总结
两种类构造方法:
1.反射类 2.javassist
分析时候可以先debug下ysoserial工具是怎么构造EXP搞清楚构造过程,在去分析反序列化就较容易了。
参考链接
https://www.anquanke.com/post/id/190461
https://baiqiantao.github.io/Java/aop/R77vuq/
https://github.com/jboss-javassist/javassist/wiki/Tutorial-1
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!