
Декомпилятор и статический анализатор Python pickling

Fickling — это декомпилятор, статический анализатор и перезаписыватель байт-кода для сериализации объектов Python pickle. Вы можете использовать Fickling для обнаружения, анализа, реверс-инжиниринга или даже создания вредоносных pickle-файлов и файлов на основе pickle, включая файлы PyTorch.
Fickling можно использовать как библиотеку Python, так и CLI.
Fickling протестирован на Python 3.9–3.13 и имеет очень мало зависимостей. И библиотеку, и утилиту командной строки можно установить через pip или uv:
# Using pip
python -m pip install fickling
# Using uv
uv pip install fickling
PyTorch является опциональной зависимостью Fickling. Поэтому для использования модулей и Fickling выполните:
pytorchpolyglot# Using pip
python -m pip install fickling[torch]
# Using uv
uv pip install fickling[torch]
Fickling может помочь защитить кодовые базы AI/ML, автоматически сканируя pickle-файлы, содержащиеся в моделях. 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",
]
)
Важно: Всегда убеждайтесь, что добавленные вручную импорты действительно безопасны и не позволяют злоумышленникам выполнять произвольный код. Если вы не уверены, как это сделать, вы можете открыть issue в репозитории Fickling на Github, указав проблемные импорты/модели, и наша команда сможет их проверить и, если возможно, включить в белый список.
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, вы всё равно можете использовать CLI-интерфейс Fickling для проверки безопасности pickle-файлов:
fickling --check-safety -p pickled.data
CLI Fickling позволяет безопасно трассировать выполнение виртуальной машины 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 содержит несколько файловых форматов, с помощью которых можно создавать полиглот-файлы — это файлы, которые могут быть корректно интерпретированы как более чем один файловый формат. 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!
Pickled-объекты Python на самом деле являются байт-кодом, который интерпретируется встроенной в Python стековой виртуальной машиной, называемой «Pickle Machine». Fickling может принимать потоки pickle-данных и декомпилировать их в читаемый Python-код, который при выполнении десериализует исходный сериализованный объект. Это стало возможным благодаря собственной реализации PM в Fickling. Fickling безопасно запускать на потенциально вредоносных файлах, поскольку его PM символически исполняет код, а не выполняет его напрямую.
Авторы не приписывают никакого значения букве «F» в названии Fickling; она может означать «fickle» (непостоянный) … или что-то ещё. Постижение её смысла — личный путь усмотрения, и он оставлен читателю в качестве упражнения.
Узнайте больше о Fickling в нашем blog post и выступлении на DEF CON AI Village 2021.
Если вы хотите сообщить об ошибке или запросить новую функциональность, пожалуйста, воспользуйтесь нашей страницей issues. Не стесняйтесь обращаться к нам или писать в Empire Hacking за помощью в использовании или расширении Fickling.
Эта утилита разработана Trail of Bits. Она лицензирована на условиях GNU Lesser General Public License v3.0. Свяжитесь с нами, если вы ищете исключение из условий.
© 2021, Trail of Bits.