前言
我的疑问主要是在虎符比赛期间读到了Ruilin大佬的"后反序列化漏洞"关于Gadget1.java中的注释产生的,部分代码如下图。
本文主要分享关于Hessian2通过Rome链两次反序列化完成恶意EvilTemplatesImpl注入中一些可能需要注意的点。
阅读需要了解Hessian2中的Rome链触发机制,本文不再赘述,文中若有错误敬请指正。
1. 关于TemplatesImpl
首先描述TemplatesImpl的触发机制中的重要方法getOutputProperties
:
getOutputProperties可以调用
newTransformer
newTransformer会调用getTransletInstance()来创建恶意类
getTransletInstance会进入到defineTransletClasses中(name不能为空,_class必须为空才能进入defineTransletClasses)
最后要注意defineTransletClasses的几个点,其中_tfactory是要着重注意的,此处是为何需要调用二次反序列化的关键之处
2. 关于反序列化的注意事项
其次,关于反序列化部分需要清楚如下几点:
关于Hessian2,Hessian2Input与Hessian2Output 均不能对transient修饰的成员进行序列化或者反序列化
对于ObjectInput与ObjectOutput,除非相关类对readObject或者writeObject进行了重写,否则也无法对transient修饰的成员的变量做操作
TemplateImpl的
_tfactory
属性虽然是transient修饰,但其重写了readObject方法,方法中会生成_tfactory的实例,这或许在本文需要着重注意。 图一
图二
综上三点,我们可以清楚,TemplatesImpl在调用重写的readObject()时_tfactory会被实例化,那么ToStringBean遍历并调用getOutputProperties方法时,内部的_tfactory.getExternalExtensionsMap()
调用也就不会出"NullPointerException"和"InvocationTargetException"了。
同时,由于Hessian2的反序列化特性无法对_tfactory进行保护,所以也就无法直接使用TemplatesImpl。
3. SignedObject的作用
此类是在sofastack/sofa-hessian的黑名单中看到的。
SignedObject使用ObjectInput.readObject和ObjectOutput.writeObject对Serializable类进行操作,字节码存储在this.content
,反序列化可以通过getObject函数来调用,并且由于是getter的缘故,所以也可以在ToStringBean的toString方法中被调用。因此可以用于解决上文TemplatesImpl中提到的_tfactory为空的问题。
用法如下:
Student
public class Student implements Serializable {
private int age = 11;
private String name ="hezhi";
private transient String nickName = "alps";
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
//强制反序列化name
this.nickName = "whoami";
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", nick='" + nickName + '\'' +
'}';
}
}
Main
public static void main(String[] args) throws Exception {
Student student = new Student();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
Signature signature = Signature.getInstance(privateKey.getAlgorithm());
SignedObject signedObject = new SignedObject(student, privateKey, signature);
Student aaa = (Student) signedObject.getObject();
System.out.println(aaa);
}
4. 总结
由于不够熟悉常用链,导致我在debug的过程中产生了很多的误区,最后感谢这么多巨人的肩膀。
5. 参考:
[笑花大王 CommonsCollections3分析]:https://www.cnblogs.com/xhds/p/15732776.html#_label1_0
[Ruilin Java"后反序列化漏洞"利用思路]:http://rui0.cn/archives/1338
[Ruilin Gadget1.java]:https://github.com/Ruil1n/after-deserialization-attack/blob/master/src/main/java/cn/rui0/idea/Gadget1.java
[D4ck Hessian 反序列化漏洞分析]:https://www.anquanke.com/post/id/209251#h3-17
[sofastack/sofa-hessian]:https://github.com/sofastack/sofa-hessian