{"version":"1.1","tactics":["monetization","positioning"],"techniques":[{"id":"F1018","name":"Convert to Cryptocurrency","tactic":"monetization","source":"f3"},{"id":"F1047","name":"Transfer of funds","tactic":"monetization","source":"f3"},{"id":"T1219","name":"Remote Access Tools","tactic":"positioning","source":"attack"}]}
Analyzing Ransomware Encryption Mechanisms
When to Use
A ransomware infection has occurred and recovery requires understanding the encryption scheme used
Assessing whether decryption is possible without paying the ransom (implementation flaws, known decryptors)
Reverse engineering ransomware to identify the encryption algorithm, key derivation, and key storage mechanism
Developing a decryptor tool when a weakness in the ransomware's cryptographic implementation is identified
Classifying a ransomware sample by its encryption approach to attribute it to a known family
Do not use for production data recovery operations without first verifying the decryption method on test copies of encrypted files.
Prerequisites
Ghidra or IDA Pro for reverse engineering the ransomware binary
Python 3.8+ with pycryptodome library for testing encryption/decryption routines
Sample encrypted files and their corresponding plaintext originals (known-plaintext pairs)
Access to the ransomware binary (unpacked if applicable)
Familiarity with symmetric (AES, ChaCha20) and asymmetric (RSA) cryptographic algorithms
NoMoreRansom.org database for checking existing free decryptors
Workflow
Step 1: Identify the Encryption Algorithm
Determine which cryptographic algorithm the ransomware uses:
Common Ransomware Encryption Schemes:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
AES-256-CBC + RSA-2048: Most common hybrid scheme (LockBit, REvil, Conti)
AES-256-CTR + RSA-4096: Stream cipher mode variant (BlackCat/ALPHV)
ChaCha20 + RSA-4096: Modern stream cipher (Hive, Royal)
Salsa20 + ECDH: Curve25519 key exchange (Babuk)
AES-128-ECB: Weak mode - potential decryption via known-plaintext
XOR-only: Trivial encryption - always recoverable
Custom algorithm: Often contains implementation flaws
Step 2: Analyze Key Generation and Management
Reverse engineer how encryption keys are generated and stored:
Key Management Patterns in Ransomware:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. STRONG (no recovery possible without key):
- Per-file AES key generated with CryptGenRandom
- AES key encrypted with embedded RSA public key
- Encrypted key appended to each file or stored separately
- RSA private key held only by attacker's C2 server
2. WEAK (potential recovery):
- AES key derived from predictable seed (timestamp, PID)
- Same AES key used for all files (single key compromise = full recovery)
- Key transmitted to C2 before encryption starts (PCAP may contain key)
- XOR with short repeating key (brute-forceable)
- PRNG seeded with GetTickCount or time() (limited keyspace)
3. FLAWED IMPLEMENTATION:
- ECB mode (preserves plaintext patterns)
- Initialization vector (IV) reuse across files
- Key stored in plaintext in memory (recoverable from memory dump)
- Partial encryption (only first N bytes encrypted)
from Crypto.Cipher import AES
import os
import struct
# Test 1: Check if same key is used for multiple files# Compare encrypted versions of known filesdefcheck_key_reuse(file1_enc, file2_enc):
withopen(file1_enc, "rb") as f:
data1 = f.read()
withopen(file2_enc, "rb") as f:
data2 = f.read()
# Extract IVs (location depends on ransomware family)# If IVs are same and files share encrypted blocks -> same key
iv1 = data1[-16:] # Example: IV at end
iv2 = data2[-16:]
if iv1 == iv2:
print("[!] Same IV detected - key reuse likely")
# Test 2: Check for predictable key derivation# If key is derived from timestamp, iterate possible valuesdefbrute_force_timestamp_key(encrypted_file, known_header, timestamp_range):
withopen(encrypted_file, "rb") as f:
encrypted_data = f.read()
for ts in timestamp_range:
# Derive key the same way ransomware doesimport 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"[!] Key found! Timestamp: {ts}")
return key
returnNone# Test 3: Check for ECB mode (pattern preservation)defcheck_ecb_mode(encrypted_file):
withopen(encrypted_file, "rb") as f:
data = f.read()
# ECB produces identical ciphertext for identical plaintext blocks
blocks = [data[i:i+16] for i inrange(0, len(data), 16)]
unique = len(set(blocks))
total = len(blocks)
if unique < total * 0.95:
print(f"[!] ECB mode likely: {total-unique} duplicate blocks out of {total}")
Step 5: Attempt Key Recovery
Use identified weaknesses for key recovery:
# Recovery Method 1: Extract key from memory dump# Volatility plugin to scan for AES key schedules# vol3 -f memory.dmp windows.yarascan --yara-rule "aes_key_schedule"# Recovery Method 2: Known-plaintext attack (weak algorithms)defxor_key_recovery(encrypted_file, known_plaintext):
"""Recover XOR key from known plaintext-ciphertext pair"""withopen(encrypted_file, "rb") as f:
ciphertext = f.read()
key = bytes(c ^ p for c, p inzip(ciphertext, known_plaintext))
# Find repeating key lengthfor key_len inrange(1, 256):
candidate = key[:key_len]
ifall(key[i] == candidate[i % key_len] for i inrange(min(len(key), key_len * 4))):
print(f"XOR key (length {key_len}): {candidate.hex()}")
return candidate
returnNone# Recovery Method 3: Check NoMoreRansom for existing decryptors# https://www.nomoreransom.org/en/decryption-tools.html
Combining symmetric (AES) for fast file encryption with asymmetric (RSA) for secure key wrapping; the standard ransomware approach
Key Wrapping
Encrypting the per-file symmetric key with the attacker's RSA public key so only the attacker's private key can decrypt it
ECB Mode
Electronic Codebook mode encrypts each block independently; preserves patterns in plaintext, a critical weakness enabling partial recovery
Known-Plaintext Attack
Using a known original file and its encrypted version to derive the encryption key; effective against XOR and weak stream ciphers
Key Schedule
The expanded form of an AES key in memory; scannable in memory dumps to recover encryption keys before they are erased
CSPRNG
Cryptographically Secure Pseudo-Random Number Generator; ransomware using CryptGenRandom produces unpredictable keys
Partial Encryption
Some ransomware only encrypts the first N bytes or every Nth block for speed; unencrypted portions may aid recovery
Tools & Systems
Ghidra: Reverse engineering suite for analyzing ransomware encryption routines at the assembly level
PyCryptodome: Python cryptographic library for implementing and testing decryption routines
NoMoreRansom.org: Free decryption tool repository maintained by Europol and security vendors for known ransomware families
Volatility: Memory forensics framework for extracting encryption keys from RAM dumps of infected systems
CryptoTester: Tool for identifying cryptographic algorithms based on constants and code patterns
Common Scenarios
Scenario: Assessing Decryption Feasibility for a Ransomware Incident
Context: An organization is hit with ransomware encrypting file servers. Management needs to know if decryption is possible without paying the ransom before making a recovery decision.
Approach:
Identify the ransomware family from ransom note, file extension, and sample hash (check ID Ransomware)
Check NoMoreRansom.org for existing free decryptors for this family
Reverse engineer the encryption routine in Ghidra to identify the algorithm and key management
Test for implementation weaknesses (key reuse, predictable seeds, ECB mode)
Check if PCAP from the incident captured the key transmission to C2 (if key was sent before encryption)
Scan memory dumps from affected machines for AES key schedules in RAM
Report findings: decryption possible/impossible with specific technical justification
Pitfalls:
Testing decryption methods on the only copy of encrypted files (always work on copies)
Assuming all files use the same key without verifying (some ransomware uses per-file keys)
Not checking for volume shadow copies (vssadmin) which ransomware may have failed to delete
Confusing the file encryption algorithm with the key wrapping algorithm in reports
Output Format
RANSOMWARE ENCRYPTION ANALYSIS
================================
Sample: lockbit3.exe
Family: LockBit 3.0 / LockBit Black
SHA-256: abc123def456...
ENCRYPTION SCHEME
File Cipher: AES-256-CTR (per-file unique key)
Key Wrapping: RSA-2048 (public key embedded in binary)
Key Generation: CryptGenRandom (CSPRNG - unpredictable)
IV Generation: Random 16 bytes per file
File Structure: [encrypted_data][rsa_encrypted_key(256B)][iv(16B)][magic(8B)]
TARGETED EXTENSIONS
Total: 412 extensions targeted
Categories: Documents (.doc, .xls, .pdf), Databases (.sql, .mdb),
Archives (.zip, .7z), Source code (.py, .java, .cs)
Excluded: .exe, .dll, .sys, .lnk (system files preserved)
IMPLEMENTATION ANALYSIS
Key Strength: STRONG - per-file random keys, no reuse
Mode Security: STRONG - CTR mode with unique nonces
Key Storage: RSA-encrypted key appended to each file
Shadow Copies: Deleted via vssadmin and WMI
DECRYPTION FEASIBILITY
Without Key: NOT POSSIBLE
- No implementation flaws identified
- RSA-2048 key wrapping prevents brute force
- CSPRNG prevents key prediction
- No existing free decryptor available
RECOVERY OPTIONS
1. Restore from offline backups (recommended)
2. Check for volume shadow copies (low probability - ransomware deletes them)
3. Memory forensics if machine was not rebooted (key may persist in RAM)
4. Negotiate with attacker (last resort - no guarantee of decryption)