一. 反序列化漏洞成因

  1. 序列化 && 反序列化(详细介绍)
    1.1 What

  1. 什么是序列化?
    序列化是指将 内存中的数据结构或对象转换为一种可存储或可传输的格式。
    这使得复杂的数据(如对象、数组、列表)可以以简单的格式存储到文件、数据库,或者通过网络发送给其他程序。
  2. 通用示例
  • 序列化对象: 把一个对象(如用户信息对象)转化为字符串或二进制格式。比如 JSON、XML、二进制流。
  • 目的: 数据持久化、网络传输、跨语言数据交换、数据缓存等。
  1. 常见序列化格式
  • JSON: 一种基于文本的格式,非常适合人类阅读和编辑。广泛用于 Web 应用和 API。
  • XML: 另一种基于文本的格式,常用于配置文件或文档存储。
  • Protocol Buffers: Google 开发的一种高效的二进制序列化格式,适合跨语言的数据传输。
  • 二进制格式: 直接将对象转化为字节流,例如 Python 的 pickle、Java 的 Serializable、PHP 的 serialize()。

  1. 什么是反序列化?
    反序列化是序列化的逆过程,即 将存储或传输中的数据格式转换回内存中的对象或数据结构。反序列化使得程序可以重构之前序列化的数据,恢复其原始的结构和状态。
  2. 通用示例
  • 反序列化对象: 将一个 JSON 字符串解析回对象,将二进制数据流还原成复杂的数据结构。
  • 目的: 恢复之前保存的状态、数据或从网络接收的数据,进行进一步的处理。

流程示意图:
内存中的数据结构/对象 <–序列化–> 字符串/二进制数据 <–反序列化–> 内存中的数据结构/对象


序列化和反序列化的例子

  1. Python
  • 序列化: json.dumps(obj) 将 Python 对象转化为 JSON 字符串。
  • 反序列化: json.loads(json_string) 将 JSON 字符串解析回 Python 对象。
  1. Java
  • 序列化: 使用 ObjectOutputStream 将对象写入文件或网络流。
  • 反序列化: 使用 ObjectInputStream 读取数据流并还原为对象。
  1. JavaScript
  • 序列化: JSON.stringify(obj) 将 JavaScript 对象转化为 JSON 字符串。
  • 反序列化: JSON.parse(json_string) 将 JSON 字符串解析回 JavaScript 对象。
  1. PHP
  • 序列化: serialize($obj) 将 PHP 对象转换为字符串。
  • 反序列化: unserialize($string) 将字符串还原为 PHP 对象。
  1. Ruby
  • 序列化: Marshal.dump(obj) 将 Ruby 对象转化为二进制数据。
  • 反序列化: Marshal.load(data) 将二进制数据还原为 Ruby 对象。

1.2 Why
为什么需要序列化和反序列化?
简单来说,以下四个点:(总之就是要用,而且已经用了很久了,知道就行)
持久化: 将程序运行时的数据保存到文件、数据库等存储系统中,以便程序重启后恢复状态。
数据传输: 数据在不同程序、不同机器之间的传输(如通过网络),需要一种通用格式进行编码和解码。
跨语言兼容: 序列化格式(如 JSON、XML)是一种通用语言,可以用于不同语言之间的数据交换。
缓存: 将复杂数据结构序列化后存储到缓存系统中,以加快访问速度。

1.3 总结
序列化: 内存中对象/数据结构 → 可存储/传输的数据格式(如 JSON 字符串、二进制流)。
反序列化: 可存储/传输的数据格式 → 内存中对象/数据结构。

  1. 漏洞能产生什么后果?
    反序列化漏洞核心问题在于数据的来源不受信任,导致在反序列化过程中执行了意料之外的代码。
    所有语言的反序列化漏洞的危害在于:反序列化过程中会执行序列化数据中的参数或调用对象中的魔术方法,这些操作可能会导致未预期的代码执行。
    所以,通常会发生以下两种情况。
    2.1 反序列化的数据被直接执行
  • 有些语言在反序列化过程中,直接从序列化数据中提取信息,并执行其中嵌入的代码。这种情况类似于执行数据中的“脚本”,从而导致攻击者能够在服务器上运行任意代码。
  • 例如:
    • Python 的 pickle 库:可以通过序列化对象的 reduce 方法定义反序列化时执行的代码。
    • PHP 的 unserialize():序列化数据中的对象可能触发某些方法的执行。
      2.2 反序列化时调用的魔术方法或构造函数
  • 许多语言的对象在反序列化时会触发特定的魔术方法、构造函数或钩子函数。这些方法通常会被自动调用,用于初始化对象状态。如果这些魔术方法没有进行适当的验证或者对象数据受到攻击者操控,可能会导致任意代码执行。
  • 例如:
    • Java 的 readObject() 和 readResolve():反序列化时被自动调用,如果这些方法中包含执行代码的逻辑,则可能被利用。
    • PHP 的 __wakeup()、__destruct() 等魔术方法:可以在对象初始化或销毁时执行任意代码。
    • Ruby 的 YAML.load:可以调用构造方法(initialize)或对象中的其他钩子。
  1. 各个语言中的成因?
    如第一条所示,反序列化在各个语言中都有部分方法,简单来说知道这些方法就大概知道怎么打了。但是最好还是知道成因。其实非常接近,只是多了解一点罢了。
    3.1 Java
  • 成因: Java 的反序列化漏洞通常由反序列化不可信数据引起。Java 的对象序列化机制允许将对象转换为字节流,然后进行存储或传输。而反序列化时,如果不对输入数据进行验证,恶意用户可以构造特定的对象,通过反序列化时的代码执行特定的逻辑。
  • 关键点: Java 中的 java.io.ObjectInputStream 是常见的风险点。如果在反序列化过程中加载了不可信的类,会触发类的构造方法或某些类的 readObject()、readResolve() 等方法,从而导致任意代码执行。
  • 防护措施: 使用 ObjectInputStream 的子类来限制允许反序列化的类,或者使用像 Jackson、Gson 这样的库,它们提供更安全的反序列化机制。
    3.2 Python
  • 成因: Python 的反序列化漏洞主要涉及 pickle 库。pickle 允许将 Python 对象序列化成字节流并反序列化。由于 pickle 在反序列化时会执行对象的构造方法和 reduce 方法,因此攻击者可以构造恶意的输入,导致任意代码执行。
  • 关键点: pickle.loads() 和 pickle.load() 是常见的风险点。如果反序列化的数据源不可信,攻击者可以执行任意代码。
  • 防护措施: 避免反序列化不可信的数据,或者使用更安全的序列化库(例如 json),因为它们不会在反序列化时执行代码。
    3.3 PHP
  • 成因: PHP 中的反序列化漏洞通常出现在 unserialize() 函数上。PHP 允许将对象序列化成字符串并进行反序列化。恶意用户可以通过构造恶意的序列化字符串来调用目标对象的魔术方法(如 __wakeup()、__destruct()、__toString()),从而实现代码执行。
  • 关键点: 如果 unserialize() 的数据未经验证,攻击者可以通过构造特殊数据结构来操纵程序行为或执行任意代码。
  • 防护措施: 避免反序列化不可信的数据,或者对反序列化的类进行严格的白名单检查。
    3.4 Ruby
  • 成因: Ruby 中的反序列化漏洞主要发生在使用 Marshal.load 和 YAML.load 函数时。Marshal 和 YAML 允许将对象序列化和反序列化。由于 Ruby 的反序列化过程会自动调用某些对象的方法,攻击者可以构造恶意的序列化数据,导致任意代码执行。
  • 关键点: Marshal.load 和 YAML.load 是主要的风险点,特别是处理不受信的数据源时。
  • 防护措施: 避免使用 YAML.load 和 Marshal.load 处理不可信数据,推荐使用 YAML.safe_load,它能限制允许加载的对象类型。
    3.5 JavaScript (Node.js)
  • 成因: 在 Node.js 中,反序列化漏洞通常与 JSON.parse() 或自定义的序列化/反序列化函数有关。虽然 JSON.parse() 不直接执行代码,但恶意用户可能会利用弱类型机制进行逻辑操作或造成拒绝服务(DoS)。
  • 关键点: 反序列化不可信的数据时,可能会引入安全问题,尤其是在使用 eval() 或者自定义的反序列化逻辑时。
  • 防护措施: 严格验证反序列化的数据,不要在反序列化时执行代码,避免使用 eval()。
    3.6 .NET (C#)
  • 成因: .NET 中的反序列化漏洞通常出现在 BinaryFormatter 类上。BinaryFormatter 允许将对象序列化为二进制格式,并在反序列化时重建对象。恶意用户可以利用反序列化的过程中触发某些类的构造函数或特定方法,从而导致任意代码执行。
  • 关键点: BinaryFormatter.Deserialize 是常见的风险点,尤其是反序列化未经验证的输入时。
  • 防护措施: 避免使用 BinaryFormatter,选择更安全的替代库(例如 DataContractSerializer 或 Json.NET),并对反序列化的类型进行白名单检查。
  1. Thinking . . . From “反序列化” to “代码执行”.
    你要学反序列化,你就不能只学反序列化,你要想到整个代码执行漏洞家族。否则便是一叶障目…
    代码执行漏洞(RCE)原理:
    外部传入的包含恶意命令参数的数据被某种方式传递到代码中执行了
    反序列化只是这些漏洞的一种触发方式,许多其他代码执行漏洞与它的触发方式和原理非常类似。

还有哪些方式呢?

  1. 命令注入 (Command Injection)
  • 描述: 外部用户可以将恶意命令嵌入输入数据,通过传递到程序中执行。这通常是因为程序直接将用户输入的数据传递给操作系统命令执行函数。
  • 示例: 在 Web 应用中,如果用户输入的内容没有进行严格过滤,通过系统调用函数(如 system() 或 exec())执行用户输入时,攻击者可以注入恶意命令。
  • 代码执行原理: 用户输入的数据未经过验证直接传递给命令执行函数。
  1. 模板注入 (Template Injection)
  • 描述: 许多 Web 应用使用模板引擎生成 HTML 页面。如果模板引擎允许在模板中嵌入代码,并且这些代码可以直接执行,攻击者就可以通过控制模板输入来执行任意代码。
  • 示例: 在 Python 中使用 Jinja2 模板引擎时,如果用户能够控制模板内容并且没有禁用危险操作,攻击者可以执行恶意代码。
  • 代码执行原理: 用户输入的模板数据被传递到模板引擎解析器,导致执行未预期的代码。
  1. 远程文件包含 (Remote File Inclusion, RFI)
  • 描述: 某些 Web 应用允许通过 URL 动态加载文件,如果文件路径可以被用户控制,攻击者可以指定一个远程的恶意脚本文件,从而在目标系统中执行。
  • 示例: 在 PHP 中,如果应用没有对 include 或 require 函数的输入参数进行过滤,攻击者可以通过 URL 指向恶意的 PHP 脚本并在服务器上执行。
  • 代码执行原理: 用户控制的文件路径被直接传递给文件加载和执行函数。
  1. 表达式注入 (Expression Injection)
  • 描述: 某些语言或框架支持计算用户输入的表达式,如果这些表达式是用户可控的,可能会导致执行任意代码。
  • 示例: 在 JavaScript 中使用 eval() 函数时,如果用户的输入被直接传递给 eval(),攻击者可以执行任意 JavaScript 代码。
  • 代码执行原理: 用户输入的数据被直接传递给表达式解析和执行函数。

…

二. Source && Sink

  1. 常见的 Source 点
    Source 是反序列化过程中,攻击者可以控制的输入源。它通常是从外部接收到的数据,可能来自网络、文件、数据库或其他未受信任的来源。攻击者通过这些源提供恶意的序列化数据,从而可以操控反序列化过程。
  • HTTP 请求: 用户通过 HTTP 请求(如 GET、POST)提交的数据,尤其是 JSON 或 XML 格式的请求体。
  • 文件上传: 用户上传的文件(如 .json、.xml 或自定义的二进制格式文件),这些文件可能包含恶意序列化数据。
  • 数据库: 攻击者通过数据库注入或直接修改数据库中的字段,提供恶意的序列化数据。
  • Session Cookies: 存储在客户端的 cookies(如使用 PHP 或 Python 的 session 管理)可能包含经过序列化的对象,攻击者可能篡改 cookies 中的数据。
  • API 请求: 使用 Web 服务时,攻击者可能通过 API 请求提供恶意的序列化数据,尤其是在服务端没有严格校验输入时。
  • 消息队列: 在使用消息队列(如 Kafka、RabbitMQ)时,攻击者可以控制传输的数据(如发送恶意的消息数据)。
  1. 常见的 Sink 点
    Sink 是反序列化数据最终被处理的地方。通常,反序列化会将数据恢复成对象或数据结构,然后在程序中使用。恶意的反序列化数据会在这个阶段触发漏洞,导致未授权的行为。
  • 反序列化方法: 反序列化操作本身(如 deserialize()、unserialize()、readObject())是最直接的 Sink 点。此时,恶意数据被还原为程序中的对象或数据结构,可能触发不安全的代码执行。
  • 对象方法的调用: 在反序列化过程中,恶意数据可能触发对象的方法调用,这些方法会执行不受信任的操作(例如执行命令、修改系统状态等)。
  • 构造函数: 在某些语言(如 Java、PHP、Python)中,反序列化过程中可以自动调用类的构造函数或魔术方法(如 __construct()、__wakeup())。如果这些构造方法没有正确校验输入,攻击者可以利用它们来执行恶意代码。
  • 系统调用/命令执行: 如果反序列化过程中触发了系统调用或执行了外部命令,这些操作可能被攻击者利用来执行恶意命令。
  • 文件/数据库操作: 反序列化后的对象可能会进行文件操作(如读取、写入文件),或操作数据库,这些操作如果没有严格的权限控制,可以被攻击者用来执行非法操作。
  1. 不同语言中的source和sink
    仔细阅读到这里的话,相信常见语言中的source和sink你大致都知道了。
    所以此处只是做个总结,做工具箱的属性。

  1. Java
  • Source 点:
    • HTTP 请求:如通过 ServletRequest.getParameter() 获取传递的参数。
    • 文件读取:如通过 ObjectInputStream.readObject() 反序列化文件内容。
    • 数据库:恶意用户通过 SQL 注入向数据库注入恶意的序列化数据。
  • Sink 点:
    • ObjectInputStream.readObject():该方法将数据反序列化为 Java 对象,是最常见的 Sink 点。
    • 反序列化过程中调用类的构造方法或魔术方法(如 readObject()、readObjectNoData())时,可能会导致恶意代码执行。
    • java.lang.Runtime.exec() 或 ProcessBuilder.start():如果恶意对象触发了系统命令执行,这些方法可能被调用。

  1. PHP
  • Source 点:
    • HTTP 请求:例如,用户通过 POST、_POST、P​OST、_GET 或 $_REQUEST 提交的数据,可能含有恶意的序列化对象。
    • Cookies:存储了反序列化对象的 session cookies 可能被篡改。
    • 数据库:通过 SQL 注入或直接修改数据库字段,攻击者可以注入恶意的序列化数据。
  • Sink 点:
    • unserialize():PHP 的反序列化函数,如果传入恶意数据,可能导致远程代码执行。
    • 类的 __wakeup() 方法:PHP 反序列化对象时,如果 __wakeup() 被调用,且没有适当的输入校验,攻击者可能触发不安全的操作。
    • 文件系统操作:如果反序列化的对象包含文件路径或命令,可能导致敏感文件的读取、写入或命令执行。

  1. Python
  • Source 点:
    • HTTP 请求:通过 requests 模块等接收到的 JSON 或 XML 数据。
    • 文件读取:例如通过 pickle.load() 读取包含恶意数据的文件。
    • 数据库:通过 SQL 注入或直接修改数据库字段提供恶意序列化数据。
  • Sink 点:
    • pickle.load():Python 的 pickle 模块可以将数据反序列化为对象,如果传入恶意数据,可能导致远程代码执行。
    • setstate() 和 getstate():某些类的序列化和反序列化操作可能会调用这些方法,导致恶意操作。
    • 系统命令执行:通过恶意对象,反序列化后可能触发如 os.system() 等方法执行系统命令。

  1. Ruby
  • Source 点:
    • HTTP 请求:例如,通过 params 获取传递的数据。
    • 文件读取:通过 Marshal.load() 读取文件中的数据。
  • Sink 点:
    • Marshal.load():Ruby 中的 Marshal 模块用于反序列化对象,恶意的序列化数据可能导致代码执行。
    • 反序列化过程中调用的对象方法:类似于其他语言,Ruby 中的对象方法如果没有适当校验,可能被利用执行恶意操作。

三. 修复方案

  1. 限制反序列化数据的来源,避免不可信的数据源。
  2. 使用安全的序列化格式,避免使用允许执行代码的序列化机制(如 Python 中避免使用 pickle,PHP 中小心使用 unserialize())。
  3. 验证反序列化数据的完整性和类型,使用白名单限制允许反序列化的对象类型。
  4. 尽量避免魔术方法和构造函数中的复杂逻辑或代码执行,减少被攻击者利用的可能性。
    总结:
  5. 对输入数据的来源进行验证和限制
  6. 选择安全的序列化格式
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐