• Java反序列化


    序列化由来

    在网络上传递信息,通常用到一些格式化数据,例如Json、XML等。但是大多数处理方法中,JSON和XML支持的数据类型就是基本数据类型,整形、浮点型、字符串、布尔等。如果开发者希望在传输数据的时候直接传输一个对象,就需要扩展基础的JSON(XML)语法。

    比如Jsackson和Fastjson这类序列化库,在JSON(XML)的基础上进行改造,通过特定的语法来传递对象;亦或者如RMI,直接使用Java等语言内置的序列化方法,将一个对象转换成一串二进制数据进行传输。

    不管是Jackson、Fastjson还是编程语言内置的序列化方法,一旦涉及到序列化与反序列化数据,就可能会涉及到安全问题。

    一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。即序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。

    将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,即把一个二进制内容(也就是byte[]数组)变回Java对象

    安全性

    因为Java的序列化机制可以导致一个实例能直接从byte[]数组创建,而不经过构造方法,因此,它存在一定的安全隐患。一个精心构造的byte[]数组被反序列化后可以执行特定的Java代码,从而导致严重的安全漏洞。

    实际上,Java本身提供的基于对象的序列化和反序列化机制既存在安全性问题,也存在兼容性问题。更好的序列化方法是通过JSON这样的通用数据结构来实现,只输出基本类型(包括String)的内容,而不存储任何与代码相关的信息。

    反序列化漏洞的攻击流程

    1. 客户端构造payload(有效载荷),并进行一层层的封装,完成最后的exp(exploit-利用代码)
    2. exp发送到服务端,进入一个服务端自主重写(也可能是也有组件重写)的readobject函数,它会反序列化恢复我们构造的exp去形成一个恶意的数据格式exp_1(剥去第一层)
    3. 这个恶意数据exp_1在接下来的处理流程(可能是在自主重写的readobject中、也可能是在外面的逻辑中),会执行一个exp_1这个恶意数据类的一个方法,在方法中会根据exp_1的内容进行函处理,从而一层层地剥去(或者说变形、解析)我们exp_1变成exp_2、exp_3…
    4. 最后在一个可执行任意命令的函数中执行最后的payload,完成远程代码执行。

    那么以上大概可以分成三个主要部分:

    1. payload:需要让服务端执行的语句:比如说弹计算器还是执行远程访问等;
    2. 反序列化利用链:服务端中存在的反序列化利用链,会一层层拨开我们的exp,最后执行payload。(如commons-collections利用链)
    3. 重写readObject:服务端中存在的可以与我们漏洞链相接的并且可以从外部访问的readObject函数重写点

    Java内置的序列化

    Java内置的序列化方法readObject是将十六进制数据流转为对象的方法,更倾向于解决“反序列化时如何还原一个完整对象”。

    Java在序列化时一个对象,将会调用这个对象中的 writeObject方法,参数类型是ObjectOutputStream ,开发者可以将任何内容写入这个stream中;反序列化时,会调用readObject,开发者也可以从中读取出前面写入的内容,并进行处理。

    每个对象都可以重写自己的writeObjectreadObject方法。

    Person person = new Person("杜子腾", 15);
    
    try {
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\person.ser");
        ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
        outputStream.writeObject(person);//序列化
        outputStream.close();
        fileOutputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    try {
        FileInputStream fileInputStream = new FileInputStream("D:\\person.ser");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        objectInputStream.readObject();//反序列化
        objectInputStream.close();
        fileInputStream.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    工具:SerializationDumper可以查看序列化的数据、ysoserial可以生成反序列化利用数据。

    利用链

    利用链也叫“gadget chains”,我们通常称为gadget。它连接的是从触发位置开始到执行命令的位置结束,在PHP里面可能是_desctructeval。gadget就是一种生成POC的方法。

  • 相关阅读:
    Word处理控件Aspose.Words功能演示:使用 C# 在 Word 文档中创建条形码
    使用 Shell 脚本定期检查 MySQL 服务是否正常运行
    计算机系统弱电网络知识点全面总结(完整版)
    shell_50.Linux获取用户输入_超时
    微信如何设置自动回复消息,提升沟通效率的?
    php74 安装sodium
    Nuxt 菜鸟入门学习笔记七:SEO 和 Meta 设置
    HTTP详解(HTTP的特点,状态码,工作原理,GET和POST的区别,如何解决无状态通信)!!!
    Java基础进阶集合-Comparable接口,Comparator比较器案例
    分频流水灯
  • 原文地址:https://blog.csdn.net/weixin_42974824/article/details/126311656