学无止境,参考着资料边学边记录吧。
0x01 Java序列化与反序列化
Java序列化是指把Java对象转换为字节序列的过程。这一过程将数据分解成字节流,以便存储在文件中或在网络上传输;
Java反序列化是指把字节序列恢复为Java对象的过程。就是打开字节流并重构成对象,恢复数据。
序列化与反序列化都可以理解为“写”和“读”操作 ,通过以下这两个方法可以将对象实例进行“序列化”与“反序列化”操作。
0x02 为什么需要序列化与反序列化
当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本、图片、音频、视频等, 而这些数据都会以二进制序列的形式在网络上传送。而当两个Java进程进行通信时,可以通过Java的序列化与反序列化在进程之间直接传送对象,换句话说,发送方需要把这个Java对象转换为字节序列,然后在网络上传送;接收方需要从字节序列中恢复出Java对象。
使用场景:
- 想把内存中的对象保存到一个文件中或者数据库中时候;
- 想用套接字在网络上传送对象的时候;
- 想通过RMI传输对象的时候
一些应用场景涉及到将对象转化成二进制,序列化保证了能够成功读取到保存的对象。
总之,序列化的用途就是传递和存储。
0x03 序列化实现的方式
3.1 Serializable
将要序列化的类实现
Serializabel 接口(Serializable接口是一个标记接口,不用实现任何方法。一旦实现了此接口,则表明该类的对象就是可序列化的),而且所有属性必须是可序列化的,就是如果一个可序列化的类的成员不是基本类型,也不是String类型,比如自己自定义的类,那这个引用类型也必须是可序列化的,否则,会导致此类不能序列化(用transient关键字修饰的属性除外,不参与序列化过程) 。需要序列化的类
序列化
可以看到运行后,生产了一个文件,将
user 对象变成了可持久化存储的二进制数据。
可以来看一下该对象序列化后的二进制数据

序列化的数据流以魔术数字和版本号开头,这个值是在调用
ObjectOutputStream序列化时,由writeStreamHeader方法写入。开头的几位一般来当作Java序列化字节的特征。反序列化

读取了序列化文件,将二进制文件重新恢复为
user对象,对象里面的属性也是完美恢复。3.2 Externalizable
通过实现
Externalizable接口进行序列化和反序列胡,但必须实现writeExternal、readExternal方法,并且还要实现一个类的无参构造方法,Serializable 接口可以不用实现。用法和实现了
Serializable接口一样,这里就不演示了。0x04 readObject()方法
特地提到这个方法是因为在反序列化漏洞中它起到了关键作用。因为在序列化过程中,JVM虚拟机会试图调用对象类里的
writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化,如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。Java反序列化的过程中可以自动执行序列化类的四个方法,实现了Serializable接口可以执行的方法包括readObject、readObjectNoData、readResolve,以及实现了Externalizable接口的readExternal方法。这些在找反序列化漏洞时都需要重点关注。
如果
readObject方法书写不当的话就有可能引发恶意代码的执行,例如基本类
readObject中存在执行命令的代码Runtime.getRuntime().exec(new String[]{"open", "-a", name}),name参数是要执行的命令。那么我们可以构造一个恶意的对象,将其name属性赋值为要执行的命令,当反序列化触发readObject时就会RCE。如下序列化和反序列化

这是一个极端的例子,在真实场景中,不会有人真的这样直接写一句执行命令的代码在readObject()中,这样写的开发绝对会被拉出去祭天的。所以反序列化漏洞通常会需要Java的一些特性进行配合比如
反射(invoke)。然后就是利用链的寻找。反序列化漏洞需要三个东西- 反序列化入口(source)
- 目标方法(sink)
- 利用链(gadget chain)
大佬们基本都会去寻找重写了这个
readObject方法的类,并配合Java的invoke反射机制,构造利用链,形成了Java中最具特色的反序列化攻击。而且再看上图中的输出结果,不仅仅触发了readObject方法,还触发了toString()、无参构造、set、get方法,那么在实际寻找利用链的过程中就不仅仅需要关注readObject()的方法了。0x05 参考
Java反序列之从萌新到菜鸟 https://www.kingkk.com/2019/01/Java反序列之从萌新到菜鸟/
Java反序列化技术分享 https://github.com/Y4er/WebLogic-Shiro-shell
- 作者:yhy
- 链接:https://fireline.fun/article/page-15
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。







.png?table=block&id=2f897da5-45e9-80f3-be17-c682d5baa107&t=2f897da5-45e9-80f3-be17-c682d5baa107)
.png?table=block&id=2ed97da5-45e9-8064-bc5e-ea3540aaeb5c&t=2ed97da5-45e9-8064-bc5e-ea3540aaeb5c)

