压缩文件 CRC32 碰撞原理解析以及制作解密脚本
字数 1473 2025-12-08 12:14:04
CRC32碰撞原理解析与解密脚本制作指南
一、CRC32基础概念
1.1 什么是CRC32校验
CRC32(Cyclic Redundancy Check 32)是一种32位循环冗余校验码,广泛应用于压缩文件格式(如ZIP、RAR)中,用于验证文件内容的完整性。它是一种线性校验和算法,能够检测数据传输或存储过程中出现的错误。
1.2 CRC32在压缩文件中的应用
在ZIP文件格式中,每个文件条目都包含一个CRC32校验值,该值基于未压缩的原始文件内容计算得出。即使文件内容被加密,CRC32值仍然以明文形式存储在文件头中,这为CRC32碰撞攻击提供了可能。
二、CRC32碰撞攻击原理
2.1 攻击的基本思路
CRC32碰撞攻击的核心原理是利用CRC32校验值空间有限(仅32位,即2^32≈42.9亿种可能)的特性,当压缩文件内文件内容很短时,可以通过暴力枚举的方式找到与目标CRC32值匹配的原始内容。
2.2 攻击的可行性条件
攻击成功的三个关键前提条件:
- 已知CRC32值:从压缩包文件头中获取
- 已知明文长度:通过文件头中的解压后大小字段获得
- 有限的字符集:明文字符集可预测或有限
2.3 数学原理分析
CRC32碰撞属于原像攻击(Pre-image Attack)的一种。给定哈希值H,寻找输入M使得CRC32(M)=H。当明文空间小于或接近2^32时,暴力枚举变得可行。
计算示例:
- 1字节明文:256种可能(瞬间完成)
- 4字节明文:95^4≈8145万种可能(可接受时间)
- 6字节明文:95^6≈7.35×10^11种可能(不可行)
三、实战案例解析
3.1 典型攻击场景
假设ZIP文件中包含一个2字节的文本文件,已知信息:
- CRC32值:0x12345678
- 明文长度:2字节
- 字符集:ASCII可打印字符(95个)
3.2 攻击步骤
- 提取CRC32值:从ZIP文件头读取目标CRC32
- 确定搜索空间:95^2=9025种可能组合
- 暴力枚举:对每个候选明文计算CRC32并比较
- 结果验证:找到CRC32(AB)=0x12345678时,明文即为"AB"
四、解密脚本制作详解
4.1 脚本整体架构
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CRC32碰撞解密脚本
功能:通过CRC32碰撞恢复ZIP文件中短文件的原始内容
"""
4.2 核心模块实现
4.2.1 CRC32计算函数
import binascii
def calculate_crc32(data):
"""计算数据的CRC32值(无符号32位)"""
return binascii.crc32(data.encode()) & 0xffffffff
4.2.2 暴力枚举函数
import itertools
def brute_crc32(target_crc, length, charset):
"""
暴力枚举CRC32原像
:param target_crc: 目标CRC32值
:param length: 明文长度
:param charset: 字符集
:return: 命中的明文字符串或None
"""
target_crc &= 0xffffffff # 确保无符号
total = len(charset) ** length
for combination in itertools.product(charset, repeat=length):
candidate = ''.join(combination)
crc_val = binascii.crc32(candidate.encode()) & 0xffffffff
if crc_val == target_crc:
return candidate
return None
4.2.3 ZIP文件处理模块
import zipfile
def extract_zip_info(zip_path):
"""提取ZIP文件中各条目的CRC32和文件大小"""
try:
with zipfile.ZipFile(zip_path, 'r') as zf:
file_info = {}
for name in zf.namelist():
info = zf.getinfo(name)
file_info[name] = {
'crc': info.CRC & 0xffffffff,
'size': info.file_size
}
return file_info
except Exception as e:
print(f"错误: {e}")
return None
4.3 字符集选择策略
提供多种字符集选项以适应不同场景:
import string
def select_charset(choice):
"""根据用户选择返回对应字符集"""
charset_map = {
'1': string.digits, # 数字 0-9
'2': string.ascii_lowercase, # 小写字母 a-z
'3': string.ascii_uppercase, # 大写字母 A-Z
'4': string.ascii_letters, # 所有字母
'5': string.printable, # 可打印字符
'6': custom_charset # 自定义字符集
}
return charset_map.get(choice, string.digits)
4.4 主控流程实现
def main_attack(zip_path, max_length=6):
"""主攻击函数"""
# 1. 提取ZIP文件信息
file_info = extract_zip_info(zip_path)
if not file_info:
return
# 2. 用户交互配置
charset = get_user_charset()
# 3. 对每个文件进行攻击
results = {}
for filename, info in file_info.items():
if info['size'] <= max_length:
print(f"攻击文件: {filename} (大小: {info['size']}字节)")
plaintext = brute_crc32(info['crc'], info['size'], charset)
results[filename] = plaintext
# 4. 输出结果
print_results(results)
五、完整脚本代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import zipfile
import binascii
import itertools
import os
import string
def banner():
print('+-----------------------------------------------------+')
print('+ CRC32碰撞攻击工具 +')
print('+ 小文件CRC32碰撞明文恢复脚本 +')
print('+ 仅限教学/CTF/合法授权使用 +')
print('+-----------------------------------------------------+')
def choose_charset():
"""字符集选择函数"""
print('请选择枚举字符集:')
print(' [1] 数字 (0-9)')
print(' [2] 小写字母 (a-z)')
print(' [3] 大写字母 (A-Z)')
print(' [4] 所有字母 (a-zA-Z)')
print(' [5] 可打印字符 (string.printable)')
print(' [6] 自定义字符集')
choice = input('输入选项编号 [默认1]: ').strip()
if choice == '2':
return string.ascii_lowercase
elif choice == '3':
return string.ascii_uppercase
elif choice == '4':
return string.ascii_letters
elif choice == '5':
return string.printable
elif choice == '6':
raw = input('请输入自定义字符集: ')
return ''.join(sorted(set(raw)))
else:
return string.digits
def brute_crc32(target_crc, length, charset):
"""CRC32暴力枚举函数"""
target_crc &= 0xffffffff
total = len(charset) ** length
print(f'目标CRC32: 0x{target_crc:08x}')
print(f'明文长度: {length}字节,字符集大小: {len(charset)}')
print(f'搜索空间: {total}种可能')
if total > 1e8:
print('警告: 搜索空间过大,可能需要较长时间')
count = 0
for combination in itertools.product(charset, repeat=length):
candidate = ''.join(combination)
crc_val = binascii.crc32(candidate.encode()) & 0xffffffff
count += 1
if crc_val == target_crc:
print(f'命中! 尝试次数: {count}, 明文: {repr(candidate)}')
return candidate
if count % 1000000 == 0:
print(f'已尝试: {count}/{total}')
print('未找到匹配明文')
return None
def crack_zip_crc(zip_path, max_length=4):
"""主攻击函数"""
if not os.path.exists(zip_path):
print(f'文件不存在: {zip_path}')
return
try:
zf = zipfile.ZipFile(zip_path, 'r')
except Exception as e:
print(f'打开ZIP文件失败: {e}')
return
charset = choose_charset()
results = {}
for name in zf.namelist():
info = zf.getinfo(name)
crc = info.CRC & 0xffffffff
size = info.file_size
print(f'\n文件: {name}')
print(f'大小: {size}字节, CRC32: 0x{crc:08x}')
if size > max_length:
print('文件过大,跳过')
continue
plaintext = brute_crc32(crc, size, charset)
results[name] = plaintext
zf.close()
# 输出最终结果
print('\n' + '='*50)
print('攻击结果汇总:')
for name, pt in results.items():
status = repr(pt) if pt else '未找到'
print(f'{name}: {status}')
def main():
banner()
zip_path = input('请输入ZIP文件路径: ').strip()
if zip_path:
crack_zip_crc(zip_path)
if __name__ == '__main__':
main()
六、攻击优化与注意事项
6.1 性能优化策略
- 并行计算:使用多进程并行处理不同字符块
- 早期终止:对部分字符集实现智能剪枝
- 彩虹表:对常用字符集预计算CRC32映射
6.2 使用限制与注意事项
- 文件长度限制:通常只适用于1-6字节的短文件
- 字符集选择:字符集越大,攻击时间呈指数增长
- 误报可能:存在不同明文产生相同CRC32的可能性
- 法律合规:仅限授权测试和教育用途
6.3 实际应用场景
- CTF竞赛:解决包含短文本的加密ZIP挑战
- 数字取证:恢复损坏压缩包中的关键短文件
- 密码学教学:理解哈希函数碰撞原理
七、总结
CRC32碰撞攻击是利用CRC32校验值空间有限的特性,通过暴力枚举恢复短文件内容的有效方法。虽然适用场景有限,但在特定条件下(文件长度短、字符集可控)具有很高的实用价值。本教学文档详细介绍了攻击原理、实现方法和注意事项,为相关领域的技术人员提供了完整的技术参考。
重要提醒:本技术应仅用于合法授权的安全测试、CTF竞赛和教育研究目的,严禁用于任何非法活动。