
Um decompilador de pickling Python e analisador estático

Fickling é um descompilador, analisador estático e reescritor de bytecode para serializações de objetos pickle do Python. Você pode usar o fickling para detectar, analisar, fazer engenharia reversa ou até mesmo criar arquivos pickle maliciosos ou baseados em pickle, incluindo arquivos PyTorch.
O Fickling pode ser usado tanto como biblioteca python quanto como CLI.
Fickling foi testado no Python 3.9 até o Python 3.13 e tem muito poucas dependências. Tanto a biblioteca quanto o utilitário de linha de comando podem ser instalados via pip ou uv:
# Using pip
python -m pip install fickling
# Using uv
uv pip install fickling
PyTorch é uma dependência opcional do Fickling. Portanto, para usar os módulos pytorch e polyglot do Fickling, você deve executar:
# Using pip
python -m pip install fickling[torch]
# Using uv
uv pip install fickling[torch]
O Fickling pode ajudar a proteger bases de código de IA/ML ao escanear automaticamente arquivos pickle contidos em modelos. O Fickling intercepta o módulo pickle e verifica as importações feitas ao carregar um modelo. Ele verifica as importações apenas contra uma lista de permissões de importações de bibliotecas de ML consideradas seguras e bloqueia arquivos que contenham outras importações.
Adicione as seguintes linhas o mais cedo possível, antes de importar torch, numpy ou qualquer outra biblioteca que use pickle:
import fickling
# This sets global hooks on pickle
fickling.hook.activate_safe_ml_environment()
Para remover a proteção:
fickling.hook.deactivate_safe_ml_environment()
É possível que os modelos que você está usando contenham importações que não são permitidas pelo Fickling. Se você ainda quiser carregar o modelo, basta permitir importações adicionais para seu caso de uso específico com o argumento also_allow:
fickling.hook.activate_safe_ml_environment(
also_allow=[
"some.import",
"another.allowed.import",
]
)
Importante: Você deve sempre garantir que importações adicionadas manualmente sejam realmente seguras e não possam permitir que atacantes executem código arbitrário. Se você não tiver certeza de como fazer isso, abra uma issue no repositório do Fickling no Github indicando as importações/modelos em questão, e nossa equipe poderá revisá-los e incluí-los na lista de permissões, se possível.
O Fickling pode ser integrado perfeitamente à sua base de código para detectar e interromper o carregamento de arquivos maliciosos em tempo de execução.
Abaixo mostramos as diferentes maneiras de usar o fickling para aplicar verificações de segurança em arquivos pickle. Internamente, ele intercepta a biblioteca pickle para adicionar verificações de segurança, de modo que carregar um arquivo pickle levanta uma exceção UnsafeFileError se conteúdo malicioso for detectado no arquivo.
# 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")
Ao sair, o gerenciador de contexto restaura o que estava instalado quando foi iniciado, de modo que um hook já existente permanece em vigor em vez de o pickle ficar sem 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!")
Você pode acessar os detalhes da análise de segurança do fickling a partir da exceção levantada:
>>> 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 você estiver usando outra linguagem além de Python, ainda pode usar o CLI do fickling para verificar a segurança de arquivos pickle:
fickling --check-safety -p pickled.data
O CLI do Fickling permite rastrear com segurança a execução da máquina virtual Pickle sem executar nenhum código malicioso:
fickling --trace file.pkl
O Fickling permite injetar código arbitrário em um arquivo pickle que será executado toda vez que o arquivo for carregado
fickling --inject "print('Malicious')" file.pkl > malicious.pkl
O Fickling pode ser usado para descompilar um arquivo pickle para análises adicionais
>>> 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=[])
O PyTorch contém vários formatos de arquivo com os quais é possível criar arquivos poliglotas, que são arquivos que podem ser interpretados validamente como mais de um formato de arquivo. O Fickling suporta identificar, inspecionar e criar poliglotas com os seguintes formatos de arquivo do 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']
Confira nossos exemplos para saber mais sobre como usar o fickling!
Objetos Python em pickle são, na verdade, bytecode interpretado por uma máquina virtual baseada em pilha embutida no Python chamada "Pickle Machine". O Fickling pode pegar fluxos de dados em pickle e descompilá-los em código Python legível por humanos que, quando executado, desserializará o objeto serializado original. Isso é possível graças à implementação personalizada da PM pelo Fickling. O Fickling é seguro para executar em arquivos potencialmente maliciosos porque sua PM executa código simbolicamente, em vez de executá-lo de forma direta.
Os autores não atribuem nenhum significado ao “F” em Fickling; ele poderia significar “fickle” (volúvel), … ou outra coisa. Decifrar seu significado é uma jornada pessoal de discrição e fica como exercício para o leitor.
Saiba mais sobre o fickling em nosso post no blog e na palestra do DEF CON AI Village 2021.
Se você quiser reportar um bug ou solicitar um recurso, use nossa página de issues. Sinta-se à vontade para nos contatar ou procurar ajuda no Empire Hacking para usar ou estender o fickling.
Este utilitário foi desenvolvido pela Trail of Bits. Ele é licenciado sob a GNU Lesser General Public License v3.0. Entre em contato se você estiver procurando uma exceção aos termos.
© 2021, Trail of Bits.