
Decompilatore e analizzatore statico per il pickling di Python.

Fickling è un decompilatore, un analizzatore statico e un riscrittore di bytecode per le serializzazioni di oggetti Python in formato pickle. Puoi usare Fickling per rilevare, analizzare, fare reverse engineering o persino creare file pickle o basati su pickle dannosi, inclusi i file PyTorch.
Fickling può essere usato sia come libreria Python sia come CLI.
Fickling è stato testato su Python 3.9 fino a Python 3.13 e ha pochissime dipendenze. Sia la libreria sia l'utilità da riga di comando possono essere installate tramite pip o uv:
# Usando pip
python -m pip install fickling
# Usando uv
uv pip install fickling
PyTorch è una dipendenza opzionale di Fickling. Pertanto, per utilizzare i moduli pytorch
e di Fickling, dovresti eseguire:
polyglot# Usando pip
python -m pip install fickling[torch]
# Usando uv
uv pip install fickling[torch]
Fickling può aiutare a proteggere i codebase AI/ML scansionando automaticamente i file pickle contenuti nei modelli. Fickling aggancia il modulo pickle e verifica le importazioni effettuate al caricamento di un modello. Controlla le importazioni solo rispetto a un allowlist di importazioni provenienti da librerie ML considerate sicure e blocca i file che contengono altre importazioni.
Aggiungi le seguenti righe il prima possibile, prima di importare torch, numpy o qualsiasi altra
libreria che usa pickle:
import fickling
# Questo imposta hook globali su pickle
fickling.hook.activate_safe_ml_environment()
Per rimuovere la protezione:
fickling.hook.deactivate_safe_ml_environment()
È possibile che i modelli che stai usando contengano importazioni non consentite da Fickling. Se vuoi comunque caricare il modello, puoi semplicemente consentire ulteriori importazioni per il tuo caso d'uso specifico con l'argomento also_allow:
fickling.hook.activate_safe_ml_environment(
also_allow=[
"some.import",
"another.allowed.import",
]
)
Importante: dovresti sempre assicurarti che le importazioni aggiunte manualmente siano effettivamente sicure e non consentano agli attaccanti di eseguire codice arbitrario. Se non sei sicuro di come fare, puoi aprire una issue sul repository GitHub di Fickling indicando le importazioni/modelli in questione, e il nostro team potrà revisionarli e includerli nell'allowlist se possibile.
Fickling può essere integrato senza soluzione di continuità nel tuo codebase per rilevare e bloccare il caricamento di file dannosi a runtime.
Di seguito mostriamo i diversi modi in cui puoi usare Fickling per applicare controlli di sicurezza sui file pickle.
Sotto il cofano, aggancia la libreria pickle per aggiungere controlli di sicurezza, così che il caricamento di un file pickle
sollevi un'eccezione UnsafeFileError se nel file viene rilevato contenuto dannoso.
# Questo applica i controlli di sicurezza ogni volta che pickle viene usato per deserializzare
fickling.always_check_safety()
# Tentare di caricare un file non sicuro ora solleva un'eccezione
with open("file.pkl", "rb") as f:
try:
pickle.load(f)
except fickling.UnsafeFileError:
print("File non sicuro!")
with fickling.check_safety():
# Tutti i file pickle caricati all'interno del context manager vengono controllati per la sicurezza
try:
with open("file.pkl", "rb") as f:
pickle.load("file.pkl")
except fickling.UnsafeFileError:
print("File non sicuro!")
# I file caricati al di fuori del context manager NON vengono controllati
pickle.load("file.pkl")
All'uscita, il context manager ripristina qualunque cosa fosse installata al momento dell'ingresso, quindi un hook già presente rimane in vigore invece di lasciare pickle senza hook.
# Usa fickling.load() al posto di pickle.load() per controllare la sicurezza e caricare un singolo file pickle
try:
fickling.load("file.pkl")
except fickling.UnsafeFileError as e:
print("File non sicuro!")
# Esegue un controllo di sicurezza su un file pickle senza caricarlo
if not fickling.is_likely_safe("file.pkl"):
print("File non sicuro!")
Puoi accedere ai dettagli dell'analisi di sicurezza di Fickling dall'interno dell'eccezione sollevata:
>>> 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]')"
]
}
}
}
Se stai usando un linguaggio diverso da Python, puoi comunque usare la CLI di Fickling per
verificare la sicurezza dei file pickle:
fickling --check-safety -p pickled.data
La CLI di Fickling consente di tracciare in modo sicuro l'esecuzione della macchina virtuale di Pickle senza
eseguire alcun codice dannoso:
fickling --trace file.pkl
Fickling consente di iniettare codice arbitrario in un file pickle che verrà eseguito ogni volta che il file viene caricato:
fickling --inject "print('Malicious')" file.pkl > malicious.pkl
Fickling può essere usato per decompilare un file pickle per ulteriori analisi:
>>> 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 contiene più formati di file con cui si possono creare file poliglotti, cioè file che possono essere interpretati validamente come più di un formato di file. Fickling supporta l'identificazione, l'ispezione e la creazione di poliglotti con i seguenti formati di file 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']
Dai un'occhiata ai nostri esempi per saperne di più sull'uso di Fickling!
Gli oggetti Python serializzati con pickle sono in realtà bytecode interpretato da una macchina virtuale basata su stack integrata in Python chiamata "Pickle Machine". Fickling può prendere flussi di dati serializzati e decompilarli in codice Python leggibile che, quando eseguito, deserializzerà l'oggetto serializzato originale. Questo è reso possibile dall'implementazione personalizzata della PM di Fickling. Fickling è sicuro da eseguire su file potenzialmente dannosi perché la sua PM esegue simbolicamente il codice piuttosto che eseguirlo apertamente.
Gli autori non attribuiscono alcun significato alla "F" in Fickling; potrebbe stare per "fickle" (volubile), ... o qualcos'altro. Decifrarne il significato è un viaggio personale di discrezione ed è lasciato come esercizio al lettore.
Scopri di più su Fickling nel nostro post sul blog e nel talk al DEF CON AI Village 2021.
Se desideri segnalare un bug o richiedere una funzionalità, usa la nostra pagina delle issues. Sentiti libero di contattarci o di rivolgerti a Empire Hacking per assistenza sull'uso o sull'estensione di Fickling.
Questa utilità è stata sviluppata da Trail of Bits. È distribuita sotto la GNU Lesser General Public License v3.0. Contattaci se stai cercando un'eccezione ai termini.
© 2021, Trail of Bits.