概念

序列化和反序列化的区别

  • 序列化:把Java对象转换为字节序列的过程
  • 反序列化:把字节序列转化为Java对象的过程

出现点

  1. 功能特性
    • 反序列化操作一般应用在导入模板文件、网络连通、数据传输、日志格式化存储、对象数据落磁盘或DB存储等业务场景,因此审计过程应重点关注这些功能模块
  2. 数据特性
    • 一段数据以rO0AB开头,基本可以确定是JAVA序列化base64加密的数据
    • aced开头,是java序列化数据的16进制
  3. 具体出现
    • 网络通信:RMI、JMX、JMS、RPC框架(如Dubbo)或使用原生Java序列化协议的Socket通信。
    • Web应用:通过HTTP请求参数、Cookie、Session(HttpSession存储于文件或Redis)传入并反序列化用户可控的对象。
    • 缓存与持久化:从文件系统或缓存(如Redis、Ehcache)读取序列化对象(.ser文件或字节流)。
    • 第三方组件:使用了存在不安全反序列化漏洞的第三方库(如Apache Commons Collections, Spring, Fastjson等)。

常见情况

  • XML&SOAP
    • XML 是一种常用的序列化和反序列化协议,具有跨机器,跨语言等优点,SOAP(SimpleObject Access protocol)是一种被广泛应用的,基于XML 为序列化和反序列化协议的结构化消息传递协议
  • JSON
  • Protobuf

利用

Ysoseria集成的jar配合生成、特性的专业漏洞利用工具等

序列化的实现

什么是序列化和反序列化

Java描述的是一个‘世界’,程序运行开始时,这个‘世界’也开始运作,但‘世界’中的对象不是一成不变的,它的属性会随着程序的运行而改变。
但很多情况下,我们需要保存某一刻某个对象的信息,来进行一些操作。比如利用反序列化将程序运行的对象状态以二进制形式储存与文件系统中,然后可以在另一个程序中对序列化后的对象状态数据进行反序列化恢复对象。可以有效地实现多平台之间的通信、对象持久化存储。

一个类的对象要想序列化成功,必须满足两个条件:

  1. 该类必须实现 java.io.Serializable 接口。
  2. 该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。

如果你想知道一个 Java 标准类是否是可序列化的,可以通过查看该类的文档,查看该类有没有实现 java.io.Serializable接口。

下面书写一个简单的demo,为了节省文章篇幅,这里把序列化操作和反序列化操作弄得简单一些,并省去了传递过程

对象所属类:

/**
 * Description:
 * <br/>网站: <a href="http://ph0rse.me">Ph0rse's Blog</a>
 * <br/>Copyright (C), 2018-2020, Ph0rse
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author Ph0rse prudenidealist@outlook.com
 * @version 1.0
 */
public class Employee implements java.io.Serializable
{
   public String name;
   public String identify;
   public void mailCheck()
   {
      System.out.println("This is the "+this.identify+" of our company");
   }
}

将对象序列化为二进制文件:

//反序列化所需类在io包中
import java.io.*;

public class SerializeDemo
{
   public static void main(String [] args)
   {
      Employee e = new Employee();
      e.name = "员工甲";
      e.identify = "General staff";
      try
      {
        // 打开一个文件输入流
         FileOutputStream fileOut =
         new FileOutputStream("D:\\Task\\employee1.db");
         // 建立对象输入流
         ObjectOutputStream out = new ObjectOutputStream(fileOut);
         //输出反序列化对象
         out.writeObject(e);
         out.close();
         fileOut.close();
         System.out.printf("Serialized data is saved in D:\\Task\\employee1.db");
      }catch(IOException i)
      {
          i.printStackTrace();
      }
   }
}

一个Identity属性为Visitors的对象被储存进了employee1.db,而反序列化操作就是从二进制文件中提取对象:

import java.io.*;

public class SerializeDemo
{
   public static void main(String [] args)
   {
      Employee e = null;
      try
      {
        // 打开一个文件输入流
         FileInputStream fileIn = new FileInputStream("D:\\Task\\employee1.db");
        // 建立对象输入流
         ObjectInputStream in = new ObjectInputStream(fileIn);
        // 读取对象
         e = (Employee) in.readObject();
         in.close();
         fileIn.close();
      }catch(IOException i)
      {
         i.printStackTrace();
         return;
      }catch(ClassNotFoundException c)
      {
         System.out.println("Employee class not found");
         c.printStackTrace();
         return;
      }
      System.out.println("Deserialized Employee...");
      System.out.println("Name: " + e.name);
      System.out.println("This is the "+e.identify+" of our company");


    }
}