
Ein Python-Pickling-Decompiler und statischer Analysator

Fickling ist ein Dekompilierer, statischer Analysator und Bytecode-Umschreiber für Python-Pickle-Objektserialisierungen. Sie können Fickling verwenden, um bösartige Pickle- oder Pickle-basierte Dateien, einschließlich PyTorch-Dateien, zu erkennen, zu analysieren, reverse zu engineering oder sogar zu erstellen.
Fickling kann sowohl als Python-Bibliothek als auch als CLI verwendet werden.
Fickling wurde mit Python 3.9 bis Python 3.13 getestet und hat nur sehr wenige Abhängigkeiten. Sowohl die Bibliothek als auch das Kommandozeilenprogramm können über pip oder uv installiert werden:
# Using pip
python -m pip install fickling
# Using uv
uv pip install fickling
PyTorch ist eine optionale Abhängigkeit von Fickling. Um die Module pytorch und von Fickling zu verwenden, führen Sie Folgendes aus:
polyglot# Using pip
python -m pip install fickling[torch]
# Using uv
uv pip install fickling[torch]
Fickling kann helfen, KI/ML-Codebasen abzusichern, indem es automatisch in Modellen enthaltene Pickle-Dateien scannt. Fickling hängt sich in das Pickle-Modul ein und prüft Importe, die beim Laden eines Modells vorgenommen werden. Es prüft die Importe nur gegen eine Zulassungsliste von Importen aus ML-Bibliotheken, die als sicher gelten, und blockiert Dateien, die andere Importe enthalten.
Fügen Sie die folgenden Zeilen so früh wie möglich ein, bevor Sie torch, numpy oder eine andere Bibliothek importieren, die pickle verwendet:
import fickling
# This sets global hooks on pickle
fickling.hook.activate_safe_ml_environment()
Um den Schutz zu entfernen:
fickling.hook.deactivate_safe_ml_environment()
Möglicherweise enthalten die von Ihnen verwendeten Modelle Importe, die von Fickling nicht erlaubt sind. Wenn Sie das Modell dennoch laden möchten, können Sie mit dem Argument also_allow einfach zusätzliche Importe für Ihren spezifischen Anwendungsfall zulassen:
fickling.hook.activate_safe_ml_environment(
also_allow=[
"some.import",
"another.allowed.import",
]
)
Wichtig: Sie sollten immer sicherstellen, dass manuell hinzugefügte Importe tatsächlich sicher sind und es Angreifern nicht ermöglichen, beliebigen Code auszuführen. Wenn Sie sich nicht sicher sind, wie das geht, können Sie ein Issue im GitHub-Repository von Fickling eröffnen, das die betreffenden Importe/Modelle angibt. Unser Team kann sie prüfen und sie gegebenenfalls in die Zulassungsliste aufnehmen.
Fickling kann nahtlos in Ihre Codebasis integriert werden, um das Laden bösartiger Dateien zur Laufzeit zu erkennen und zu stoppen.
Im Folgenden zeigen wir die verschiedenen Möglichkeiten, wie Sie Fickling verwenden können, um Sicherheitsprüfungen für Pickle-Dateien durchzusetzen. Im Hintergrund hängt es sich in die pickle-Bibliothek ein, um Sicherheitsprüfungen hinzuzufügen, sodass das Laden einer Pickle-Datei eine UnsafeFileError-Ausnahme auslöst, wenn bösartiger Inhalt in der Datei erkannt wird.
# 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")
Beim Verlassen stellt der Kontextmanager den Zustand wieder her, der beim Eintritt installiert war. Ein bereits vorhandener Hook bleibt also wirksam, anstatt dass pickle ungehooked zurückgelassen wird.
# 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!")
Sie können auf die Details der Sicherheitsanalyse von Fickling aus der ausgelösten Ausnahme zugreifen:
>>> 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]')"
]
}
}
}
Wenn Sie eine andere Sprache als Python verwenden, können Sie die CLI von Fickling weiterhin verwenden, um Pickle-Dateien auf Sicherheit zu prüfen:
fickling --check-safety -p pickled.data
Die CLI von Fickling ermöglicht es, die Ausführung der virtuellen Pickle-Maschine sicher zu verfolgen, ohne bösartigen Code auszuführen:
fickling --trace file.pkl
Fickling ermöglicht es, beliebigen Code in eine Pickle-Datei zu injizieren, der bei jedem Laden der Datei ausgeführt wird:
fickling --inject "print('Malicious')" file.pkl > malicious.pkl
Fickling kann verwendet werden, um eine Pickle-Datei zur weiteren Analyse zu dekompilieren:
>>> 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 enthält mehrere Dateiformate, mit denen sich Polyglott-Dateien erstellen lassen – Dateien, die gültig als mehr als ein Dateiformat interpretiert werden können. Fickling unterstützt das Identifizieren, Untersuchen und Erstellen von Polyglotten mit den folgenden PyTorch-Dateiformaten:
>> 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']
Schauen Sie sich unsere Beispiele an, um mehr über die Verwendung von Fickling zu erfahren!
Bei gepickelten Python-Objekten handelt es sich tatsächlich um Bytecode, der von einer in Python integrierten stack-basierten virtuellen Maschine namens „Pickle Machine“ interpretiert wird. Fickling kann gepickelte Datenströme in menschenlesbaren Python-Code dekompilieren, der bei Ausführung das ursprüngliche serialisierte Objekt deserialisiert. Dies wird durch Ficklings eigene Implementierung der PM ermöglicht. Fickling ist sicher auf potenziell bösartigen Dateien ausführbar, da seine PM Code symbolisch ausführt, anstatt ihn offen auszuführen.
Die Autoren schreiben dem „F“ in Fickling keine Bedeutung zu; es könnte für „fickle“ (wankelmütig) … oder etwas anderes stehen. Seine Bedeutung zu ergründen, ist eine persönliche Reise im Ermessen des Lesers und bleibt diesem als Übung überlassen.
Erfahren Sie mehr über Fickling in unserem Blogbeitrag und DEF CON AI Village 2021-Vortrag.
Wenn Sie einen Fehlerbericht oder eine Funktionsanfrage einreichen möchten, nutzen Sie bitte unsere Issues-Seite. Sie können uns gerne kontaktieren oder sich im Empire Hacking-Slack melden, wenn Sie Hilfe bei der Verwendung oder Erweiterung von Fickling benötigen.
Dieses Werkzeug wurde von Trail of Bits entwickelt. Es ist unter der GNU Lesser General Public License v3.0 lizenziert. Kontaktieren Sie uns, wenn Sie eine Ausnahme von den Bedingungen suchen.
© 2021, Trail of Bits.