Análisis de Mecanismos de Cifrado de Ransomware
Cuándo Usarlo
- Ha ocurrido una infección de ransomware y la recuperación requiere entender el esquema de cifrado utilizado
- Evaluar si es posible descifrar sin pagar el rescate (fallos de implementación, descifradores conocidos)
- Realizar ingeniería inversa de ransomware para identificar el algoritmo de cifrado, la derivación de claves y el mecanismo de almacenamiento de claves
- Desarrollar una herramienta de descifrado cuando se identifica una debilidad en la implementación criptográfica del ransomware
- Clasificar una muestra de ransomware por su enfoque de cifrado para atribuirla a una familia conocida
No usar para operaciones de recuperación de datos en producción sin antes verificar el método de descifrado en copias de prueba de los archivos cifrados.
Requisitos Previos
- Ghidra o IDA Pro para ingeniería inversa del binario de ransomware
- Python 3.8+ con la biblioteca
pycryptodomepara probar rutinas de cifrado/descifrado - Archivos cifrados de muestra y sus originales en texto plano correspondientes (pares de texto plano conocido)
- Acceso al binario de ransomware (desempaquetado si corresponde)
- Familiaridad con algoritmos criptográficos simétricos (AES, ChaCha20) y asimétricos (RSA)
- Base de datos NoMoreRansom.org para comprobar descifradores gratuitos existentes
Flujo de Trabajo
Paso 1: Identificar el Algoritmo de Cifrado
Determinar qué algoritmo criptográfico utiliza el ransomware:
# Verificar el uso de Windows Crypto API en las importaciones
import pefile
pe = pefile.PE("ransomware.exe")
crypto_apis = {
"CryptAcquireContextA": "Windows CryptoAPI",
"CryptAcquireContextW": "Windows CryptoAPI",
"CryptGenKey": "Generación de claves Windows CryptoAPI",
"CryptEncrypt": "Cifrado Windows CryptoAPI",
"CryptImportKey": "Importación de claves Windows CryptoAPI",
"BCryptOpenAlgorithmProvider": "Windows CNG (criptografía moderna)",
"BCryptEncrypt": "Cifrado Windows CNG",
"BCryptGenerateKeyPair": "Generación de claves asimétricas Windows CNG",
}
print("Importaciones 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()]}")
Esquemas Comunes de Cifrado en Ransomware:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
AES-256-CBC + RSA-2048: Esquema híbrido más común (LockBit, REvil, Conti)
AES-256-CTR + RSA-4096: Variante de modo de flujo (BlackCat/ALPHV)
ChaCha20 + RSA-4096: Cifrado de flujo moderno (Hive, Royal)
Salsa20 + ECDH: Intercambio de claves Curve25519 (Babuk)
AES-128-ECB: Modo débil - posible descifrado mediante texto plano conocido
Solo XOR: Cifrado trivial - siempre recuperable
Algoritmo personalizado: A menudo contiene fallos de implementación
Paso 2: Analizar la Generación y Gestión de Claves
Realizar ingeniería inversa de cómo se generan y almacenan las claves de cifrado:
Patrones de Gestión de Claves en Ransomware:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. FUERTE (no es posible recuperación sin clave):
- Clave AES por archivo generada con CryptGenRandom
- Clave AES cifrada con clave pública RSA incrustada
- Clave cifrada añadida a cada archivo o almacenada por separado
- Clave privada RSA solo en poder del servidor C2 del atacante
2. DÉBIL (recuperación potencial):
- Clave AES derivada de una semilla predecible (marca de tiempo, PID)
- Misma clave AES utilizada para todos los archivos (comprometer una clave = recuperación completa)
- Clave transmitida al C2 antes de iniciar el cifrado (la captura de paquetes puede contener la clave)
- XOR con clave corta repetitiva (factible por fuerza bruta)
- PRNG con semilla de GetTickCount o time() (espacio de claves limitado)
3. IMPLEMENTACIÓN DEFECTUOSA:
- Modo ECB (preserva patrones del texto plano)
- Reutilización del vector de inicialización (IV) entre archivos
- Clave almacenada en texto plano en memoria (recuperable desde un volcado de memoria)
- Cifrado parcial (solo los primeros N bytes cifrados)
Paso 3: Examinar la Rutina de Cifrado de Archivos
Realizar ingeniería inversa de la lógica de procesamiento de archivos:
// Flujo típico de cifrado de archivos en ransomware (pseudocódigo descompilado de Ghidra):
void encrypt_file(char *filepath) {
// 1. Verificar la extensión del archivo contra la lista de objetivos
if (!is_target_extension(filepath)) return;
// 2. Generar clave AES por archivo (32 bytes para AES-256)
BYTE aes_key[32];
CryptGenRandom(hProv, 32, aes_key);
// 3. Generar IV aleatorio (16 bytes)
BYTE iv[16];
CryptGenRandom(hProv, 16, iv);
// 4. Leer el contenido del archivo
HANDLE hFile = CreateFile(filepath, GENERIC_READ, ...);
BYTE *plaintext = read_entire_file(hFile);
// 5. Cifrar con AES-256-CBC
aes_cbc_encrypt(plaintext, file_size, aes_key, iv);
// 6. Cifrar la clave AES con la clave pública RSA
BYTE encrypted_key[256]; // Salida RSA-2048
rsa_encrypt(aes_key, 32, rsa_pubkey, encrypted_key);
// 7. Escribir: datos_cifrados + clave_cifrada + IV en el archivo
write_file(filepath, encrypted_data, encrypted_key, iv);
// 8. Renombrar archivo con extensión del ransomware
rename_file(filepath, strcat(filepath, ".locked"));
}
Paso 4: Verificar Debilidades Criptográficas
Probar la implementación en busca de fallos explotables:
from Crypto.Cipher import AES
import os
import struct
# Prueba 1: Verificar si se usa la misma clave para múltiples archivos
# Comparar versiones cifradas de archivos conocidos
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()
# Extraer IVs (la ubicación depende de la familia de ransomware)
# Si los IVs son iguales y los archivos comparten bloques cifrados -> misma clave
iv1 = data1[-16:] # Ejemplo: IV al final
iv2 = data2[-16:]
if iv1 == iv2:
print("[!] Mismo IV detectado - probable reutilización de clave")
# Prueba 2: Verificar derivación de clave predecible
# Si la clave se deriva de la marca de tiempo, iterar valores posibles
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:
# Derivar clave de la misma manera que lo hace el 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"[!] Clave encontrada! Marca de tiempo: {ts}")
return key
return None
# Prueba 3: Verificar modo ECB (preservación de patrones)
def check_ecb_mode(encrypted_file):
with open(encrypted_file, "rb") as f:
data = f.read()
# ECB produce texto cifrado idéntico para bloques de texto plano idénticos
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"[!] Modo ECB probable: {total-unique} bloques duplicados de {total}")
Paso 5: Intentar Recuperación de Clave
Usar debilidades identificadas para la recuperación de claves:
# Método de recuperación 1: Extraer clave de volcado de memoria
# Plugin de Volatility para escanear programas de claves AES
# vol3 -f memory.dmp windows.yarascan --yara-rule "aes_key_schedule"
# Método de recuperación 2: Ataque de texto plano conocido (algoritmos débiles)
def xor_key_recovery(encrypted_file, known_plaintext):
"""Recuperar clave XOR a partir de un par texto plano-texto cifrado conocido"""
with open(encrypted_file, "rb") as f:
ciphertext = f.read()
key = bytes(c ^ p for c, p in zip(ciphertext, known_plaintext))
# Encontrar longitud de clave repetitiva
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"Clave XOR (longitud {key_len}): {candidate.hex()}")
return candidate
return None
# Método de recuperación 3: Verificar NoMoreRansom para descifradores existentes
# https://www.nomoreransom.org/es/decryption-tools.html
Paso 6: Documentar el Análisis de Cifrado
Recopilar hallazgos en un informe estructurado:
El análisis debe documentar:
- Algoritmo identificado (AES, RSA, ChaCha20, personalizado)
- Tamaño de clave y modo de operación (CBC, CTR, ECB, GCM)
- Método de generación de clave (CSPRNG, semilla predecible, clave estática)
- Ubicación de almacenamiento de clave (añadida al archivo, registro, transmisión a C2)
- Patrón de modificación de archivos (cifrado completo, parcial, solo cabecera)
- Extensiones de archivo objetivo
- Formato de la nota de rescate e infraestructura de pago
- Evaluación de viabilidad de descifrado (posible/imposible/parcial)
- Enfoque de recuperación recomendado
Conceptos Clave
| Término | Definición |
|---|---|
| Cifrado Híbrido | Combinación de cifrado simétrico (AES) para cifrado rápido de archivos con asimétrico (RSA) para envoltura segura de claves; el enfoque estándar del ransomware |
| Envoltura de Clave | Cifrar la clave simétrica por archivo con la clave pública RSA del atacante para que solo la clave privada del atacante pueda descifrarla |
| Modo ECB | El modo Electronic Codebook cifra cada bloque de forma independiente; preserva patrones en el texto plano, una debilidad crítica que permite recuperación parcial |
| Ataque de Texto Plano Conocido | Usar un archivo original conocido y su versión cifrada para derivar la clave de cifrado; efectivo contra XOR y cifrados de flujo débiles |
| Programa de Claves | La forma expandida de una clave AES en memoria; escaneable en volcados de memoria para recuperar claves de cifrado antes de que se borren |
| CSPRNG | Generador de Números Pseudoaleatorios Criptográficamente Seguro; el ransomware que usa CryptGenRandom produce claves impredecibles |
| Cifrado Parcial | Algunos ransomware solo cifran los primeros N bytes o cada N bloque por velocidad; las porciones no cifradas pueden ayudar en la recuperación |
Herramientas y Sistemas
- Ghidra: Suite de ingeniería inversa para analizar rutinas de cifrado de ransomware a nivel de ensamblador
- PyCryptodome: Biblioteca criptográfica de Python para implementar y probar rutinas de descifrado
- NoMoreRansom.org: Repositorio gratuito de herramientas de descifrado mantenido por Europol y proveedores de seguridad para familias conocidas de ransomware
- Volatility: Marco de análisis forense de memoria para extraer claves de cifrado de volcados de RAM de sistemas infectados
- CryptoTester: Herramienta para identificar algoritmos criptográficos basados en constantes y patrones de código
Escenarios Comunes
Escenario: Evaluación de Viabilidad de Descifrado para un Incidente de Ransomware
Contexto: Una organización sufre un ataque de ransomware que cifra servidores de archivos. La dirección necesita saber si es posible descifrar sin pagar el rescate antes de tomar una decisión de recuperación.
Enfoque:
- Identificar la familia de ransomware a partir de la nota de rescate, la extensión de archivo y el hash de la muestra (verificar con ID Ransomware)
- Consultar NoMoreRansom.org para buscar descifradores gratuitos existentes para esta familia
- Realizar ingeniería inversa de la rutina de cifrado en Ghidra para identificar el algoritmo y la gestión de claves
- Probar debilidades de implementación (reutilización de claves, semillas predecibles, modo ECB)
- Verificar si la captura de paquetes (PCAP) del incidente capturó la transmisión de la clave al C2 (si la clave se envió antes del cifrado)
- Escanear volcados de memoria de las máquinas afectadas en busca de programas de claves AES en RAM
- Informar hallazgos: descifrado posible/imposible con justificación técnica específica
Errores Comunes:
- Probar métodos de descifrado en la única copia de archivos cifrados (siempre trabajar con copias)
- Asumir que todos los archivos usan la misma clave sin verificar (algunos ransomware usan claves por archivo)
- No verificar las copias de sombra de volumen (vssadmin) que el ransomware pudo no haber eliminado
- Confundir el algoritmo de cifrado de archivos con el algoritmo de envoltura de claves en los informes
Formato de Salida
ANÁLISIS DE CIFRADO DE RANSOMWARE
===================================
Muestra: lockbit3.exe
Familia: LockBit 3.0 / LockBit Black
SHA-256: abc123def456...
ESQUEMA DE CIFRADO
Cifrado de archivos: AES-256-CTR (clave única por archivo)
Envoltura de clave: RSA-2048 (clave pública incrustada en el binario)
Generación de clave: CryptGenRandom (CSPRNG - impredecible)
Generación de IV: 16 bytes aleatorios por archivo
Estructura del archivo: [datos_cifrados][clave_rsa_cifrada(256B)][iv(16B)][magic(8B)]
EXTENSIONES OBJETIVO
Total: 412 extensiones objetivo
Categorías: Documentos (.doc, .xls, .pdf), Bases de datos (.sql, .mdb),
Archivos (.zip, .7z), Código fuente (.py, .java, .cs)
Excluidas: .exe, .dll, .sys, .lnk (archivos de sistema preservados)
ANÁLISIS DE IMPLEMENTACIÓN
Fortaleza de clave: FUERTE - claves aleatorias por archivo, sin reutilización
Seguridad del modo: FUERTE - modo CTR con nonces únicos
Almacenamiento de clave: Clave cifrada con RSA añadida a cada archivo
Copias de sombra: Eliminadas mediante vssadmin y WMI
VIABILIDAD DE DESCIFRADO
Sin clave: NO ES POSIBLE
- No se identificaron fallos de implementación
- Envoltura de clave RSA-2048 evita fuerza bruta
- CSPRNG impide predicción de clave
- No hay descifrador gratuito disponible
OPCIONES DE RECUPERACIÓN
1. Restaurar desde copias de seguridad fuera de línea (recomendado)
2. Verificar copias de sombra de volumen (baja probabilidad - el ransomware las elimina)
3. Análisis forense de memoria si la máquina no se reinició (la clave puede persistir en RAM)
4. Negociar con el atacante (último recurso - sin garantía de descifrado)