
Ficklingは、Pythonのpickleオブジェクトシリアライゼーションのためのデコンパイラ、静的アナライザ、およびバイトコードリライタです。Ficklingを使用すると、悪意のあるpickleファイルやpickleベースのファイル(PyTorchファイルを含む)を検出、分析、リバースエンジニアリング、さらには作成することもできます。
FicklingはPythonライブラリとしてもCLIとしても使用できます。
FicklingはPython 3.11以降が必要で、依存関係はごくわずかです。ライブラリとコマンドラインユーティリティの両方をpipまたはuvでインストールできます:
# Using pip
python -m pip install fickling
# Using uv
uv pip install fickling
PyTorchはFicklingのオプション依存関係です。したがって、Ficklingのpytorchモジュールとpolyglotモジュールを使用するには、以下を実行してください:
# Using pip
python -m pip install fickling[torch]
# Using uv
uv pip install fickling[torch]
Fickling は、モデルに含まれる pickle ファイルを自動的にスキャンすることで、AI/ML コードベースのセキュリティ保護を支援します。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",
]
)
重要: 手動で追加したインポートが実際に安全であり、攻撃者が任意のコードを実行できないことを常に確認する必要があります。その方法が不明な場合は、FicklingのGithubリポジトリで問題のインポート/モデルを示すissueを開くことができます。私たちのチームがそれらをレビューし、可能であれば許可リストに含めることができます。
Ficklingはコードベースにシームレスに統合して、実行時に悪意あるファイルの読み込みを検出して停止することができます。
以下では、pickleファイルに対して安全チェックを強制するためにficklingを使用するさまざまな方法を示します。内部的には、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以外の言語を使用している場合でも、ficklingのCLIを使用してpickleファイルの安全性をチェックできます:
fickling --check-safety -p pickled.data
Fickling の CLI を使用すると、悪意のあるコードを実行することなく、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 の使い方について詳しくは、サンプルをご覧ください!
Pickle 化された Python オブジェクトは、実際には Python に組み込まれた「Pickle Machine」と呼ばれるスタックベースの仮想マシンによって解釈されるバイトコードです。Fickling は Pickle 化されたデータストリームを受け取り、人間が読める Python コードに逆コンパイルできます。このコードを実行すると、元のシリアライズされたオブジェクトにデシリアライズされます。これは Fickling による PM の独自実装によって実現されています。Fickling はコードを明示的に実行するのではなく、シンボリックに実行するため、潜在的に悪意のあるファイルに対しても安全に実行できます。
著者らは Fickling の「F」に特定の意味を定めていません。「fickle(気まぐれな)」を表すこともあれば、… それ以外の何かを表すこともあります。その意味を占うことは、分別に基づく個人的な旅であり、読者への課題として残されています。
fickling について詳しくは、ブログ記事および DEF CON AI Village 2021 の講演をご覧ください。
バグ報告や機能リクエストは、issues ページをご利用ください。 fickling の使用や拡張についてのサポートが必要な場合は、お気軽にご連絡いただくか、Empire Hacking でお問い合わせください。
このユーティリティは Trail of Bits によって開発されました。 GNU Lesser General Public License v3.0 の下でライセンスされています。 条項の例外をお探しの場合は、お問い合わせください。
© 2021, Trail of Bits.