ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

关于 Java 序列化和反序列化的谈话

2022-11-04 16:04:39  阅读:273  来源: 互联网

标签:java 函数 学习


前言

目前Java安全的普及可以说是红队的必知之道。我曾经陷入了学习Java安全的初衷——学习CC链——放弃——再次开始学习Java的安全恶性循环就像背单词,总是止步于放弃。最后,在看到高级scz的博客后,我下定了决心。

基本用途

不再介绍序列化和反序列化的概念,让我们直接看一下用户。

对于可序列化的类,它需要实现可序列化外部化接口,前者是一个空接口:

public interface Serializable {  
}

它仅用于标识此类可以序列化,后者继承前者。

Java 对象的序列化步骤:

  • 创建一个可以包装另一个类型的输出流java.io.ObjectOutputStream

  • writeObject通过其方法编写对象

反序列化 Java 对象的步骤:

  • 创建一个可以包装另一种类型的输入流java.io.ObjectInputStream

  • 读取对象通过对象的方法读取对象

序列化数据格式

将序列化数据写入文件并观察:

您可以看到有一些可读的字符串,包括类名和一些成员变量名称和值。

使用该工具:序列化转储程序可以轻松还原序列化数据,例如原始流文件:

对于十六进制数据:

完整输入:

与 Oracle 官方文档中的对象序列化流协议 [2] 部分相比,让我们讨论以下序列化数据的结构。

首先是幻数和协议版本。您可以在 ObjectStreamConstants接口中看到定义:

后跟内容,即一个或多个内容,后者由反对者块数据组成。

对象里面的内容是序列化数据的核心,由以下任何内容组成:

  • 新对象:对象

  • 新类:种类

  • 新数组:数组

  • 新字符串:字符串

  • newEnum:枚举类型

  • newClassDesc:类定义

  • 上一页对象:对类型的引用

  • 空引用:空

  • 异常:异常

  • TC_RESET:重置引用 ID

请参阅新对象:

我们使用上面的例子来比较,包含一个 newObject 的内容,TC_OBJECTafter classDesc,它包含类名和长度、serialVersionUID、属性名称和长度、父类和其他信息。在此之后是 newHandle,前者是序列化数据中当前结构的唯一 ID,后者是序列化 object.classdata[] 中的信息。

newClassDescand classDesc并不相同,从定义中可以看出:

classDescEquivalent to newClassDescthe 封装,它可以是 newClassDescbe 的空值或指向类定义的指针。

在这一点上,你可能想知道,我为什么要阅读这个无聊的文档?你为什么不开始谈论CC链?

需要了解有关序列化数据结构的详细信息有三个原因:

  • 帮助理解通过填充序列化数据中的垃圾字符来绕过 WAF 的原理

  • 帮助以后了解 JDK 8u20 本机反序列化漏洞

  • 也许您会遇到需要使用其他语言来执行 Java 反序列化漏洞的情况

属性的效果

在 PHP 中序列化时,变量的作用域会影响序列化的数据,那么在 Java 中是否有类似的情况呢?

将两个变量添加到 Personclass 中:

观察序列化数据后,发现这两个变量都不存在:

由 static 或 transient 关键字修改的变量不会出现在序列化数据中,这是出于一些敏感数据的考虑。

但是如果你尝试在反序列化后调用这两个变量,你可以看到地址正常输出,而密码为空:

这是因为寻址一个静态变量,并且调用它在 JVM 中注册的值,而不是序列化后获得的值。

如果要序列化由瞬态关键字修改的变量,则需要使用 外部化接口:

在这里,如果用于解析,将发生以下错误:test.rawSerializationDumper

原因是实现 Externalizable 接口的类,其序列化是通过该方法写入流的 writeExternal,也必须通过相应的 readExternalMethod 进行解析,因此 SerializationDumper这样的序列化数据如果不提供原始类就无法解析。

对象流类分析

ObjectStreamClass 它可以用来分析JVM中加载的序列化类的序列化特征,包括字段描述信息和serialVersionUID等。

ObjectStreamClass有两种静态方法:

lookup(Class<?>cl) ObjectStreamClass如果提供的类是可序列化的,则返回一个实例,否则为 null:

该方法将返回相应的实例,而不管提供的类是否可反序列化。lookup any(Class<?>cl)

获取ObjectStreamClass实例后,可以调用相应的方法来获取信息:

  • getDeclaredSUID:提取序列号

  • getSerialFields:提取所需的序列化字段,如果没有,则提取默认字段

关于 ObjectInputStream.resolveClass()

图片.png

解析类该方法接收一个ObjectStreamClass实例,获取其类名,然后使用反射返回此类的Class实例。实际上,允许在反序列化期间返回对象之前替换或解析对象。

此方法在 Apache Shiro 中被覆盖:

这导致了 Shiro 反序列化漏洞的一些有趣情况,这将在后面的 Shiro 文章中详细讨论。

重写此方法也是防御反序列化漏洞的一种方法,例如 SerialKiller [3] 项目:

黑名单或白名单防御是通过重写来执行的。ObjectInputStream.resolveClass()

readObjectNoData

反序列化过程中,如果序列化类的超类与反序列化类的超类不同,因为序列化时的类与反序列化时的版本不同,或者因为收到的序列化数据不完整,或者序列化数据有害,会影响初始化的对象字段值。

标签:java,函数,学习
来源:

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有