TL;DR 让这两张图片发生 MD5 碰撞现在(*) 轻而易举且即时。
⟷
<a href=http://gunshowcomic.com/648>
不要玩火,不要依赖 MD5。
(*) 碰撞任意一对文件在很多年前就已可行,但每次需要数小时,且没有捷径。
本页面提供了针对特定文件格式的技巧以及预计算的碰撞前缀,使碰撞可以即时完成。
git clone. 运行脚本。完成。
作者:Ange Albertini 和 Marc Stevens。
目标是广泛探索现有的攻击——并在此过程中展示 MD5 有多么脆弱(任意 JPG、PNG、PDF、MP4、PE 等均可即时碰撞)—— 并详细研究常见文件格式,以确定 它们如何被当前或未来的攻击所利用。
事实上,相同的文件格式技巧可以用于多种哈希 (相同的 JPG 技巧已被用于 MD5、 恶意 SHA-1 和 SHA1), 只要碰撞遵循相同的字节模式。
本文档不是关于新的攻击(最近的一次攻击记录于 2012 年), 而是关于现有攻击的新利用形式。
截至 2018 年 12 月,已知攻击的当前状态:
获取一个文件,使其哈希等于另一个文件或给定哈希:不可能
使两个不同的文件具有相同的 MD5:即时
使两个任意文件获得相同的 MD5:数小时(72 小时.core)
使两个特定文件格式(PNG、JPG、PE 等)的任意文件获得相同的 MD5:即时
使两个不同的文件具有相同的 SHA1:6500 年.core
import crypt crypt.crypt("5dUD&66", "br") 'brokenOz4KxMc' crypt.crypt("O!>',%$", "br") 'brokenOz4KxMc'
# 攻击
MD5 和 SHA1 以 64 字节的块为单位工作。
如果两个内容 A 与 B 具有相同的哈希值,那么向两者追加相同的内容 C,哈希值仍将保持相同。``` text
hash(A) = hash(B) -> hash(A + C) = hash(B + C)
碰撞的工作原理是在块边界处插入一定数量的计算所得碰撞块, 其数量取决于文件中此之前的内容。 这些碰撞块看起来非常随机,但带有一些细微差异 (每种攻击遵循特定模式), 它们会引入微小差异,并最终 使这些块之后的哈希值相同。
这些差异被恶意利用来构造具有特定属性的有效文件。
文件格式同样自上而下工作,且大多数按字节级块处理。
可以插入一些“注释”块,以将文件块对齐到块边界, 将特定结构与碰撞块的差异对齐, 对文件解析器隐藏碰撞块其余部分的随机性, 并对解析器隐藏本应有效的内容(使其看到另一内容)。
这些“注释”块往往并非官方真正的注释: 它们只是被用作解析器忽略的数据容器 (例如,ID 以小写字母开头的 PNG 块是辅助性的,而非关键性的)。
大多数情况下,碰撞块中的差异被用来修改注释块的长度,
该长度通常在该块数据之前声明:
在此注释块较短版本与较长版本之间的间隙中,
声明另一个注释块以跳过一个文件的内容 A。
在此文件内容 A 之后,直接附加另一个文件内容 B。

由于文件格式通常定义一个终止符,使解析器在其后停止,
A 将终止解析,从而使附加的内容 B 被忽略。
因此通常至少需要两个注释——往往需要三个:
文件格式的这些常见特性使之成为可能——它们通常不被视为弱点,但可以被检测或规范化消除:
| 前缀 | = | 前缀 |
|---|---|---|
| 碰撞 A | ≠ | 碰撞 B |
| 后缀 | = | 后缀 |
两个文件几乎完全相同(它们的内容只有几个比特的差异)
利用:
捆绑两份内容,然后选择:
具有此结构的两个文件:
| 前缀 | = | 前缀 |
|---|---|---|
| 碰撞 A | ≠ | 碰撞 B |
| A | = | |
| = | B |
将显示 A 或 B。
最终版本于 2009 年发布。
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
.. .. .. X. .. .. .. .. .. .. .. .. .. .. .. ..
.. .. .. .. .. .. .. .. .. .. .. .. .. X. .X ..
.. .. .. .. .. .. .. .. .. .. .. X. .. .. .. ..
这些差异不在块的开始/结束附近,因此很难利用,因为你无法控制任何邻近字节。 一个潜在的解决方案是暴力破解周围字节——参见 PoCGTFO 14:10。
示例:
使用空前缀:``` MD5: fe6c446ee3a831ee010f33ac9c1b602c SHA256: c5dd2ef7c74cd2e80a0fd16f1dd6955c626b59def888be734219d48da6b9dbdd
00: 37 75 C1 F1-C4 A7 5A E7-9C E0 DE 7A-5B 10 80 26 7u┴±─ºZτ£α▐z[►Ç&
10: 02 AB D9 39-C9 6C 5F 02-12 C2 7F DA-CD 0D A3 B0 ☻½┘9╔l_☻↕┬⌂┌═♪ú░
20: 8C ED FA F3-E1 A3 FD B4-EF 09 E7 FB-B1 C3 99 1D îφ·≤ßú²┤∩○τ√▒├Ö↔
30: CD 91 C8 45-E6 6E FD 3D-C7 BB 61 52-3E F4 E0 38 ═æ╚Eµn²=╟╗aR>⌠α8
40: 49 11 85 69-EB CC 17 9C-93 4F 40 EB-33 02 AD 20 I◄àiδ╠↨£ôO@δ3☻¡
50: A4 09 2D FB-15 FA 20 1D-D1 DB 17 CD-DD 29 59 1E ñ○-√§· ↔╤█↨═▌)Y▲ ................
60: 39 89 9E F6-79 46 9F E6-8B 85 C5 EF-DE 42 4F 46 9ë₧÷yFƒµïà┼∩▐BOF ...X............
70: C2 78 75 9D-8B 65 F4 50-EA 21 C5 59-18 62 FF 7B ┬xu¥ïe⌠PΩ!┼Y↑b { .............XX.
...........X....
................
00: 37 75 C1 F1-C4 A7 5A E7-9C E0 DE 7A-5B 10 80 26 7u┴±─ºZτ£α▐z[►Ç& ...X............
10: 02 AB D9 B9-C9 6C 5F 02-12 C2 7F DA-CD 0D A3 B0 ☻½┘╣╔l_☻↕┬⌂┌═♪ú░ .............XX.
20: 8C ED FA F3-E1 A3 FD B4-EF 09 E7 FB-B1 43 9A 1D îφ·≤ßú²┤∩○τ√▒CÜ↔ ...........X....
30: CD 91 C8 45-E6 6E FD 3D-C7 BB 61 D2-3E F4 E0 38 ═æ╚Eµn²=╟╗a╥>⌠α8
40: 49 11 85 69-EB CC 17 9C-93 4F 40 EB-33 02 AD 20 I◄àiδ╠↨£ôO@δ3☻¡ /
50: A4 09 2D 7B-15 FA 20 1D-D1 DB 17 CD-DD 29 59 1E ñ○-{§· ↔╤█↨═▌)Y▲
60: 39 89 9E F6-79 46 9F E6-8B 85 C5 EF-DE C2 4E 46 9ë₧÷yFƒµïà┼∩▐┬NF
70: C2 78 75 9D-8B 65 F4 50-EA 21 C5 D9-18 62 FF 7B ┬xu¥ïe⌠PΩ!┼┘↑b {
MD5: fe6c446ee3a831ee010f33ac9c1b602c SHA256: e27cf3073c704d0665da42d597d4d20131013204eecb6372a5bd60aeddd5d670
其他具有相同前缀的示例:[1](https://github.com/decalage2/collisions/blob/master/examples/fastcoll1.bin) ⟷ [2](https://github.com/decalage2/collisions/blob/master/examples/fastcoll2.bin)
**变体**:存在一种[单块 MD5 碰撞](https://marc-stevens.nl/research/md5-1block-collision/),但需要五周的计算时间。
这里有一段[记录](https://github.com/decalage2/collisions/blob/master/examples/fastcoll.svg),展示不带任何前缀的 FastColl 计算过程,
以及另一段[带前缀的记录](https://github.com/decalage2/collisions/blob/master/examples/fastcoll-prefix.svg)。