
Fickling 是一个用于 Python pickle 对象序列化的反编译器、静态分析器和字节码重写器。你可以使用 fickling 来检测、分析、逆向工程,甚至创建恶意的 pickle 或基于 pickle 的文件,包括 PyTorch 文件。
Fickling 既可作为 Python 库 使用,也可作为 CLI 使用。
Fickling 需要 Python 3.11 或更高版本,且依赖项极少。库和命令行工具均可通过 pip 或 uv 安装:
# Using pip
python -m pip install fickling
# Using uv
uv pip install fickling
PyTorch 是 Fickling 的可选依赖项。因此,要使用 Fickling 的 pytorch 和 polyglot 模块,你应该运行:
# Using pip
python -m pip install fickling[torch]
# Using uv
uv pip install fickling[torch]
Fickling 可以通过自动扫描模型中包含的 pickle 文件来帮助保护 AI/ML 代码库。Fickling 会挂钩 pickle 模块,并验证加载模型时所做的导入。它仅将导入与来自 ML 库且被视为安全的导入允许列表进行核对,并阻止包含其他导入的文件。
请尽可能早地添加以下行,在导入 torch、numpy 或任何其他使用 pickle 的库之前:
import fickling
# This sets global hooks on pickle
fickling.hook.activate_safe_ml_environment()
要移除保护:
fickling.hook.deactivate_safe_ml_environment()
你使用的模型可能包含 Fickling 不允许的导入。如果你仍想加载该模型,可以简单地通过 also_allow 参数为你的特定用例允许额外的导入:
fickling.hook.activate_safe_ml_environment(
also_allow=[
"some.import",
"another.allowed.import",
]
)
重要:你应始终确保手动添加的导入实际上是安全的,并且不会使攻击者能够执行任意代码。如果你不确定如何操作,可以在 Fickling 的 Github 仓库中提交 issue,说明相关的导入/模型,我们的团队可以对其进行审查,并在可能的情况下将其加入允许列表。
Fickling 可以无缝集成到你的代码库中,以在运行时检测并阻止加载恶意文件。
下面我们展示使用 fickling 对 pickle 文件强制执行安全检查的不同方式。
在底层,它会挂钩 pickle 库以添加安全检查,从而在检测到文件中存在恶意内容时,加载 pickle 文件会引发 UnsafeFileError 异常。
# This enforces safety checks every time pickle is used to deserialize
fickling.always_check_safety()
# Attempt to load an unsafe file now raises an exception
with open("file.pkl", "rb") as f:
try:
pickle.load(f)
except fickling.UnsafeFileError:
print("Unsafe file!")
with fickling.check_safety():
# All pickle files loaded within the context manager are checked for safety
try:
with open("file.pkl", "rb") as f:
pickle.load("file.pkl")
except fickling.UnsafeFileError:
print("Unsafe file!")
# Files loaded outside of context manager are NOT checked
pickle.load("file.pkl")
退出时,上下文管理器会恢复进入时已安装的内容,因此已经就位的钩子会继续生效,而不是让 pickle 处于未挂钩状态。
# Use fickling.load() in place of pickle.load() to check safety and load a single pickle file
try:
fickling.load("file.pkl")
except fickling.UnsafeFileError as e:
print("Unsafe file!")
# Perform a safety check on a pickle file without loading it
if not fickling.is_likely_safe("file.pkl"):
print("Unsafe file!")
你可以从抛出的异常中访问 fickling 安全分析的详细信息:
>>> try:
... fickling.load("unsafe.pkl")
... except fickling.UnsafeFileError as e:
... print(e.info)
{
"severity": "OVERTLY_MALICIOUS",
"analysis": "Call to `eval(b'[5, 6, 7, 8]')` is almost certainly evidence of a malicious pickle file. Variable `_var0` is assigned value `eval(b'[5, 6, 7, 8]')` but unused afterward; this is suspicious and indicative of a malicious pickle file",
"detailed_results": {
"AnalysisResult": {
"OvertlyBadEval": "eval(b'[5, 6, 7, 8]')",
"UnusedVariables": [
"_var0",
"eval(b'[5, 6, 7, 8]')"
]
}
}
}
如果你使用的不是 Python 语言,你仍然可以使用 fickling 的 CLI 来对 pickle 文件进行安全检查:
fickling --check-safety -p pickled.data
Fickling 的 CLI 允许安全地跟踪 Pickle 虚拟机的执行过程,而无需
执行任何恶意代码:
fickling --trace file.pkl
Fickling 允许在 pickle 文件中注入任意代码,该代码将在每次加载该文件时执行
fickling --inject "print('Malicious')" file.pkl > malicious.pkl
Fickling 可用于反编译 pickle 文件以进行进一步分析
>>> import ast, pickle
>>> from fickling.fickle import Pickled
>>> fickled_object = Pickled.load(pickle.dumps([1, 2, 3, 4]))
>>> print(ast.dump(fickled_object.ast, indent=4))
Module(
body=[
Assign(
targets=[
Name(id='result', ctx=Store())],
value=List(
elts=[
Constant(value=1),
Constant(value=2),
Constant(value=3),
Constant(value=4)],
ctx=Load()))],
type_ignores=[])
PyTorch 包含多种文件格式,可用来构造多格式文件(polyglot),即能够被有效解释为不止一种文件格式的文件。 Fickling 支持识别、检查并创建以下 PyTorch 文件格式的多格式文件:
>> import torch
>> import torchvision.models as models
>> from fickling.pytorch import PyTorchModelWrapper
>> model = models.mobilenet_v2()
>> torch.save(model, "mobilenet.pth")
>> fickled_model = PyTorchModelWrapper("mobilenet.pth")
>> print(fickled_model.formats)
Your file is most likely of this format: PyTorch v1.3
['PyTorch v1.3']
查看我们的示例 以了解更多关于使用 fickling 的信息!
被 pickle 序列化的 Python 对象实际上是字节码,由 Python 内置的、名为“Pickle Machine”的基于栈的虚拟机解释执行。Fickling 可以接收 pickle 数据流并将其反编译为人类可读的 Python 代码,该代码在执行时会反序列化为原始的序列化对象。这得益于 Fickling 对 PM 的自定义实现。Fickling 可以安全地处理潜在的恶意文件,因为其 PM 以符号方式执行代码,而非直接执行代码。
作者并未对 Fickling 中的“F”赋予任何含义;它可能代表“fickle”(善变)……或其他什么。推测其含义是一段关乎个人判断的旅程,留给读者作为练习。
在我们的博客文章和 DEF CON AI Village 2021 演讲中了解更多关于 fickling 的信息。
如果您想提交错误报告或功能请求,请使用我们的议题页面。 欢迎联系我们,或在 Empire Hacking 中寻求关于使用或扩展 fickling 的帮助。
此工具由 Trail of Bits 开发。 它基于 GNU Lesser General Public License v3.0 许可。 如果您希望获得条款例外,请联系我们。
© 2021, Trail of Bits.