freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Java反序列化深度讲解(二)
SpringKill 2023-08-01 00:04:40 127206
所属地 北京

前面一篇文章我们详细说了说反序列化的反射部分,这一部分很基础,也就是我们后面想要编写POC等内容的时候经常用来调用一些方法所使用的操作,这一篇我们就正式开始,详细说说反序列化漏洞吧。

序列化和反序列化

那么说到反序列化漏洞,首先肯定要知道什么是反序列化。
序列化和反序列化说到底还是为了通信存在的,同时反序列化也不是Java特有的,比如我们最经常使用和看到的的JSON其实就是一种序列化数据。
序列化和反序列化是一个思想:通过将数据以某种格式/语法进行一个“打包”成一个序列化的数据,然后再由接收端使用固定的格式/语法将其“解包”,从而达到复杂数据的精简传输,这种“打包”生成的内容有可能像JSON等内容一样,是一个特定格式的字符串,也有可能是像Java中的一种二进制流,这取决于对方如何实现。
就单独说说Java以及其中的反序列化吧。

序列化和反序列化的方法

  1. Java原生序列化

Java原生序列化是Java标准库提供的一种对象序列化方式。它涉及两个主要类:ObjectOutputStream用于将Java对象序列化为字节流,ObjectInputStream用于将字节流反序列化为Java对象。要使一个类可序列化,只需实现Serializable接口,该接口是一个标记接口,不包含任何方法。例如:

import java.io.*;

public class MyClass implements Serializable {
    static int value = 100;
    static String name = "TestClass";

    MyClass() {
        System.out.println(name + value);
    }

}

然后可以使用ObjectOutputStreamMyClass的对象序列化到文件或网络流:

MyClass myObject = new MyClass();
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data.bin"))) {
    oos.writeObject(myObject);
}

反序列化时,可以使用ObjectInputStream

MyClass deserializedObject;
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.bin"))) {
    deserializedObject = (MyClass) ois.readObject();
}
  1. JSON序列化
    JSON是一种轻量级数据交换格式,常用于Web应用程序的数据传输。Java中有许多开源库(如Jackson、Gson、JSON-B等)可以将Java对象序列化为JSON格式,以及从JSON格式反序列化为Java对象。
    以Jackson为例,将Java对象序列化为JSON字符串:

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(myObject);

反序列化:

MyClass deserializedObject = objectMapper.readValue(json, MyClass.class);
  1. XML序列化
    XML(eXtensible Markup Language)是另一种用于数据交换的通用格式,与JSON类似,Java中也有库可以实现XML序列化和反序列化。常用的库包括JAXB(Java Architecture for XML Binding)。
    以JAXB为例,将Java对象序列化为XML字符串:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

JAXBContext context = JAXBContext.newInstance(MyClass.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

StringWriter writer = new StringWriter();
marshaller.marshal(myObject, writer);
String xml = writer.toString();

反序列化:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

JAXBContext context = JAXBContext.newInstance(MyClass.class);
Unmarshaller unmarshaller = context.createUnmarshaller();

String xml = "<myClass><value>42</value><name>John</name></myClass>";
MyClass deserializedObject = (MyClass) unmarshaller.unmarshal(new StringReader(xml));
  1. 第三方序列化库
    除了JSON和XML,还有一些其他的第三方序列化库,如Apache Avro、Google Protocol Buffers等。这些库通常提供更高效的序列化和反序列化性能,但是同样的也存在一些新的安全风险。

为什么会出现漏洞

其他语言的反序列化漏洞

这一切还要从Java的语言特性说起了,比起其他语言的序列化反序列化,Java能够更方便地修改你想要序列化的流数据(writeObject()),做过CTF题目的师傅们应该清楚PHP的反序列化,通常在实现反序列化的过程中我们控制的并不是具体的某个对象,而是某个对象的值。
且看如下php代码:

<?php
class phone
{
    public $apple;
    public $samsung;
    public function see()
    {
        echo eval($this->apple);
    }
}
class tv
{
        public $skyworth;
        public $sony;
        public function __toString()
        {
                $this->skyworth->see();
                return "1";
        }
}
class book
{
        public $math;
        public $chinese;
        public function read()
        {
            $this->chinese->learn();
        }
}
class bottle
{
        public $locklock;
        public $fuguang;
        public function __toString()
        {
                $this->locklock->read();
                return "lock lock read!";
        }
}
class car
{
        public $volkswagen;
        public $audi;
        public function __invoke()
        {
            $this->volkswagen = $this->audi." Deutsch";
        }
}
class fruit
{
        public $apple;
        public $orange;
        public function __call($t1,$t2)
        {
                $s1 = $this->orange;
                $s1();
        }
}
?>

想必阅读完代码,构造完链子的时候师傅们就应该明白了,PHP反序列化和Java反序列化漏洞的不同点就在于用户能不能对序列化的数据进行一些“特殊”的比如序列化自定义类这种操作。PHP的反序列化我们常常通过阅读源码后找到危险的点,然后控制类中的属性值来达到目的(其实通常存在于析构函数中),但是Java中我们可以传入任意类来构造恶意数据。
再直白点,如果PHP的系统中不存在能够执行命令的地方,那么我们反序列化的数据也不能,但是Java中却可以,这也是Java反序列化存在的一个重要原因

那么下一篇我们就来分析具体的反序列化历史漏洞还有著名的CC链吧。

# web安全 # 漏洞分析 # 网络安全技术 # java反序列化 # Java代码审计
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 SpringKill 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Java反序列化深入理解
SpringKill LV.3
这家伙太懒了,还未填写个人描述!
  • 4 文章数
  • 3 关注者
Java反序列化深度讲解(一)
2023-07-13
【漏洞分析】CVE-2023-31058 Apache Inlong JDBC反序列化漏洞
2023-05-31
【漏洞分析】CVE-2023-27482 Home Assistant 权限绕过致远程代码执行漏洞
2023-05-17
文章目录