前言

我的疑问主要是在虎符比赛期间读到了Ruilin大佬的"后反序列化漏洞"关于Gadget1.java中的注释产生的,部分代码如下图。

本文主要分享关于Hessian2通过Rome链两次反序列化完成恶意EvilTemplatesImpl注入中一些可能需要注意的点。

阅读需要了解Hessian2中的Rome链触发机制,本文不再赘述,文中若有错误敬请指正。

1. 关于TemplatesImpl

首先描述TemplatesImpl的触发机制中的重要方法getOutputProperties

  • getOutputProperties可以调用newTransformer

  • newTransformer会调用getTransletInstance()来创建恶意类

  • getTransletInstance会进入到defineTransletClasses中(name不能为空,_class必须为空才能进入defineTransletClasses)

  • 最后要注意defineTransletClasses的几个点,其中_tfactory是要着重注意的,此处是为何需要调用二次反序列化的关键之处

2. 关于反序列化的注意事项

其次,关于反序列化部分需要清楚如下几点:

  1. 关于Hessian2,Hessian2Input与Hessian2Output 均不能对transient修饰的成员进行序列化或者反序列化

  2. 对于ObjectInput与ObjectOutput,除非相关类对readObject或者writeObject进行了重写,否则也无法对transient修饰的成员的变量做操作

  3. 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

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖