
Fickling は、Python の pickle オブジェクトシリアライゼーションのための逆コンパイラ、静的解析ツール、およびバイトコードリライタです。Fickling を使用すると、PyTorch ファイルを含む悪意のある pickle または pickle ベースのファイルを検出、解析、リバースエンジニアリング、あるいは作成することもできます。
Fickling は、Python ライブラリと CLI の両方として使用できます。
Fickling は Python 3.9 から Python 3.13 まででテストされており、依存関係はほとんどありません。ライブラリとコマンドライン ユーティリティの両方を 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",
]
)
重要: 手動で追加したインポートが実際に安全であり、攻撃者が任意のコードを実行できるようにならないことを常に確認してください。その方法がわからない場合は、該当するインポート/モデルを示す issue を Fickling の GitHub リポジトリに開いてください。可能であれば、チームがそれらを確認し、許可リストに含めます。
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 は、潜在的に悪意のあるファイルに対して安全に実行できます。その PM がコードを明示的に実行するのではなく、シンボリックに実行するためです。
著者は 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.