
Un décompilateur de pickling Python et un analyseur statique

Fickling est un décompilateur, un analyseur statique et un réécriveur de bytecode pour les sérialisations d'objets Python pickle. Vous pouvez utiliser Fickling pour détecter, analyser, rétro-ingénierer ou même créer des fichiers pickle malveillants ou basés sur pickle, y compris les fichiers PyTorch.
Fickling peut être utilisé à la fois comme bibliothèque Python et comme CLI.
Fickling a été testé de Python 3.9 à Python 3.13 et a très peu de dépendances. La bibliothèque et l'utilitaire en ligne de commande peuvent être installés via pip ou uv :
# Using pip
python -m pip install fickling
# Using uv
uv pip install fickling
PyTorch est une dépendance optionnelle de Fickling. Par conséquent, pour utiliser les modules pytorch et de Fickling, vous devez exécuter :
polyglot# Using pip
python -m pip install fickling[torch]
# Using uv
uv pip install fickling[torch]
Fickling peut aider à sécuriser les bases de code IA/ML en analysant automatiquement les fichiers pickle contenus dans les modèles. Fickling se branche sur le module pickle et vérifie les imports effectués lors du chargement d'un modèle. Il vérifie les imports par rapport à une liste blanche d'imports provenant de bibliothèques de ML considérées comme sûres, et bloque les fichiers contenant d'autres imports.
Ajoutez les lignes suivantes le plus tôt possible, avant d'importer torch, numpy ou toute autre bibliothèque qui utilise pickle :
import fickling
# This sets global hooks on pickle
fickling.hook.activate_safe_ml_environment()
Pour supprimer la protection :
fickling.hook.deactivate_safe_ml_environment()
Il est possible que les modèles que vous utilisez contiennent des imports non autorisés par Fickling. Si vous souhaitez tout de même charger le modèle, vous pouvez simplement autoriser des imports supplémentaires pour votre cas d'utilisation spécifique avec l'argument also_allow :
fickling.hook.activate_safe_ml_environment(
also_allow=[
"some.import",
"another.allowed.import",
]
)
Important : Vous devez toujours vous assurer que les imports ajoutés manuellement sont réellement sûrs et ne peuvent pas permettre à des attaquants d'exécuter du code arbitraire. Si vous ne savez pas comment faire, vous pouvez ouvrir un ticket sur le dépôt GitHub de Fickling en indiquant les imports/modèles concernés, et notre équipe pourra les examiner et les inclure dans la liste blanche si possible.
Fickling peut être intégré de manière transparente à votre base de code pour détecter et interrompre le chargement de fichiers malveillants à l'exécution.
Ci-dessous, nous montrons les différentes façons d'utiliser Fickling pour appliquer des contrôles de sécurité sur les fichiers pickle. Sous le capot, il intercepte la bibliothèque pickle pour ajouter des contrôles de sécurité afin que le chargement d'un fichier pickle lève une exception UnsafeFileError si du contenu malveillant est détecté dans le fichier.
# 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")
À la sortie, le gestionnaire de contexte restaure ce qui était installé lors de son entrée, de sorte qu'un hook déjà en place reste effectif au lieu de laisser pickle sans hook.
# 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!")
Vous pouvez accéder aux détails de l'analyse de sécurité de Fickling depuis l'exception levée :
>>> 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]')"
]
}
}
}
Si vous utilisez un autre langage que Python, vous pouvez toujours utiliser la CLI de Fickling pour vérifier la sécurité de fichiers pickle :
fickling --check-safety -p pickled.data
La CLI de Fickling permet de tracer en toute sécurité l'exécution de la machine virtuelle Pickle sans exécuter de code malveillant :
fickling --trace file.pkl
Fickling permet d'injecter du code arbitraire dans un fichier pickle qui s'exécutera à chaque chargement du fichier.
fickling --inject "print('Malicious')" file.pkl > malicious.pkl
Fickling peut être utilisé pour décompiler un fichier pickle en vue d'une analyse plus approfondie.
>>> 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 contient plusieurs formats de fichiers avec lesquels on peut créer des fichiers polyglottes, c'est-à-dire des fichiers pouvant être valablement interprétés comme plus d'un format de fichier. Fickling permet d'identifier, d'inspecter et de créer des polyglottes avec les formats de fichiers PyTorch suivants :
>> 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']
Consultez nos exemples pour en savoir plus sur l'utilisation de Fickling !
Les objets Python picklés sont en réalité du bytecode interprété par une machine virtuelle à pile intégrée à Python, appelée la « Pickle Machine ». Fickling peut prendre des flux de données picklés et les décompiler en code Python lisible par l'humain qui, lorsqu'il est exécuté, désérialisera l'objet sérialisé d'origine. Cela est rendu possible par l'implémentation personnalisée de la PM par Fickling. Fickling peut être exécuté en toute sécurité sur des fichiers potentiellement malveillants car sa PM exécute symboliquement le code plutôt que de l'exécuter ouvertement.
Les auteurs ne prescrivent aucune signification au « F » de Fickling ; il pourrait signifier « fickle », … ou autre chose. Deviner sa signification est un voyage personnel marqué par la discrétion et est laissé en exercice au lecteur.
En savoir plus sur Fickling dans notre article de blog et conférence DEF CON AI Village 2021.
Si vous souhaitez signaler un bug ou demander une fonctionnalité, veuillez utiliser notre page issues. N'hésitez pas à nous contacter ou à nous rejoindre sur Empire Hacking pour obtenir de l'aide sur l'utilisation ou l'extension de Fickling.
Cet utilitaire a été développé par Trail of Bits. Il est sous licence GNU Lesser General Public License v3.0. Contactez-nous si vous cherchez une exception aux conditions.
© 2021, Trail of Bits.