序列化与反序列化的原理以及利用和防御

1、序列化和反序列化的概念

序列化:把对象转换为字节序列的过程称为对象的序列化。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

序列化就是把对象转换成字节流,便于保存在内存、文件、数据库中;反序列化即逆过程,由字节流还原成对象。Java中的ObjectOutputStream类的writeObject()方法可以实现序列化,类ObjectInputStream类的readObject()方法用于反序列化。下面是将字符串对象先进行序列化,存储到本地文件,然后再通过反序列化进行恢复

如果Java应用对用户输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能带来任意代码执行

问题的根源在于类ObjectInputStream在反序列化时,没有对生成的对象的类型做限制;假若反序列化可以设置Java类型的白名单

2、序列化的目的与用到序列化的情况

当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
当你想用套接字在网络上传送对象的时候;
当你想通过RMI传输对象的时候;

2.1对象序列化的步骤如下

(1)创建对象输入流,它可以包装一个其他类型的目标输入流,例如:文件输出流。

(2)通过对象输入流的writeObject()方法写对象。

2.2.对象的反序列化如下:

 (1)创建对象输入流,同样的,可以包含其他类型的目标输出流,例如:文件输入流。

(2)通过对象输入流的readObject()方法读取对象。

3、漏洞挖掘

基本手段:

从可控数据的反序列化或间接的反序列化接口入手,在此基础上尝试构造序列化对象。

首先拿到一个Java应用,需要找到一个接受外部输入的序列化对象的接收点,即反序列化漏洞的触发点。我们可以通过审计源码中对反序列化函数的调用(例如readObject())来寻找,也可以直接通过对应用交互流量进行抓包,查看流量中是否包含java序列化数据来判断,java序列化数据的特征为以标记(ac ed 00 05)开头。

确定了反序列化输入点后,再考察应用的Class Path中是否包含Apache Commons Collections库(ysoserial所支持的其他库亦可),如果是,就可以使用ysoserial来生成反序列化的payload,指定库名和想要执行的命令即可:

通过先前找到的传入对象方式进行对象注入,数据中载入payload,触发受影响应用中ObjectInputStream的反序列化操作,随后通过反射调用Runtime.getRunTime.exec即可完成利用。

4、防御手段

4.1 weblogic防御

• 过滤T3协议,限定可连接的IP
• 设置Nginx反向代理,实现t3协议和http协议隔离
• JEP290(JDK8u121,7u131,6u141),这个机制主要是在每层反序列化过程中都加了一层黑名单处理

4.2 原生反序列化防御

• 不要反序列化不可信的数据
• 给反序列数据加密签名,并确保解密在反序列之前
• 给反序列化接口添加认证授权
• 反序列化服务只允许监听在本地或者开启相应防火墙
• 升级第三方库
• 升级JDK,JEP290