npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
MITRE D3FEND
Overview
Modern ransomware uses hybrid encryption combining symmetric algorithms (AES-256-CBC/CTR, ChaCha20, Salsa20) for file encryption with asymmetric algorithms (RSA-2048/4096, Curve25519) for key protection. The encryption routine typically generates a random symmetric key per file, encrypts file contents, then encrypts the symmetric key with the attacker's embedded public key. Reverse engineering these routines identifies the specific algorithms, key derivation methods, initialization vectors, file targeting patterns, and potential implementation flaws that could enable decryption without paying the ransom. Notable examples include Rhysida (AES-256-CTR + RSA-4096), Qilin.B (AES-256-CTR with AES-NI or ChaCha20 fallback), and Medusa (AES-256 + RSA).
When to Use
- When performing authorized security testing that involves reverse engineering ransomware encryption routine
- When analyzing malware samples or attack artifacts in a controlled environment
- When conducting red team exercises or penetration testing engagements
- When building detection capabilities based on offensive technique understanding
Prerequisites
- IDA Pro or Ghidra for static disassembly
- x64dbg/WinDbg for dynamic debugging
- Python 3.9+ with
pycryptodome,pefile - Understanding of AES, RSA, ChaCha20, Curve25519 algorithms
- Knowledge of Windows CryptoAPI and CNG (BCrypt) functions
- Sandbox environment for safe execution
Key Concepts
Hybrid Encryption Model
Ransomware generates a unique AES key and IV for each file. The file content is encrypted with this symmetric key. The symmetric key is then encrypted with the attacker's RSA public key (embedded in the binary or fetched from C2). The encrypted key is appended or prepended to the encrypted file. Only the attacker holding the RSA private key can decrypt the per-file symmetric keys.
Cryptographic API Identification
Windows ransomware typically uses CryptoAPI (CryptAcquireContext, CryptGenKey, CryptEncrypt) or CNG (BCryptGenerateSymmetricKey, BCryptEncrypt). Some use OpenSSL or custom implementations. Identifying these API calls provides immediate insight into the algorithm, key size, and mode of operation.
Implementation Flaws
Decryption opportunities arise from: hardcoded encryption keys, weak PRNG for key generation (using GetTickCount or time() as seed), reuse of IVs across files, ECB mode usage, keys remaining in memory post-encryption, and race conditions where keys can be captured during encryption.
Workflow
Step 1: Identify Cryptographic Functions
#!/usr/bin/env python3
"""Identify cryptographic functions in ransomware PE files."""
import pefile
import sys
CRYPTO_APIS = {
# Windows CryptoAPI
"CryptAcquireContextA": "CryptoAPI context acquisition",
"CryptAcquireContextW": "CryptoAPI context acquisition",
"CryptGenKey": "Key generation",
"CryptDeriveKey": "Key derivation",
"CryptEncrypt": "Encryption operation",
"CryptDecrypt": "Decryption operation",
"CryptImportKey": "Key import (public key?)",
"CryptExportKey": "Key export",
"CryptGenRandom": "Random number generation",
"CryptCreateHash": "Hash creation",
"CryptHashData": "Hashing operation",
# Windows CNG (BCrypt)
"BCryptOpenAlgorithmProvider": "CNG algorithm initialization",
"BCryptGenerateSymmetricKey": "CNG symmetric key generation",
"BCryptEncrypt": "CNG encryption",
"BCryptDecrypt": "CNG decryption",
"BCryptGenerateKeyPair": "CNG key pair generation",
"BCryptImportKeyPair": "CNG key import",
# OpenSSL
"EVP_EncryptInit_ex": "OpenSSL encrypt init",
"EVP_EncryptUpdate": "OpenSSL encrypt update",
"EVP_EncryptFinal_ex": "OpenSSL encrypt final",
"RSA_public_encrypt": "OpenSSL RSA encryption",
"AES_set_encrypt_key": "OpenSSL AES key setup",
# File operations
"CreateFileW": "File open (target files)",
"ReadFile": "File read (before encryption)",
"WriteFile": "File write (after encryption)",
"FindFirstFileW": "File enumeration (targeting)",
"FindNextFileW": "File enumeration",
"MoveFileW": "File rename (extension change)",
"DeleteFileW": "File deletion (originals)",
}
AES_SBOX = bytes([
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
])
CHACHA20_CONSTANT = b"expand 32-byte k"
def analyze_imports(filepath):
"""Analyze PE imports for cryptographic APIs."""
try:
pe = pefile.PE(filepath)
except pefile.PEFormatError:
print("[-] Not a valid PE file")
return
print("[+] Cryptographic API Analysis")
print("=" * 60)
crypto_imports = []
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
for entry in pe.DIRECTORY_ENTRY_IMPORT:
dll = entry.dll.decode('utf-8', errors='replace')
for imp in entry.imports:
if imp.name:
name = imp.name.decode('utf-8', errors='replace')
if name in CRYPTO_APIS:
desc = CRYPTO_APIS[name]
crypto_imports.append((dll, name, desc))
print(f" [{dll}] {name}: {desc}")
if not crypto_imports:
print(" No known crypto APIs found in imports")
print(" Malware may use custom implementation or dynamic loading")
return crypto_imports
def find_crypto_constants(filepath):
"""Search for embedded cryptographic constants."""
with open(filepath, 'rb') as f:
data = f.read()
print("\n[+] Cryptographic Constants Search")
print("=" * 60)
# AES S-Box
offset = data.find(AES_SBOX)
if offset != -1:
print(f" AES S-Box found at offset 0x{offset:x}")
# ChaCha20/Salsa20 constant
offset = data.find(CHACHA20_CONSTANT)
if offset != -1:
print(f" ChaCha20 constant at offset 0x{offset:x}")
# RSA public key markers
rsa_markers = [
b'-----BEGIN PUBLIC KEY-----',
b'-----BEGIN RSA PUBLIC KEY-----',
b'\x30\x82', # ASN.1 SEQUENCE
]
for marker in rsa_markers:
offset = data.find(marker)
if offset != -1:
print(f" RSA key marker at offset 0x{offset:x}")
# Common ransomware file extension patterns
import re
ext_pattern = re.compile(rb'\.\w{3,10}(?=\x00)', re.IGNORECASE)
extensions = set()
for match in ext_pattern.finditer(data):
ext = match.group().decode('ascii', errors='replace').lower()
target_exts = [
'.doc', '.docx', '.xls', '.xlsx', '.pdf', '.ppt',
'.jpg', '.png', '.sql', '.mdb', '.bak', '.zip',
]
if ext in target_exts:
extensions.add(ext)
if extensions:
print(f"\n Target file extensions: {', '.join(sorted(extensions))}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <ransomware_sample>")
sys.exit(1)
analyze_imports(sys.argv[1])
find_crypto_constants(sys.argv[1])Step 2: Analyze Encryption Flow
def analyze_encryption_pattern(filepath):
"""Analyze file encryption patterns from ransomware artifacts."""
import os
import struct
with open(filepath, 'rb') as f:
data = f.read()
file_size = len(data)
print(f"\n[+] Encrypted File Analysis: {filepath}")
print(f" Size: {file_size:,} bytes")
# Check for appended key material (common pattern)
# Many ransomware families append encrypted key at end of file
tail_sizes = [256, 512, 1024, 2048] # Common RSA ciphertext sizes
for size in tail_sizes:
if file_size > size + 16:
tail = data[-size:]
# High entropy suggests encrypted data
entropy = calculate_entropy(tail)
if entropy > 7.5:
print(f" Possible encrypted key ({size} bytes) "
f"at end of file (entropy: {entropy:.2f})")
# Check for header modifications
# Many ransomware prepend metadata
header = data[:64]
print(f" First 16 bytes: {header[:16].hex()}")
# Check if original file header is preserved
known_headers = {
b'PK': 'ZIP/Office',
b'\x89PNG': 'PNG',
b'\xff\xd8\xff': 'JPEG',
b'%PDF': 'PDF',
b'\xd0\xcf\x11\xe0': 'OLE (DOC/XLS)',
}
for magic, ftype in known_headers.items():
if header.startswith(magic):
print(f" Original format preserved: {ftype}")
break
else:
print(" Original header destroyed/encrypted")
def calculate_entropy(data):
"""Calculate Shannon entropy of data."""
from collections import Counter
import math
if not data:
return 0
freq = Counter(data)
length = len(data)
entropy = -sum(
(count / length) * math.log2(count / length)
for count in freq.values()
)
return entropyValidation Criteria
- Cryptographic algorithms identified (AES, RSA, ChaCha20, etc.)
- Key size and mode of operation determined
- Key generation method analyzed for potential weaknesses
- Per-file key encryption scheme documented
- File targeting patterns and extension list extracted
- Embedded public keys extracted for infrastructure correlation
- Potential decryption opportunities assessed
References
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.9 KB
API Reference: Reverse Engineering Ransomware Encryption
Cryptographic Algorithm Constants
| Algorithm | Signature | Description |
|---|---|---|
| AES | S-Box starting 0x63 0x7C 0x77 |
AES Rijndael substitution box |
| RSA | DER 0x30 0x82 prefix |
ASN.1 RSA key structure |
| ChaCha20/Salsa20 | expand 32-byte k |
Stream cipher constant |
| RC4 | Sequential 0-255 state | Key scheduling algorithm init |
Encryption Analysis Techniques
| Technique | Tool | Purpose |
|---|---|---|
| Entropy analysis | ent, Python |
Detect encrypted regions |
| Constant scanning | IDA/Ghidra YARA | Find crypto implementations |
| API tracing | x64dbg, Frida | Trace CryptEncrypt/BCrypt calls |
| Key extraction | Volatility3 | Dump keys from memory |
Ransomware Encryption Patterns
| Pattern | Indicator |
|---|---|
| Full encryption | Entropy > 7.9 across entire file |
| Intermittent | High entropy blocks with gaps |
| Header-only | First N bytes encrypted, rest plain |
| Appended metadata | File larger than original (key/IV at end) |
Common Ransomware Crypto
| Family | Algorithm | Key Mgmt |
|---|---|---|
| LockBit 3.0 | AES-256-CBC + RSA-2048 | Per-file AES key, RSA-encrypted |
| BlackCat/ALPHV | ChaCha20 + RSA-4096 | Rust implementation |
| Royal | AES-256-CBC + RSA-2048 | Intermittent encryption |
| Akira | ChaCha20 | Partial file encryption |
Python Libraries
| Library | Version | Purpose |
|---|---|---|
hashlib |
stdlib | SHA256 hashing |
struct |
stdlib | Binary data parsing |
re |
stdlib | Pattern extraction |
math |
stdlib | Shannon entropy calculation |
References
- ID Ransomware: https://id-ransomware.malwarehunterteam.com/
- NoMoreRansom Decryptors: https://www.nomoreransom.org/en/decryption-tools.html
- Ghidra: https://ghidra-sre.org/
standards.md1.1 KB
Ransomware Encryption Standards Reference
Common Encryption Schemes by Family
| Family | Symmetric | Asymmetric | Key Size |
|---|---|---|---|
| Rhysida | AES-256-CTR | RSA-4096 | 256-bit |
| Qilin.B | AES-256-CTR/ChaCha20 | RSA-4096 OAEP | 256-bit |
| Medusa | AES-256 | RSA public key | 256-bit |
| LockBit 3.0 | AES-256-CTR | Curve25519 | 256-bit |
| BlackCat/ALPHV | AES-128/ChaCha20 | RSA-2048 | 128/256-bit |
| Conti | ChaCha20 | RSA-4096 | 256-bit |
Windows Cryptographic API Cheat Sheet
| Function | Purpose |
|---|---|
| CryptAcquireContext | Acquire crypto provider handle |
| CryptGenKey | Generate symmetric/asymmetric key |
| CryptImportKey | Import key blob |
| BCryptOpenAlgorithmProvider | Open CNG algorithm |
| BCryptGenerateSymmetricKey | Create symmetric key |
MITRE ATT&CK Techniques
- T1486: Data Encrypted for Impact
- T1490: Inhibit System Recovery
- T1083: File and Directory Discovery
- T1082: System Information Discovery
References
workflows.md1.7 KB
Ransomware Encryption Analysis Workflows
Workflow 1: Encryption Routine Identification
[Ransomware Sample] --> [Import Analysis] --> [Find Crypto APIs]
|
v
[Identify Algorithm]
|
v
[Trace Key Generation]
|
v
[Assess Decryption Feasibility]Workflow 2: Key Recovery Assessment
[Encrypted Files] --> [Analyze File Structure] --> [Locate Encrypted Key]
|
v
[Check for PRNG Weaknesses]
|
v
[Attempt Key Recovery]Workflow 3: Decryptor Development
[Identified Flaw] --> [Extract Parameters] --> [Build Decryption Logic]
|
v
[Test on Sample Files]
|
v
[Release Decryptor Tool]Scripts 2
agent.py6.6 KB
#!/usr/bin/env python3
"""Agent for reverse engineering ransomware encryption routines.
Identifies encryption algorithms, extracts key material from
memory dumps or binary analysis, detects IV/nonce patterns,
and documents the cryptographic implementation for decryptor
development.
"""
import json
import sys
import re
import struct
import hashlib
from pathlib import Path
from datetime import datetime
CRYPTO_CONSTANTS = {
"AES S-Box": bytes([0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5]),
"AES Inv S-Box": bytes([0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38]),
"RSA Marker": b"\x30\x82",
"ChaCha20 Constant": b"expand 32-byte k",
"Salsa20 Constant": b"expand 32-byte k",
"RC4 State Init": bytes(range(8)),
"SHA256 Init H0": struct.pack(">I", 0x6a09e667),
}
RANSOMWARE_PATTERNS = {
"file_extension_change": re.compile(rb'\.\w{3,10}(?=\x00)'),
"ransom_note_name": re.compile(rb'(?:README|RECOVER|DECRYPT|HOW.TO)[\w.-]*\.(?:txt|html|hta)', re.I),
"bitcoin_address": re.compile(rb'[13][a-km-zA-HJ-NP-Z1-9]{25,34}'),
"onion_url": re.compile(rb'[\w]{16,56}\.onion'),
"email_address": re.compile(rb'[\w.+-]+@[\w-]+\.[\w.]{2,}'),
}
class RansomwareREAgent:
"""Analyzes ransomware encryption implementation."""
def __init__(self, sample_path, output_dir="./ransomware_re"):
self.sample_path = Path(sample_path)
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.findings = []
def identify_crypto_algorithms(self):
"""Scan binary for cryptographic algorithm constants."""
data = self.sample_path.read_bytes()
detected = []
for name, constant in CRYPTO_CONSTANTS.items():
offset = data.find(constant)
if offset != -1:
detected.append({
"algorithm": name,
"offset": hex(offset),
"context": data[max(0, offset - 16):offset + len(constant) + 16].hex(),
})
self.findings.append({
"type": "Crypto Algorithm Detected",
"algorithm": name, "offset": hex(offset),
})
return detected
def extract_encryption_indicators(self):
"""Extract ransomware-specific indicators from the binary."""
data = self.sample_path.read_bytes()
indicators = {}
for name, pattern in RANSOMWARE_PATTERNS.items():
matches = pattern.findall(data)
if matches:
decoded = []
for m in matches[:10]:
try:
decoded.append(m.decode("utf-8", errors="ignore"))
except (UnicodeDecodeError, AttributeError):
decoded.append(m.hex())
indicators[name] = decoded
return indicators
def analyze_encrypted_file(self, encrypted_path, original_path=None):
"""Analyze an encrypted file to determine encryption characteristics."""
enc_data = Path(encrypted_path).read_bytes()
analysis = {
"file_size": len(enc_data),
"entropy": self._calculate_entropy(enc_data),
"header_bytes": enc_data[:64].hex(),
"footer_bytes": enc_data[-64:].hex() if len(enc_data) > 64 else "",
}
if analysis["entropy"] > 7.9:
analysis["encryption_type"] = "Full file encryption"
elif analysis["entropy"] > 6.0:
analysis["encryption_type"] = "Partial/intermittent encryption"
else:
analysis["encryption_type"] = "Possibly not encrypted or header-only"
if original_path and Path(original_path).exists():
orig_data = Path(original_path).read_bytes()
analysis["size_difference"] = len(enc_data) - len(orig_data)
if analysis["size_difference"] > 0:
analysis["appended_bytes"] = analysis["size_difference"]
analysis["footer_metadata"] = enc_data[len(orig_data):len(orig_data) + 128].hex()
return analysis
def _calculate_entropy(self, data):
"""Calculate Shannon entropy of data."""
if not data:
return 0.0
import math
freq = [0] * 256
for byte in data:
freq[byte] += 1
length = len(data)
entropy = 0.0
for count in freq:
if count > 0:
p = count / length
entropy -= p * math.log2(p)
return round(entropy, 4)
def extract_key_material(self, memory_dump_path=None):
"""Search for potential encryption key material."""
search_data = (Path(memory_dump_path).read_bytes()
if memory_dump_path else self.sample_path.read_bytes())
potential_keys = []
for offset in range(0, min(len(search_data), 10_000_000), 16):
block = search_data[offset:offset + 32]
if len(block) < 16:
break
entropy = self._calculate_entropy(block)
if entropy > 4.5 and all(b != 0 for b in block[:16]):
if not all(b == block[0] for b in block[:16]):
potential_keys.append({
"offset": hex(offset),
"length": len(block),
"entropy": entropy,
"sha256": hashlib.sha256(block).hexdigest()[:16],
})
if len(potential_keys) >= 50:
break
return potential_keys[:20]
def generate_report(self):
crypto = self.identify_crypto_algorithms()
indicators = self.extract_encryption_indicators()
sha256 = hashlib.sha256(self.sample_path.read_bytes()).hexdigest()
report = {
"sample": str(self.sample_path),
"sha256": sha256,
"report_date": datetime.utcnow().isoformat(),
"crypto_algorithms": crypto,
"ransomware_indicators": indicators,
"findings": self.findings,
}
report_path = self.output_dir / "ransomware_re_report.json"
with open(report_path, "w") as f:
json.dump(report, f, indent=2)
print(json.dumps(report, indent=2))
return report
def main():
if len(sys.argv) < 2:
print("Usage: agent.py <sample_path> [encrypted_file] [original_file]")
sys.exit(1)
agent = RansomwareREAgent(sys.argv[1])
agent.generate_report()
if len(sys.argv) > 2:
orig = sys.argv[3] if len(sys.argv) > 3 else None
analysis = agent.analyze_encrypted_file(sys.argv[2], orig)
print(json.dumps(analysis, indent=2))
if __name__ == "__main__":
main()
process.py5.4 KB
#!/usr/bin/env python3
"""
Ransomware Encryption Routine Analyzer
Analyzes ransomware samples to identify encryption algorithms,
key generation methods, and potential decryption opportunities.
Requirements:
pip install pefile pycryptodome
Usage:
python process.py --sample ransomware.exe
python process.py --encrypted-file encrypted.docx.locked
"""
import argparse
import json
import math
import re
import struct
import sys
from collections import Counter
from pathlib import Path
try:
import pefile
except ImportError:
pefile = None
CRYPTO_APIS = {
"CryptAcquireContextA": ("CryptoAPI", "context"),
"CryptAcquireContextW": ("CryptoAPI", "context"),
"CryptGenKey": ("CryptoAPI", "keygen"),
"CryptEncrypt": ("CryptoAPI", "encrypt"),
"CryptDecrypt": ("CryptoAPI", "decrypt"),
"CryptImportKey": ("CryptoAPI", "import"),
"CryptGenRandom": ("CryptoAPI", "random"),
"BCryptOpenAlgorithmProvider": ("CNG", "init"),
"BCryptGenerateSymmetricKey": ("CNG", "keygen"),
"BCryptEncrypt": ("CNG", "encrypt"),
"BCryptDecrypt": ("CNG", "decrypt"),
"EVP_EncryptInit_ex": ("OpenSSL", "init"),
"EVP_EncryptUpdate": ("OpenSSL", "encrypt"),
"RSA_public_encrypt": ("OpenSSL", "rsa_encrypt"),
"AES_set_encrypt_key": ("OpenSSL", "aes_init"),
}
AES_SBOX_PREFIX = bytes([0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5])
CHACHA_CONST = b"expand 32-byte k"
SALSA_CONST = b"expand 32-byte k"
def entropy(data):
if not data:
return 0.0
freq = Counter(data)
length = len(data)
return -sum(
(c / length) * math.log2(c / length) for c in freq.values()
)
def analyze_sample(filepath):
report = {"file": str(filepath), "crypto_apis": [], "constants": [],
"embedded_keys": [], "target_extensions": []}
with open(filepath, 'rb') as f:
data = f.read()
report["size"] = len(data)
report["entropy"] = round(entropy(data), 3)
# Import analysis
if pefile:
try:
pe = pefile.PE(filepath)
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
for entry in pe.DIRECTORY_ENTRY_IMPORT:
dll = entry.dll.decode('utf-8', errors='replace')
for imp in entry.imports:
if imp.name:
name = imp.name.decode('utf-8', errors='replace')
if name in CRYPTO_APIS:
framework, op = CRYPTO_APIS[name]
report["crypto_apis"].append({
"dll": dll,
"function": name,
"framework": framework,
"operation": op,
})
except Exception:
pass
# Crypto constants
if data.find(AES_SBOX_PREFIX) != -1:
report["constants"].append("AES S-Box")
if data.find(CHACHA_CONST) != -1:
report["constants"].append("ChaCha20/Salsa20")
# RSA keys
pem_markers = [b'-----BEGIN PUBLIC KEY-----',
b'-----BEGIN RSA PUBLIC KEY-----']
for marker in pem_markers:
idx = data.find(marker)
if idx != -1:
end = data.find(b'-----END', idx)
if end != -1:
key_data = data[idx:end + 30].decode('ascii', errors='replace')
report["embedded_keys"].append({
"type": "PEM RSA Public Key",
"offset": f"0x{idx:x}",
"preview": key_data[:100],
})
# Target extensions
ext_pattern = re.compile(rb'\.(?:doc|docx|xls|xlsx|pdf|ppt|pptx|'
rb'jpg|png|sql|mdb|bak|zip|rar|7z|'
rb'psd|dwg|vmdk|raw|db)\b', re.I)
for m in ext_pattern.finditer(data):
ext = m.group().decode('ascii', errors='replace').lower()
if ext not in report["target_extensions"]:
report["target_extensions"].append(ext)
return report
def analyze_encrypted_file(filepath):
with open(filepath, 'rb') as f:
data = f.read()
report = {
"file": str(filepath),
"size": len(data),
"entropy": round(entropy(data), 3),
"high_entropy": entropy(data) > 7.9,
"possible_appended_key": [],
}
# Check tail for appended encrypted key
for key_size in [128, 256, 512, 1024, 2048]:
if len(data) > key_size + 16:
tail = data[-key_size:]
tail_entropy = entropy(tail)
if tail_entropy > 7.5:
report["possible_appended_key"].append({
"size": key_size,
"entropy": round(tail_entropy, 3),
})
return report
def main():
parser = argparse.ArgumentParser(
description="Ransomware Encryption Analyzer"
)
parser.add_argument("--sample", help="Ransomware binary")
parser.add_argument("--encrypted-file", help="Encrypted file to analyze")
parser.add_argument("--output", help="Output JSON report")
args = parser.parse_args()
if args.sample:
report = analyze_sample(args.sample)
elif args.encrypted_file:
report = analyze_encrypted_file(args.encrypted_file)
else:
parser.print_help()
return
print(json.dumps(report, indent=2))
if args.output:
with open(args.output, 'w') as f:
json.dump(report, f, indent=2)
if __name__ == "__main__":
main()