$npx -y skills add killvxk/cybersecurity-skills-zh --skill analyzing-ransomware-encryption-mechanisms分析勒索软件家族使用的加密算法、密钥管理和文件加密例程, 评估解密可行性、识别实现上的弱点并支持恢复工作。 涵盖 AES、RSA、ChaCha20 及混合加密方案。 适用于勒索软件密码分析、加密分析、密钥恢复评估或勒索软件解密可行性等请求。
| 1 | # 分析勒索软件加密机制 |
| 2 | |
| 3 | ## 适用场景 |
| 4 | |
| 5 | - 发生勒索软件感染,恢复工作需要了解所使用的加密方案 |
| 6 | - 评估无需支付赎金是否可以解密(实现缺陷、已知解密工具) |
| 7 | - 对勒索软件进行逆向工程,以识别加密算法、密钥派生和密钥存储机制 |
| 8 | - 当发现勒索软件密码实现中的弱点时,开发解密工具 |
| 9 | - 通过加密方式对勒索软件样本进行分类,将其归属到已知家族 |
| 10 | |
| 11 | **不适用于**在未事先用加密文件的测试副本验证解密方法的情况下对生产数据进行恢复操作。 |
| 12 | |
| 13 | ## 前置条件 |
| 14 | |
| 15 | - Ghidra 或 IDA Pro,用于对勒索软件二进制文件进行逆向工程 |
| 16 | - Python 3.8+,安装 `pycryptodome` 库用于测试加密/解密例程 |
| 17 | - 加密文件样本及其对应的明文原件(已知明文对) |
| 18 | - 访问勒索软件二进制文件(如有必要需先解包) |
| 19 | - 熟悉对称(AES、ChaCha20)和非对称(RSA)密码算法 |
| 20 | - NoMoreRansom.org 数据库,用于检查是否存在免费解密工具 |
| 21 | |
| 22 | ## 工作流程 |
| 23 | |
| 24 | ### 步骤 1:识别加密算法 |
| 25 | |
| 26 | 确定勒索软件使用的密码算法: |
| 27 | |
| 28 | ```python |
| 29 | # 检查导入表中的 Windows 加密 API |
| 30 | import pefile |
| 31 | |
| 32 | pe = pefile.PE("ransomware.exe") |
| 33 | |
| 34 | crypto_apis = { |
| 35 | "CryptAcquireContextA": "Windows CryptoAPI", |
| 36 | "CryptAcquireContextW": "Windows CryptoAPI", |
| 37 | "CryptGenKey": "Windows CryptoAPI 密钥生成", |
| 38 | "CryptEncrypt": "Windows CryptoAPI 加密", |
| 39 | "CryptImportKey": "Windows CryptoAPI 密钥导入", |
| 40 | "BCryptOpenAlgorithmProvider": "Windows CNG(现代加密)", |
| 41 | "BCryptEncrypt": "Windows CNG 加密", |
| 42 | "BCryptGenerateKeyPair": "Windows CNG 非对称密钥生成", |
| 43 | } |
| 44 | |
| 45 | print("加密 API 导入:") |
| 46 | for entry in pe.DIRECTORY_ENTRY_IMPORT: |
| 47 | for imp in entry.imports: |
| 48 | if imp.name and imp.name.decode() in crypto_apis: |
| 49 | print(f" {entry.dll.decode()} -> {imp.name.decode()}: {crypto_apis[imp.name.decode()]}") |
| 50 | ``` |
| 51 | |
| 52 | ``` |
| 53 | 常见勒索软件加密方案: |
| 54 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 55 | AES-256-CBC + RSA-2048: 最常见的混合方案(LockBit、REvil、Conti) |
| 56 | AES-256-CTR + RSA-4096: 流密码模式变体(BlackCat/ALPHV) |
| 57 | ChaCha20 + RSA-4096: 现代流密码(Hive、Royal) |
| 58 | Salsa20 + ECDH: Curve25519 密钥交换(Babuk) |
| 59 | AES-128-ECB: 弱模式——可能通过已知明文解密 |
| 60 | 仅 XOR: 简单加密——始终可恢复 |
| 61 | 自定义算法: 通常包含实现缺陷 |
| 62 | ``` |
| 63 | |
| 64 | ### 步骤 2:分析密钥生成和管理 |
| 65 | |
| 66 | 逆向工程密钥的生成和存储方式: |
| 67 | |
| 68 | ``` |
| 69 | 勒索软件中的密钥管理模式: |
| 70 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
| 71 | 1. 强(无密钥则无法恢复): |
| 72 | - 使用 CryptGenRandom 为每个文件生成 AES 密钥 |
| 73 | - AES 密钥用嵌入的 RSA 公钥加密 |
| 74 | - 加密后的密钥附加到每个文件末尾或单独存储 |
| 75 | - RSA 私钥仅由攻击者的 C2 服务器持有 |
| 76 | |
| 77 | 2. 弱(可能可以恢复): |
| 78 | - AES 密钥从可预测的种子派生(时间戳、PID) |
| 79 | - 所有文件使用相同的 AES 密钥(破解一个密钥即可完全恢复) |
| 80 | - 加密开始前密钥已传输到 C2(PCAP 可能包含密钥) |
| 81 | - 使用短的重复密钥进行 XOR 加密(可暴力破解) |
| 82 | - PRNG 以 GetTickCount 或 time() 为种子(密钥空间有限) |
| 83 | |
| 84 | 3. 存在缺陷的实现: |
| 85 | - ECB 模式(保留明文模式) |
| 86 | - 跨文件重用初始化向量(IV) |
| 87 | - 密钥以明文形式存储在内存中(可从内存转储中恢复) |
| 88 | - 部分加密(仅加密前 N 字节) |
| 89 | ``` |
| 90 | |
| 91 | ### 步骤 3:检查文件加密例程 |
| 92 | |
| 93 | 逆向工程文件处理逻辑: |
| 94 | |
| 95 | ```c |
| 96 | // 典型的勒索软件文件加密流程(Ghidra 反编译伪代码): |
| 97 | |
| 98 | void encrypt_file(char *filepath) { |
| 99 | // 1. 根据目标列表检查文件扩展名 |
| 100 | if (!is_target_extension(filepath)) return; |
| 101 | |
| 102 | // 2. 生成每文件 AES 密钥(AES-256 为 32 字节) |
| 103 | BYTE aes_key[32]; |
| 104 | CryptGenRandom(hProv, 32, aes_key); |
| 105 | |
| 106 | // 3. 生成随机 IV(16 字节) |
| 107 | BYTE iv[16]; |
| 108 | CryptGenRandom(hProv, 16, iv); |
| 109 | |
| 110 | // 4. 读取文件内容 |
| 111 | HANDLE hFile = CreateFile(filepath, GENERIC_READ, ...); |
| 112 | BYTE *plaintext = read_entire_file(hFile); |
| 113 | |
| 114 | // 5. 使用 AES-256-CBC 加密 |
| 115 | aes_cbc_encrypt(plaintext, file_size, aes_key, iv); |
| 116 | |
| 117 | // 6. 用 RSA 公钥加密 AES 密钥 |
| 118 | BYTE encrypted_key[256]; // RSA-2048 输出 |
| 119 | rsa_encrypt(aes_key, 32, rsa_pubkey, encrypted_key); |
| 120 | |
| 121 | // 7. 写入:加密数据 + 加密的密钥 + IV 到文件 |
| 122 | write_file(filepath, encrypted_data, encrypted_key, iv); |
| 123 | |
| 124 | // 8. 使用勒索软件扩展名重命名文件 |
| 125 | rename_file(filepath, strcat(filepath, ".locked")); |
| 126 | } |
| 127 | ``` |
| 128 | |
| 129 | ### 步骤 4:检查密码学弱点 |
| 130 | |
| 131 | 测试实现中是否存在可利用的缺陷: |
| 132 | |
| 133 | ```python |
| 134 | from Crypto.Cipher import AES |
| 135 | import os |
| 136 | import struct |
| 137 | |
| 138 | # 测试 1:检查是否对多个文件使用相同密钥 |
| 139 | # 比较已知文件的加密版本 |
| 140 | def check_key_reuse(file1_enc, file2_enc): |
| 141 | with open(file1_enc, "rb") as f: |
| 142 | data1 = f.read() |
| 143 | with open(file2_enc, "rb") as f: |
| 144 | data2 = f.read() |
| 145 | |
| 146 | # 提取 IV(位置取决于勒索软件家族) |
| 147 | # 如果 IV 相同且文件共享加密块 -> 使用相同密钥 |
| 148 | iv1 = data1[-16:] # 示例:IV 在末尾 |
| 149 | iv2 = data2[-16:] |
| 150 | if iv1 == iv2: |
| 151 | print("[!] 检测到相同 IV——可能存在密钥重用") |
| 152 | |
| 153 | # 测试 2:检查可预测的密钥派生 |
| 154 | # 如果密钥由时间戳派生,迭代可能的值 |
| 155 | def brute_force_timestamp_key(encrypted_file, known_header, timestamp_range): |
| 156 | with open(encrypted_file, "rb") as f: |
| 157 | encrypted_data = f.read() |
| 158 | |
| 159 | for ts in timestamp_range: |
| 160 | # 与勒索软件相同的方式派生密钥 |
| 161 | import hashlib |
| 162 | key = hashlib.sha256(str(ts).encode()).digest() |
| 163 | iv = encrypted_data[-16:] |
| 164 | cipher = AES.new(key, AES.MODE_CBC, iv) |
| 165 | decrypted = cipher.decrypt(encrypted_data[:16]) |
| 166 | |
| 167 | if decrypted[:len(known_header)] == known_header: |
| 168 | print(f"[!] 找到密钥!时间戳:{ts}") |
| 169 | return key |
| 170 | |
| 171 | return None |
| 172 | |
| 173 | # 测试 3:检查 ECB 模式(模式保留) |
| 174 | def check_ecb_mode(encrypted_file): |
| 175 | with open(encrypted_file, "rb") as f: |
| 176 | data = f.read() |
| 177 | # ECB 对相同的明文块产生相同的密文块 |
| 178 | blocks = [data[i:i+16] for i in range(0, len(data), 16)] |
| 179 | unique = len(set(blocks)) |
| 180 | total = len(blocks) |
| 181 | if unique < total * 0.95: |
| 182 | print(f"[!] 可能为 ECB 模式:{total} 个块中有 {total-unique} 个重复块") |
| 183 | ``` |
| 184 | |
| 185 | ### 步骤 5:尝试密钥恢复 |
| 186 | |
| 187 | 利用已识别的弱点进行密钥恢复: |
| 188 | |
| 189 | ```python |
| 190 | # 恢复方法 1:从内存转储中提取密钥 |
| 191 | # 使用 Volatility 插件扫描 AES 密钥调度 |
| 192 | # vol3 -f memory.dmp windows.yarascan --yara-rule "aes_key_schedule" |
| 193 | |
| 194 | # 恢复方 |