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();
}
try {
    FileInputStream fileInputStream = new FileInputStream("D:\\person.ser");
    ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
    objectInputStream.readObject();//反序列化
    objectInputStream.close();
    fileInputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}

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

利用链

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值