一、pickle 反序列化
1.1 原理
pickle 是相当于一个指令解释器,解析对应的opcode指令。因此其实python的序列化和反序列化机制更像是一个代码执行。pickle 的反序列化器是一个 opcode 解释器:它按顺序读取 opcode 并执行对应的动作。Pickle 的 opcode ≈ Python 对象操作的汇编代码,这也就是说我们的
Python 字节码
是 解释 Python 源代码用的“机器码”
Pickle opcode
是 解释 Python 对象结构和构造过程用的“脚本码”
类似汇编语言
1 |
|
Pickle 是一种带有执行语义的脚本格式。
它的 opcode 可以直接构造对象、调用函数(如
os.system()
)。所以,只要你给 Python 反序列化一个恶意构造的 pickle 数据,它就会自动“解释执行”这些指令
1.2 rce
因为 pickle.loads()
会直接执行传入数据中的指令(opcode),而这些指令可以构造任意对象、调用任意函数、执行任意系统命令 —— 这就是完整的代码执行能力。
pickle.dumps()
它 不是 把 Python 代码序列化成字节码(像
.pyc
文件那样);它是把一个 Python 对象(含其结构、数据、构造方法) 序列化成一种 pickle 指令流(opcode 流);
这个 opcode 是
pickle
模块内部设计的一套“迷你语言”,能表示“如何构造这个对象”。
1.3 构造
__reduce__()
在 Python 中,pickle
模块用来“序列化”和“反序列化”对象。
而当你 反序列化 一个对象时,pickle
必须知道:
“我应该怎么重新构造这个对象?”
这时候就靠对象的 __reduce__()
方法 来告诉 pickle
如何“重建自己”
1 | import os |
只需要一个元组 带上函数名字 + 元组参数
二、复现
其实我感觉还是很简单的. 并且官方其实没有一些修复方式。这不算是一个漏洞,更多是算是一种特性。
server
1 | from flask import Flask, request |
exp
1 | import pickle |
成功构造无回显rce