Analyse des Mécanismes de Chiffrement des Ransomwares
Quand l'utiliser
- Une infection par ransomware a eu lieu et la récupération nécessite de comprendre le schéma de chiffrement utilisé
- Évaluer si un déchiffrement est possible sans payer la rançon (défauts d'implémentation, outils de déchiffrement connus)
- Rétro-ingénierie d'un ransomware pour identifier l'algorithme de chiffrement, la dérivation de clé et le mécanisme de stockage des clés
- Développer un outil de déchiffrement lorsqu'une faiblesse dans l'implémentation cryptographique du ransomware est identifiée
- Classifier un échantillon de ransomware par son approche de chiffrement pour l'attribuer à une famille connue
Ne pas utiliser pour des opérations de récupération de données en production sans avoir d'abord vérifié la méthode de déchiffrement sur des copies de test des fichiers chiffrés.
Prérequis
- Ghidra ou IDA Pro pour la rétro-ingénierie du binaire du ransomware
- Python 3.8+ avec la bibliothèque
pycryptodomepour tester les routines de chiffrement/déchiffrement - Échantillons de fichiers chiffrés et leurs originaux en clair correspondants (paires clair-chiffré connues)
- Accès au binaire du ransomware (dépaqueté si applicable)
- Connaissance des algorithmes cryptographiques symétriques (AES, ChaCha20) et asymétriques (RSA)
- Base de données NoMoreRansom.org pour vérifier l'existence d'outils de déchiffrement gratuits
Workflow
Étape 1 : Identifier l'algorithme de chiffrement
Déterminer quel algorithme cryptographique le ransomware utilise :
# Vérifier l'utilisation de l'API Crypto Windows dans les imports
import pefile
pe = pefile.PE("ransomware.exe")
crypto_apis = {
"CryptAcquireContextA": "Windows CryptoAPI",
"CryptAcquireContextW": "Windows CryptoAPI",
"CryptGenKey": "Génération de clé Windows CryptoAPI",
"CryptEncrypt": "Chiffrement Windows CryptoAPI",
"CryptImportKey": "Importation de clé Windows CryptoAPI",
"BCryptOpenAlgorithmProvider": "Windows CNG (crypto moderne)",
"BCryptEncrypt": "Chiffrement Windows CNG",
"BCryptGenerateKeyPair": "Génération de paire de clés asymétriques Windows CNG",
}
print("Imports Crypto API :")
for entry in pe.DIRECTORY_ENTRY_IMPORT:
for imp in entry.imports:
if imp.name and imp.name.decode() in crypto_apis:
print(f" {entry.dll.decode()} -> {imp.name.decode()}: {crypto_apis[imp.name.decode()]}")
Schémas de chiffrement courants des ransomwares :
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
AES-256-CBC + RSA-2048 : Schéma hybride le plus courant (LockBit, REvil, Conti)
AES-256-CTR + RSA-4096 : Variante en mode flux (BlackCat/ALPHV)
ChaCha20 + RSA-4096 : Chiffrement de flux moderne (Hive, Royal)
Salsa20 + ECDH : Échange de clés Curve25519 (Babuk)
AES-128-ECB : Mode faible - déchiffrement potentiel via texte clair connu
XOR uniquement : Chiffrement trivial - toujours récupérable
Algorithme personnalisé : Contient souvent des défauts d'implémentation
Étape 2 : Analyser la génération et la gestion des clés
Rétro-ingénierie de la manière dont les clés de chiffrement sont générées et stockées :
Modèles de gestion des clés dans les ransomwares :
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. FORT (aucune récupération possible sans la clé) :
- Clé AES par fichier générée avec CryptGenRandom
- Clé AES chiffrée avec la clé publique RSA intégrée
- Clé chiffrée ajoutée à chaque fichier ou stockée séparément
- Clé privée RSA détenue uniquement par le serveur C2 de l'attaquant
2. FAIBLE (récupération potentielle) :
- Clé AES dérivée d'une graine prévisible (timestamp, PID)
- Même clé AES utilisée pour tous les fichiers (compromission d'une seule clé = récupération totale)
- Clé transmise au C2 avant le début du chiffrement (la capture PCAP peut contenir la clé)
- XOR avec une clé répétitive courte (bruteforçable)
- PRNG initialisé avec GetTickCount ou time() (espace de clés limité)
3. IMPLÉMENTATION DÉFECTUEUSE :
- Mode ECB (préserve les motifs du texte clair)
- Réutilisation du vecteur d'initialisation (IV) entre les fichiers
- Clé stockée en clair en mémoire (récupérable à partir d'un dump mémoire)
- Chiffrement partiel (seuls les premiers N octets sont chiffrés)
Étape 3 : Examiner la routine de chiffrement des fichiers
Rétro-ingénierie de la logique de traitement des fichiers :
// Flux de chiffrement typique d'un ransomware (pseudo-code décompilé depuis Ghidra) :
void encrypt_file(char *filepath) {
// 1. Vérifier l'extension du fichier par rapport à la liste cible
if (!is_target_extension(filepath)) return;
// 2. Générer une clé AES par fichier (32 octets pour AES-256)
BYTE aes_key[32];
CryptGenRandom(hProv, 32, aes_key);
// 3. Générer un IV aléatoire (16 octets)
BYTE iv[16];
CryptGenRandom(hProv, 16, iv);
// 4. Lire le contenu du fichier
HANDLE hFile = CreateFile(filepath, GENERIC_READ, ...);
BYTE *plaintext = read_entire_file(hFile);
// 5. Chiffrer avec AES-256-CBC
aes_cbc_encrypt(plaintext, file_size, aes_key, iv);
// 6. Chiffrer la clé AES avec la clé publique RSA
BYTE encrypted_key[256]; // Sortie RSA-2048
rsa_encrypt(aes_key, 32, rsa_pubkey, encrypted_key);
// 7. Écrire : données_chiffrées + clé_chiffrée + IV dans le fichier
write_file(filepath, encrypted_data, encrypted_key, iv);
// 8. Renommer le fichier avec l'extension du ransomware
rename_file(filepath, strcat(filepath, ".locked"));
}
Étape 4 : Vérifier les faiblesses cryptographiques
Tester l'implémentation pour des défauts exploitables :
from Crypto.Cipher import AES
import os
import struct
# Test 1 : Vérifier si la même clé est utilisée pour plusieurs fichiers
# Comparer les versions chiffrées de fichiers connus
def check_key_reuse(file1_enc, file2_enc):
with open(file1_enc, "rb") as f:
data1 = f.read()
with open(file2_enc, "rb") as f:
data2 = f.read()
# Extraire les IV (l'emplacement dépend de la famille de ransomware)
# Si les IV sont identiques et que les fichiers partagent des blocs chiffrés -> même clé
iv1 = data1[-16:] # Exemple : IV à la fin
iv2 = data2[-16:]
if iv1 == iv2:
print("[!] Même IV détecté - réutilisation de clé probable")
# Test 2 : Vérifier une dérivation de clé prévisible
# Si la clé est dérivée d'un timestamp, itérer sur les valeurs possibles
def brute_force_timestamp_key(encrypted_file, known_header, timestamp_range):
with open(encrypted_file, "rb") as f:
encrypted_data = f.read()
for ts in timestamp_range:
# Dériver la clé de la même manière que le ransomware
import hashlib
key = hashlib.sha256(str(ts).encode()).digest()
iv = encrypted_data[-16:]
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(encrypted_data[:16])
if decrypted[:len(known_header)] == known_header:
print(f"[!] Clé trouvée ! Timestamp : {ts}")
return key
return None
# Test 3 : Vérifier le mode ECB (préservation des motifs)
def check_ecb_mode(encrypted_file):
with open(encrypted_file, "rb") as f:
data = f.read()
# ECB produit un texte chiffré identique pour des blocs de texte clair identiques
blocks = [data[i:i+16] for i in range(0, len(data), 16)]
unique = len(set(blocks))
total = len(blocks)
if unique < total * 0.95:
print(f"[!] Mode ECB probable : {total-unique} blocs en double sur {total}")
Étape 5 : Tenter la récupération de clé
Utiliser les faiblesses identifiées pour la récupération de clé :
# Méthode de récupération 1 : Extraire la clé d'un dump mémoire
# Plugin Volatility pour scanner les schémas de clé AES
# vol3 -f memory.dmp windows.yarascan --yara-rule "aes_key_schedule"
# Méthode de récupération 2 : Attaque par texte clair connu (algorithmes faibles)
def xor_key_recovery(encrypted_file, known_plaintext):
"""Récupérer la clé XOR à partir d'une paire texte clair-texte chiffré connue"""
with open(encrypted_file, "rb") as f:
ciphertext = f.read()
key = bytes(c ^ p for c, p in zip(ciphertext, known_plaintext))
# Trouver la longueur de la clé répétée
for key_len in range(1, 256):
candidate = key[:key_len]
if all(key[i] == candidate[i % key_len] for i in range(min(len(key), key_len * 4))):
print(f"Clé XOR (longueur {key_len}) : {candidate.hex()}")
return candidate
return None
# Méthode de récupération 3 : Vérifier NoMoreRansom pour des outils de déchiffrement existants
# https://www.nomoreransom.org/en/decryption-tools.html
Étape 6 : Documenter l'analyse du chiffrement
Compiler les résultats dans un rapport structuré :
L'analyse doit documenter :
- Algorithme identifié (AES, RSA, ChaCha20, personnalisé)
- Taille de clé et mode de fonctionnement (CBC, CTR, ECB, GCM)
- Méthode de génération de clé (CSPRNG, graine prévisible, clé statique)
- Emplacement de stockage de la clé (ajoutée au fichier, registre, transmission C2)
- Motif de modification des fichiers (chiffrement complet, partiel, uniquement l'en-tête)
- Extensions de fichiers ciblées
- Format de la note de rançon et infrastructure de paiement
- Évaluation de la faisabilité du déchiffrement (possible/impossible/partiel)
- Approche de récupération recommandée
Concepts clés
| Terme | Définition |
|---|---|
| Chiffrement hybride | Combinaison d'un chiffrement symétrique (AES) pour un chiffrement rapide des fichiers avec un chiffrement asymétrique (RSA) pour un encapsulement sécurisé des clés ; approche standard des ransomwares |
| Encapsulement de clé | Chiffrement de la clé symétrique par fichier avec la clé publique RSA de l'attaquant afin que seule la clé privée de l'attaquant puisse la déchiffrer |
| Mode ECB | Le mode Electronic Codebook chiffre chaque bloc indépendamment ; préserve les motifs du texte clair, une faiblesse critique permettant une récupération partielle |
| Attaque par texte clair connu | Utilisation d'un fichier original connu et de sa version chiffrée pour en déduire la clé de chiffrement ; efficace contre XOR et les chiffrements de flux faibles |
| Schéma de clé | La forme développée d'une clé AES en mémoire ; analysable dans les dumps mémoire pour récupérer les clés de chiffrement avant qu'elles ne soient effacées |
| CSPRNG | Générateur de nombres pseudo-aléatoires cryptographiquement sûr ; les ransomwares utilisant CryptGenRandom produisent des clés imprévisibles |
| Chiffrement partiel | Certains ransomwares ne chiffrent que les N premiers octets ou un bloc sur N pour plus de rapidité ; les portions non chiffrées peuvent faciliter la récupération |
Outils et systèmes
- Ghidra : Suite de rétro-ingénierie pour analyser les routines de chiffrement des ransomwares au niveau assembleur
- PyCryptodome : Bibliothèque cryptographique Python pour implémenter et tester les routines de déchiffrement
- NoMoreRansom.org : Répertoire d'outils de déchiffrement gratuits maintenu par Europol et des éditeurs de sécurité pour les familles de ransomwares connues
- Volatility : Framework de criminalistique mémoire pour extraire les clés de chiffrement des dumps RAM des systèmes infectés
- CryptoTester : Outil pour identifier les algorithmes cryptographiques basés sur des constantes et des motifs de code
Scénarios courants
Scénario : Évaluer la faisabilité du déchiffrement pour un incident ransomware
Contexte : Une organisation est victime d'un ransomware chiffrant les serveurs de fichiers. La direction a besoin de savoir si un déchiffrement est possible sans payer la rançon avant de prendre une décision de récupération.
Approche :
- Identifier la famille de ransomware à partir de la note de rançon, de l'extension de fichier et du hash de l'échantillon (vérifier ID Ransomware)
- Vérifier NoMoreRansom.org pour des outils de déchiffrement gratuits existants pour cette famille
- Rétro-ingénierie de la routine de chiffrement dans Ghidra pour identifier l'algorithme et la gestion des clés
- Tester les faiblesses d'implémentation (réutilisation de clé, graines prévisibles, mode ECB)
- Vérifier si une capture PCAP de l'incident a capturé la transmission de la clé au C2 (si la clé a été envoyée avant le chiffrement)
- Analyser les dumps mémoire des machines affectées pour rechercher les schémas de clé AES dans la RAM
- Rapporter les résultats : déchiffrement possible/impossible avec une justification technique spécifique
Pièges à éviter :
- Tester les méthodes de déchiffrement sur la seule copie des fichiers chiffrés (toujours travailler sur des copies)
- Supposer que tous les fichiers utilisent la même clé sans vérifier (certains ransomwares utilisent des clés par fichier)
- Ne pas vérifier les copies fantômes de volumes (vssadmin) que le ransomware peut avoir échoué à supprimer
- Confondre l'algorithme de chiffrement des fichiers avec l'algorithme d'encapsulement de clé dans les rapports
Format de sortie
ANALYSE DU CHIFFREMENT DU RANSOMWARE
======================================
Échantillon : lockbit3.exe
Famille : LockBit 3.0 / LockBit Black
SHA-256 : abc123def456...
SCHÉMA DE CHIFFREMENT
Chiffrement fichier : AES-256-CTR (clé unique par fichier)
Encapsulement clé : RSA-2048 (clé publique intégrée au binaire)
Génération de clé : CryptGenRandom (CSPRNG - imprévisible)
Génération de IV : 16 octets aléatoires par fichier
Structure fichier : [données_chiffrées][clé_chiffrée_RSA(256B)][IV(16B)][magique(8B)]
EXTENSIONS CIBLÉES
Total : 412 extensions ciblées
Catégories : Documents (.doc, .xls, .pdf), Bases de données (.sql, .mdb),
Archives (.zip, .7z), Code source (.py, .java, .cs)
Exclues : .exe, .dll, .sys, .lnk (fichiers système préservés)
ANALYSE DE L'IMPLÉMENTATION
Force de la clé : FORT - clés aléatoires par fichier, pas de réutilisation
Sécurité du mode : FORT - mode CTR avec nonces uniques
Stockage de la clé : Clé chiffrée RSA ajoutée à chaque fichier
Copies fantômes : Supprimées via vssadmin et WMI
FAISABILITÉ DU DÉCHIFFREMENT
Sans la clé : NON POSSIBLE
- Aucun défaut d'implémentation identifié
- L'encapsulement de clé RSA-2048 empêche le brute force
- le CSPRNG empêche la prédiction de clé
- Aucun outil de déchiffrement gratuit existant
OPTIONS DE RÉCUPÉRATION
1. Restaurer à partir de sauvegardes hors ligne (recommandé)
2. Vérifier les copies fantômes de volumes (faible probabilité - le ransomware les supprime)
3. Criminalistique mémoire si la machine n'a pas été redémarrée (la clé peut persister dans la RAM)
4. Négocier avec l'attaquant (dernier recours - aucune garantie de déchiffrement)