关键词:MD5、SHA-1、SHA-256、SHA-512、碰撞攻击、哈希数据库、hashcat
难度:入门
前置知识:取证流程与原则
一、概述
比对 2 TB 的镜像和原始介质是不是同一份,靠逐字节比对要跑几天。哈希把它压成 64 个十六进制字符。
这里有一个必须先分清的区分:取证需要的是哈希函数三个性质里的前两个,不是第三个。确定性和单向性至今完好,前者让你能跨机比对,后者让你无法从哈希反推内容。
抗碰撞性防的是这样一类对手:既能准备两份哈希相同、内容不同的文件,又能让其中一个的文件和另一个文件的哈希值同时进入记录。取证现场常见的情形并不是这样——哈希由取证人自己计算并写进记录,事后篡改数据的人无从影响这个已经落在纸面上的值,他改动文件时必须连哈希一起重算,于是留下的是"新文件的哈希不等于记录值",这属于确定性和单向性就能发现的情形,不是碰撞。
这不等于抗碰撞性无关。当哈希值不是由你独家计算,而是由对方提供、预置或早已在别处登记——送检材料附带的校验值、多方共同持有的哈希、去重系统里的内容指纹——此时能够同时操纵文件与登记值的对手才真正存在,碰撞构造才有意义。取证中凡遇到哈希值不是你算的这一情形,就退回抗碰撞性这一侧来评估。
这个区分解释了 2.3 为什么说"MD5 可以用,但不能作为唯一依据":自带哈希值的材料(例如从对方系统导出的校验文件、镜像分卷附带的 .md5)一旦被采信为比对依据,MD5 的碰撞现实就会变成直接风险,而不只是理论上的算法强度问题。
哈希贯穿全流程四个节点,但它不是一个阶段,是一个持续动作。
源介质 ──采集──> 镜像 ──复制──> 分析副本 ──分析──> 结论
H0 H1 H2 H3
└──── 必须相等 ────┘ └─── 必须相等 ───┘
H0 与 H1 相等,证明采集无损;H2 与 H3 相等,证明分析过程没动数据。这两组相等关系是取证的核心证明——第五章案例里四个节点全部记录且一致,支撑的就是这一句话。
两组相等各有各的作用对象。H0 是采集时同步算出的源介质哈希,H1 是事后从已落盘的镜像重新读的,两条读取路径撞在同一个值上,才排除了"写盘时错了一块、而错的那块又被一起算进去了"这种自证。H2 若取自 E01 的内嵌 Hash section,而那个 section 是采集时写进容器的,独立性就只来自 H1 与 H0 的独立读取,不来自它自己。
上游依赖镜像制作:dcfldd hash=... hashlog=... 必须在采集时同步计算,事后对已有镜像补算是另一回事(步骤 1 强调这一点,第四章陷阱 5 会讲为什么补算无效)。dcfldd 的价值在于一次读取同时算源和镜像的哈希,避免"dd 完再 sha256sum"造成的二次读盘和中间态风险。
下游支撑证据保管链与委托证明:链上最有价值的一行就是哈希值,它能证明数据没变,但不能证明数据从哪来。
落到具体产物上,DigiForensics.hashlog 是 dcfldd 边读边算写出的日志,它是 H0 的唯一来源,事后无法重建。DigiForensics.dd 的 sha256sum 给出 H1/H2/H3 三个值,它们来自同一个文件,分别在采集完成、分析开始、分析结束时计算。
E01 的 Hash section 是容器内嵌摘要,它针对的是解压后的原始字节流,不是压缩后容器(第四章陷阱 8)。ewfverify 的输出提供独立验证通道,与外部记录的哈希互为印证;它不带 -f 时用容器内嵌的 MD5 作为默认目标算法。
NSRL / 已知文件库是以 MD5 为主索引的已知文件集合,用途是排除而非证明:命中说明这是常见系统文件,不命中说明它不常见,两者都不能单独定性。哈希值只能在同算法之间比较,用 SHA-256 去查一个 MD5 索引的库,得到的是"无匹配"而不是"不匹配"——两件事的含义完全不同。
空字符串 MD5 d41d8cd98f00b204e9800998ecf8427e 常被用作"文件为空"的特征信号。密码哈希($1$/$5$/$6$/$argon2 等前缀)是另一种完全不同的哈希对象,它的用途是路径 B(密码恢复),不是路径 A(完整性验证),第四章陷阱 12 讲的是把两者混用的后果。hash_chain.log 是分析前后追加记录的日志文件。
据此可以判断几件事:MD5 现在还能不能用(能,但不能作唯一依据)、为什么 SHA-1 和 MD5 属于同一档、完整一次取证该出现几次哈希(四次)、以及遇到故障盘时怎么用分窗哈希把损坏定位到一个区间。
哈希能证明内容相同,为什么不能证明来源合法,那是保管链的事,见证据保管链与委托证明;两个文件内容相似但不完全相同怎么判断同源,相似度是另一套判据,见近似匹配与模糊哈希;SHA-3 / BLAKE3 的性能优势属于格式与工具方向,术语表与官方文档更合适;密码怎么恢复不在这里展开,步骤 6 只讲怎么识别哈希类型与格式,实际恢复强调授权 + 最小化 + 脱敏,见通用密码恢复。
上手前需要先知道取证流程分几个阶段(见取证流程与原则),否则"分析前后各算一次"这句话里的"分析"没有边界。另外建议先实际跑过 sha256sum 和 md5sum,亲手验证 2.2 那张表里 abc 的四个哈希值。这张表的价值不在背诵,在于让你看到 MD5 与 SHA-256 输出长度的真实差异——128 位与 256 位不是"短一点长一点"的关系,抗碰撞空间差 2 的 128 次方倍。
二、核心原理
2.1 哈希函数的三个性质
| 性质 |
含义 |
取证中的意义 |
| 确定性 |
相同输入必得相同输出 |
同一文件任何时候算都一样,可跨机比对 |
| 单向性 |
已知输出难以反推输入 |
无法从哈希"还原"文件,密码才安全 |
| 抗碰撞 |
难以找到两个不同输入产生相同输出 |
已被 MD5 和 SHA-1 攻破;哈希值由他人提供时直接相关 |
关键理解:前两条至今完好,支撑日常取证。抗碰撞性平时用不上,在哈希值由他人提供或早已在别处登记时才会成为决定性判据——这就是 MD5 在取证中仍有位置、却不能单独承担完整性的原因。
2.2 四种算法的实测对比
用输入 abc 实测(可用 printf 'abc' | <工具> 自行验证):
| 算法 |
输出长度 |
abc 的实测哈希值 |
状态 |
| MD5 |
128 bit (32 字符) |
900150983cd24fb0d6963f7d28e17f72 |
已不安全,见 2.3 |
| SHA-1 |
160 bit (40 字符) |
a9993e364706816aba3e25717850c26c9cd0d89d |
已不安全 |
| SHA-256 |
256 bit (64 字符) |
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad |
当前推荐 |
| SHA-512 |
512 bit (128 字符) |
ddaf35a1...454d4423643ce80e2a9ac94fa54ca49f |
高安全场景 |
空字符串的 MD5 恒为 d41d8cd98f00b204e9800998ecf8427e,常被用作"文件为空"的特征信号。
2.3 为什么取证要弃用 MD5(但不能全盘否定)
MD5 的问题不在于"能算错",而在于碰撞可被主动构造。
| 事件 |
含义 |
| 2004 年发现实用碰撞 |
首次证明 MD5 碰撞可行 |
| 2008 年 SHAttered |
首个公开的相同前缀碰撞,两份不同文件拥有相同 MD5 |
| 2019 年 chosen-prefix collision |
更实用的攻击:攻击者可在两个文件各自前缀后自由插入碰撞块 |
这意味着什么:如果一份文件被"合法地"修改过,攻击者可以计算出修改后版本的 MD5,使其与原始版本的 MD5 完全相同。于是"源盘 MD5 == 镜像 MD5"这个证明就失效了——两份不同的数据拥有同一个指纹。
⚠️ 这正是"为什么现在必须用 SHA-256"的直接原因:SHA-256 目前没有实用的碰撞构造方法。
但 MD5 不是完全无用。以下场景仍然合理:
| 合理场景 |
理由 |
| 兼容历史系统与格式 |
E01 早期版本、很多司法鉴定规范、NSRL 等数据库仍以 MD5 为主索引 |
| 快速粗筛 |
计算速度比 SHA-256 快得多,批量扫描上亿文件时先跑 MD5 缩小范围 |
| 交叉校验 |
同时记录 MD5+SHA-256,MD5 作为辅助、便于与外部数据比对 |
实务原则:新做的案件至少要有 SHA-256;MD5 可以并列记录,但不能作为唯一完整性依据。报告中写"MD5 一致"而没有 SHA-256,在严谨质证时会被追问。
2.4 SHA-1 的特殊尴尬地位
SHA-1 情况比 MD5 更微妙。Git 等大量系统仍在用 SHA-1(Git 直到近年才逐步迁移),但它同样有已公开的碰撞构造(SHA-1 is a Shambles 首次展示了实际可行的碰撞)。
结论:取证中 SHA-1 和 MD5 属于同一档,都只能作辅助。若设备/格式只内嵌了 SHA-1,你需要用外部记录的 SHA-256 补齐。
2.5 哈希链:一次计算远远不够
一次完整取证应至少出现四次哈希:
H0 源介质哈希 —— 采集时同步计算(dcfldd hash=...)
H1 镜像文件哈希 —— 采集完成立刻计算
验证:H0 == H1 ← 这一步是取证的核心证明
H2 分析副本哈希 —— 开始分析前计算
H3 分析后哈希 —— 分析结束重新计算
验证:H2 == H3 ← 证明分析过程没改动数据
源介质 ──采集──> 镜像 ──复制──> 分析副本 ──分析──> 结论
H0 H1 H2 H3
└──── 必须相等 ────┘ └─── 必须相等 ───┘
dcfldd 的价值就在这里:一次读取同时算源和镜像的哈希,避免"dd 完再 sha256sum"造成的二次读盘和中间态风险。
2.6 哈希数据库的实战价值
已知文件库是哈希最大的非密码学用途:
| 数据库 |
作用 |
取证用途 |
| NSRL / known-good |
数亿已知文件的哈希 |
快速排除系统文件,剩余的都是"值得看"的 |
| malware 库 |
已知恶意样本哈希 |
命中即定性 |
| 本机基线库 |
自己构建(装机即哈希全部文件) |
企业内网取证,发现"非标准"文件 |
效果示例:对一块 500 GB 的镜像做全盘哈希后与 NSRL 比对,通常能过滤掉 60%–80% 的文件——因为绝大多数是操作系统和常用软件自带的。剩下的部分才需要逐个人工审阅。
2.7 哈希在密码恢复中的角色
破解的前提永远是"拿到哈希值"。取证中常见的来源有这几处:
| 来源 |
典型哈希类型 |
备注 |
| Windows SAM/SYSTEM |
NTLM |
需先离线提取 |
Linux /etc/shadow |
SHA-512 crypt ($6$) 或 bcrypt |
现代发行版多为 SHA-512 |
| 浏览器密码库 |
AES 密钥 + DPAPI/Keychain |
见板块 5 |
| 数据库配置 |
明文/salt+hash |
宝塔、WordPress 等 |
| 无线网络 |
WPA-PMKID |
需抓取握手/EAPOL |
这是两条完全不同的使用路径。路径 A(证据用途)用哈希证明文件没变,用 sha256sum,不涉及破解;路径 B(还原用途)用哈希尝试还原明文密码,用 hashcat/john。
本篇重点讲 A。B 的攻击手法详见板块 5。
三、操作步骤
步骤 1:采集时同步计算(推荐方式)
# 一次读盘,同时算源与镜像的哈希 —— 最佳实践
sudo dcfldd if=/dev/sdX of=DigiForensics.dd \
hash=md5,sha256 hashlog=DigiForensics.hashlog \
bs=4M conv=noerror,sync status=on
# 查看生成的哈希日志
cat DigiForensics.hashlog
💡 hashwindow 参数可让 dcfldd 每 N 字节记一次分窗哈希。对疑似故障盘很有价值:如果两次读取同一区段结果不同,能精确定位不稳定区域。
步骤 2:独立复算验证
# 用独立工具复算镜像,确保不是 dcfldd 的 bug
sha256sum DigiForensics.dd
md5sum DigiForensics.dd
# 对 E01 容器,用容器自身的验证能力
ewfverify DigiForensics.E01
两条路径都应通过。若 dcfldd 记录值与 sha256sum 复算值不一致,说明流程中有问题,必须查明。
步骤 3:分析前后各算一次
# 分析前
sha256sum DigiForensics.dd | tee /case/h_before.txt
# ... 分析操作 ...
# 分析后
sha256sum DigiForensics.dd | tee /case/h_after.txt
# 自动比对
cut -d' ' -f1 /case/h_before.txt
cut -d' ' -f1 /case/h_after.txt
步骤 4:分窗哈希定位损坏位置
# 每 512 MB 记一次哈希,用于故障盘的精确定位
sudo dcfldd if=/dev/sdX of=DigiForensics.dd \
hash=sha256 hashwindow=512M hashlog=DigiForensics.window.log \
bs=4M conv=noerror,sync status=on
# 比对两次运行的分窗哈希,找出不稳定区段
diff <(awk '{print $1}' run1.window.log) <(awk '{print $1}' run2.window.log)
步骤 5:批量文件哈希(用于 NSRL 比对)
# 单文件
sha256sum "/mnt/case/Users/Alice/report.docx"
# 递归整个目录,输出可直接喂给比对工具
find /mnt/case -type f -exec sha256sum {} \; > allfiles.sha256
# 与已知文件库比对(需预先导入 NSRL 到比对数据库)
# 常见工具:hashdeep、hfind(NsrlUpdate 项目)
hfind allfiles.sha256
步骤 6:识别与破解密码哈希(路径 B)