
Hash collisions and their exploitations
TL;DR obtenir une collision MD5 de ces deux images est désormais(*) trivial et instantané.
⟷
<a href=http://gunshowcomic.com/648>
Ne jouez pas avec le feu, ne vous fiez pas à MD5.
(*) Collisionner n'importe quelle paire de fichiers est possible depuis de nombreuses années, mais cela prend plusieurs heures à chaque fois, sans raccourci.
Cette page fournit des astuces spécifiques aux formats de fichiers et des préfixes de collision précalculés pour rendre la collision instantanée.
git clone. Exécutez le script. Terminé.
Par Ange Albertini et Marc Stevens.
L'objectif est d'explorer en profondeur les attaques existantes - et de montrer au passage à quel point MD5 est faible (collisions instantanées de n'importe quel JPG, PNG, PDF, MP4, PE...) - et aussi d'explorer en détail les formats de fichiers courants pour déterminer comment ils peuvent être exploités avec des attaques présentes ou futures.
En effet, la même astuce de format de fichier peut être utilisée sur plusieurs hashs (les mêmes astuces JPG ont été utilisées pour MD5, SHA-1 malveillant et SHA1), tant que les collisions suivent les mêmes motifs d'octets.
Ce document ne traite pas de nouvelles attaques (la plus récente a été documentée en 2012), mais de nouvelles formes d'exploitation des attaques existantes.
État actuel - en décembre 2018 - des attaques connues :
obtenir un fichier qui a le hash d'un autre fichier ou un hash donné : impossible
obtenir deux fichiers différents avec le même MD5 : instantané
faire en sorte que deux fichiers arbitraires aient le même MD5 : quelques heures (72 heures.core)
faire en sorte que deux fichiers arbitraires de formats spécifiques (PNG, JPG, PE...) aient le même MD5 : instantané
obtenir deux fichiers différents avec le même SHA1 : 6500 ans.core
(*) exemple avec crypt - merci Sven !```
import crypt crypt.crypt("5dUD&66", "br") 'brokenOz4KxMc' crypt.crypt("O!>',%$", "br") 'brokenOz4KxMc'
# Attaques
MD5 et SHA1 fonctionnent avec des blocs de 64 octets.
Si deux contenus A et B ont le même hachage, alors ajouter le même contenu C aux deux conservera le même hachage.``` text
hash(A) = hash(B) -> hash(A + C) = hash(B + C)
Collisions work by inserting at a block boundary a number of computed collision blocks that depends on what came before in the file. These collision blocks are very random-looking with some minor differences (that follow a specific pattern for each attack) and they will introduce tiny differences while eventually getting hashes the same value after these blocks.
These differences are abused to craft valid files with specific properties.
File formats also work top-down, and most of them work by byte-level chunks.
Some 'comment' chunks can be inserted to align file chunks to block boundaries, to align specific structures to collision blocks differences, to hide the rest of the collision blocks randomness from the file parsers, and to hide otherwise valid content from the parser (so that it will see another content).
These 'comment' chunks are often not officially real comments: they are just used as data containers that are ignored by the parser (for example, PNG chunks with a lowercase-starting ID are ancillary, not critical).
Most of the time, a difference in the collision blocks is used to modify the length of a comment chunk,
which is typically declared just before the data of this chunk:
in the gap between the smaller and the longer version of this chunk,
another comment chunk is declared to jump over one file's content A.
After this file content A, just append another file content B.

Since file formats usually define a terminator that will make parsers stop after it,
A will terminate parsing, which will make the appended content B ignored.
So typically at least two comments are needed - often three:
These common properties of file formats make it possible - they are not typically seen as weaknesses, but they can be detected or normalized out:
| Prefix | = | Prefix |
|---|---|---|
| Collision A | ≠ | Collision B |
| Suffix | = | Suffix |
Both files are almost identical (their content have only a few bits of differences)
Exploitation:
Bundle two contents, then either:
Two files with this structure:
will show either A or B.
Final version in 2009.
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
.. .. .. X. .. .. .. .. .. .. .. .. .. .. .. ..
.. .. .. .. .. .. .. .. .. .. .. .. .. X. .X ..
.. .. .. .. .. .. .. .. .. .. .. X. .. .. .. ..
The differences aren't near the start/end of the blocks, so it's very hard to exploit since you don't control any nearby byte. A potential solution is to brute-force the surrounding bytes - cf PoCGTFO 14:10.
Examples:
With an empty prefix:``` 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
Autres exemples, avec un préfixe identique : [1](https://github.com/decalage2/collisions/blob/HEAD/examples/fastcoll1.bin) ⟷ [2](https://github.com/decalage2/collisions/blob/HEAD/examples/fastcoll2.bin)
**Variante** : il existe une [collision MD5 à un seul bloc](https://marc-stevens.nl/research/md5-1block-collision/) mais elle nécessite cinq semaines de calcul.
Voici un [enregistrement](https://github.com/decalage2/collisions/blob/HEAD/examples/fastcoll.svg) d'un calcul FastColl sans préfixe
et [un autre](https://github.com/decalage2/collisions/blob/HEAD/examples/fastcoll-prefix.svg) avec un préfixe.
### [UniColl](https://github.com/decalage2/collisions/blob/HEAD/unicoll.md) (MD5)
Documenté en [2012](https://www.cwi.nl/system/files/PhD-Thesis-Marc-Stevens-Attacks-on-Hash-Functions-and-Applications.pdf#page=199), implémenté en [2017](https://github.com/cr-marcstevens/hashclash/blob/95c2619a8078990056beb7aaa59104021714ee3c/scripts/poc_no.sh)
[UniColl](https://github.com/cr-marcstevens/hashclash#create-you-own-identical-prefix-collision) vous permet de contrôler quelques octets dans les blocs de collision,
avant et après la première différence, ce qui en fait une collision à préfixe identique avec quelques différences contrôlables, presque comme une collision à préfixe choisi.
C'est très pratique, et mieux encore, la différence peut être très prévisible :
dans le cas de `m2+= 2^8` (alias `N=1` / `m2 9` dans le script HashClash [poc_no.sh](https://github.com/cr-marcstevens/hashclash/blob/master/scripts/poc_no.sh#L30)),
la différence est de +1 sur le 9e octet, ce qui la rend très exploitable,
car vous pouvez même penser à la collision de tête :
le 9e caractère de cette phrase sera remplacé par le suivant : `0` remplacé par `1`, `a` remplacé par `b`..
- temps : quelques minutes (dépend du nombre d'octets que vous voulez contrôler )
- espace : deux blocs
- différences : ```
.. .. .. .. DD .. .. .. ..
.. .. .. .. +1 .. .. .. ..
Exemples avec N=1 et 20 octets de texte défini dans les blocs de collision:```
00: 55 6E 69 43-6F 6C 6C 20-31 20 70 72-65 66 69 78 UniColl 1 prefix
10: 20 32 30 62-F5 48 34 B9-3B 1C 01 9F-C8 6B E6 44 20b⌡H4╣;∟☺ƒ╚kµD
20: FE F6 31 3A-63 DB 99 3E-77 4D C7 5A-6E B0 A6 88 ■÷1:c█Ö>wM╟Zn░ªê
30: 04 05 FB 39-33 21 64 BF-0D A4 FE E2-A6 9D 83 36 ♦♣√93!d┐♪ñ■Γª¥â6
40: 4B 14 D7 F2-47 53 84 BA-12 2D 4F BB-83 78 6C 70 K¶╫≥GSä║↕-O╗âxlp
50: C6 EB 21 F2-F6 59 9A 85-14 73 04 DD-57 5F 40 3C ╞δ!≥÷YÜà¶s♦▌W_@< .........X......
60: E1 3F B0 DB-E8 B4 AA B0-D5 56 22 AF-B9 04 26 FC ß?░█Φ┤¬░╒V"»╣♦&ⁿ ................
70: 9F D2 0C 00-86 C8 ED DE-85 7F 03 7B-05 28 D7 0F ƒ╥♀ å╚φ▐à⌂♥{♣(╫☼ ................
................
.........X......
00: 55 6E 69 43-6F 6C 6C 20-31 21 70 72-65 66 69 78 UniColl 1!prefix ................
10: 20 32 30 62-F5 48 34 B9-3B 1C 01 9F-C8 6B E6 44 20b⌡H4╣;∟☺ƒ╚kµD ................
20: FE F6 31 3A-63 DB 99 3E-77 4D C7 5A-6E B0 A6 88 ■÷1:c█Ö>wM╟Zn░ªê ................
30: 04 05 FB 39-33 21 64 BF-0D A4 FE E2-A6 9D 83 36 ♦♣√93!d┐♪ñ■Γª¥â6
40: 4B 14 D7 F2-47 53 84 BA-12 2C 4F BB-83 78 6C 70 K¶╫≥GSä║↕,O╗âxlp /
50: C6 EB 21 F2-F6 59 9A 85-14 73 04 DD-57 5F 40 3C ╞δ!≥÷YÜà¶s♦▌W_@<
60: E1 3F B0 DB-E8 B4 AA B0-D5 56 22 AF-B9 04 26 FC ß?░█Φ┤¬░╒V"»╣♦&ⁿ
70: 9F D2 0C 00-86 C8 ED DE-85 7F 03 7B-05 28 D7 0F ƒ╥♀ å╚φ▐à⌂♥{♣(╫☼
UniColl a moins de contrôle qu'une véritable collision de préfixe choisi, mais elle est beaucoup plus rapide, surtout qu'elle ne prend que deux blocs.
Voici un [enregistrement](https://github.com/decalage2/collisions/blob/HEAD/examples/unicoll.svg) d'un calcul UniColl.
### [Shattered](http://shattered.io) (SHA1)
Documenté en [2013](https://marc-stevens.nl/research/papers/EC13-S.pdf), calculé en [2017](http://shattered.io).
- temps: 6500 années.CPU et 110 années.GPU
- espace: deux blocs
- différences: ```
.. .. .. DD ?? ?? ?? ??
or
?? ?? ?? DD .. .. .. ..
La différence entre les blocs de collision de chaque côté est ce masque Xor :``` 0C 00 00 02 C0 00 00 10 B4 00 00 1C 3C 00 00 04 BC 00 00 1A 20 00 00 10 24 00 00 1C EC 00 00 14 0C 00 00 02 C0 00 00 10 B4 00 00 1C 2C 00 00 04 BC 00 00 18 B0 00 00 10 00 00 00 0C B8 00 00 10
Exemples : [PoC||GTFO 0x18](https://github.com/angea/pocorgtfo#0x18) utilise les préfixes SHA1 calculés,
réutilise l'image directement depuis la source PDFLaTeX (voir [article 18:10](https://archive.org/stream/pocorgtfo18#page/n62/mode/1up)),
mais vérifie aussi la valeur des préfixes via JavaScript dans la page HTML (le fichier est polyglotte, ZIP, HTML et PDF).
## Collisions à préfixe choisi
Elles permettent de collisionner n'importe quel contenu.
| 𝓐 | ≠ | 𝔅 |
| :----: |:-:| :----: |
| Collision *A* | ≠ | Collision *B* |
1. prendre deux préfixes arbitraires
2. remplir le plus court pour qu'il soit aussi long que le plus long. les deux sont complétés jusqu'au bloc suivant - moins 12 octets
- ces 12 octets de données aléatoires seront ajoutés des deux côtés pour randomiser la recherche d'anniversaire
3. X blocs de quasi-collision seront calculés et ajoutés.
Moins il y a de blocs, plus le calcul est long.
Ex : [400 kHeures pour un bloc](https://www.win.tue.nl/hashclash/SingleBlock/). 72 heures-cœurs pour neuf blocs avec [HashClash](https://github.com/cr-marcstevens/hashclash).
Les collisions à préfixe choisi sont toutes-puissantes, mais elles peuvent prendre beaucoup de temps ne serait-ce que pour une paire de fichiers.
### [HashClash](https://github.com/cr-marcstevens/hashclash) (MD5)
Version finale en [2009](https://www.win.tue.nl/hashclash/ChosenPrefixCollisions/).
Exemples : collisionnons `yes` et `no`. Cela a pris trois heures sur 24 cœurs.```
'yes' prefix:
000: 79 65 73 0A-3D 62 84 11-01 75 D3 4D-EB 80 93 DE yes◙=bä◄☺u╙MδÇô▐ - Prefix, padding
010: 31 C1 D9 30-45 FB BE 1E-71 F0 0A 63-75 A8 30 AA 1┴┘0E√╛▲q≡◙cu¿0¬
020: 98 17 CA E3-A2 6B 8E 3D-44 A9 8F F2-0E 67 96 48 ÿ↨╩πókÄ=D⌐Å≥♫gûH
030: 97 25 A6 FB-00 00 00 00-49 08 09 33-F0 62 C4 E8 ù%ª√ I◘○3≡b─Φ
040: D5 F1 54 CD-CA A1 42 90-7F 9D 3D 9A-67 C4 1B 0F ╒±T═╩íBÉ⌂¥=Üg─←☼ - Collision blocks start
050: 04 9F 19 E8-92 C3 AA 19-43 31 1A DB-DA 96 01 54 ♦ƒ↓ΦÆ├¬↓C1→█┌û☺T
060: 85 B5 9A 88-D8 A5 0E FB-CD 66 9A DA-4F 20 8A AA à╡Üê╪Ñ♫√═fÜ┌O è¬
070: BA E3 9C F0-78 31 8F D1-14 5F 3E B9-0F 9F 3E 19 ║π£≡x1Å╤¶_>╣☼ƒ>↓
080: 09 9C BB A9-45 89 BA A8-03 E6 C0 31-A0 54 D6 26 ○£╗⌐Eë║¿♥µ└1áT╓&
090: 3F 80 4C 06-0F C7 D9 19-09 D3 DA 14-FD CB 39 84 ?ÇL♠☼╟┘↓○╙┌¶²╦9ä
0A0: 1F 0D 77 5F-55 AA 7A 07-4C 24 8B 13-0A 54 A2 BC ▼♪w_U¬z•L$ï‼◙Tó╝
0B0: C5 12 7D 4F-E0 5E F2 23-C5 07 61 E4-80 91 B2 13 ┼↕}Oα^≥#┼•aΣÇæ▓‼
0C0: E7 79 07 2A-CF 1B 66 39-8C F0 8E 7E-75 25 22 1D τy•*╧←f9î≡Ä~u%"↔
0D0: A7 3B 49 4A-32 A4 3A 07-61 26 64 EA-6B 83 A2 8D º;IJ2ñ:•a&dΩkâóì
0E0: BE A3 FF BE-4E 71 AE 18-E2 D0 86 4F-20 00 30 26 ╛ú ╛Nq«↑Γ╨åO 0&
0F0: 0A 71 DE 1F-40 B4 F4 8F-9C 50 5C 78-DD CD 72 89 ◙q▐▼@┤⌠Å£P\x▌═rë
100: BA D1 BF F9-96 80 E3 06-96 F3 B9 7C-77 2D EB 25 ║╤┐∙ûÇπ♠û≤╣|w-δ%
110: 1E 56 70 D7-14 1F 55 4D-EC 11 58 59-92 45 E1 33 ▲Vp╫¶▼UM∞◄XYÆEß3
120: 3E 0E A1 6E-FF D9 90 AD-F6 A0 AD 0E-C6 D6 88 12 >♫ín ┘É¡÷á¡♫╞╓ê↕
130: B8 74 F2 9E-DD 53 F7 88-19 73 85 39-AA 9B E0 8D ╕t≥₧▌S≈ê↓sà9¬¢αì
\
140: 82 BF 9C 5E-58 42 1E 3B-94 CF 5B 54-73 5F A8 4A é┐£^XB▲;ö╧[Ts_¿J
150: FD 5B 64 CF-59 D1 96 74-14 B3 0C AF-11 1C F9 47 ²[d╧Y╤ût¶│♀»◄∟∙G ................
160: C5 7A 2C F7-D5 24 F5 EB-BE 54 3E 12-B0 24 67 3F ┼z,≈╒$⌡δ╛T>↕░$g? ................
170: 01 DD 95 76-8D 0D 58 FB-50 23 70 3A-BD ED BE AC ☺▌òvì♪X√P#p:╜φ╛¼ ...............X
................
180: B8 32 DB AE-E8 DC 3A 83-7A C8 D5 0F-08 90 1D 99 ╕2█«Φ▄:âz╚╒☼◘É↔Ö
190: 2D 7D 17 34-4E A8 21 98-61 1A 65 DA-FC 9B A4 BA -}↨4N¿!ÿa→e┌ⁿ¢ñ║ ................
1A0: E1 42 2B 86-0C 94 2A F6-D6 A4 81 B5-2B 0B E9 37 ßB+å♀ö*÷╓ñü╡+♂Θ7 ................
1B0: 44 D2 E4 23-14 7C 16 B8-84 90 8B E0-A1 A7 BD 27 D╥Σ#¶|▬╕äÉïαíº╜' ..............X.
................
1C0: C7 7E E6 17-1A 93 C5 EE-59 70 91 26-4E 9D C7 7C ╟~µ↨→ô┼εYpæ&N¥╟|
1D0: 1D 3D AB F1-B4 F4 F1 D9-86 48 75 77-6E FE 98 84 ↔=½±┤⌠±┘åHuwn■ÿä ................
1E0: EF 3C 1C C7-16 5A 1F 83-60 EC 5C FE-CA 17 0C 74 ∩<∟╟▬Z▼â`∞\■╩↨♀t ................
1F0: EB 8E 9D F6-90 A3 CD 08-65 D5 5A 4C-2E C6 BE 54 δÄ¥÷Éú═◘e╒ZL.╞╛T ...............X
................
'no' prefix: ................
000: 6E 6F 0A E5-5F D0 83 01-9B 4D 55 06-61 AB 88 11 no◙σ_╨â☺¢MU♠a½ê◄ ................
010: 8A FA 4D 34-B3 75 59 46-56 97 EF 6C-4A 07 90 CC è·M4│uYFVù∩lJ•É╠ ............X...
020: FE 19 D7 CF-6F 92 03 9C-91 AA A5 DA-56 92 C1 04 ■↓╫╧oÆ♥£æ¬Ñ┌VÆ┴♦ ................
030: E6 4C 08 A3-00 00 00 00-8D B6 4E 47-FF AF 7A 3C µL◘ú ì╢NG »z<
................
040: D5 F1 54 CD-CA A1 42 90-7F 9D 3D 9A-67 C4 1B 0F ╒±T═╩íBÉ⌂¥=Üg─←☼ ................
050: 04 9F 19 E8-92 C3 AA 19-43 31 1A DB-DA 96 01 54 ♦ƒ↓ΦÆ├¬↓C1→█┌û☺T ............X...
060: 85 B5 9A 88-D8 A5 0E FB-CD 66 9A DA-4F 20 8A A9 à╡Üê╪Ñ♫√═fÜ┌O è⌐ ................
070: BA E3 9C F0-78 31 8F D1-14 5F 3E B9-0F 9F 3E 19 ║π£≡x1Å╤¶_>╣☼ƒ>↓
................
080: 09 9C BB A9-45 89 BA A8-03 E6 C0 31-A0 54 D6 26 ○£╗⌐Eë║¿♥µ└1áT╓& ................
090: 3F 80 4C 06-0F C7 D9 19-09 D3 DA 14-FD CB 39 84 ?ÇL♠☼╟┘↓○╙┌¶²╦9ä .............X..
0A0: 1F 0D 77 5F-55 AA 7A 07-4C 24 8B 13-0A 54 B2 BC ▼♪w_U¬z•L$ï‼◙T▓╝ ................
0B0: C5 12 7D 4F-E0 5E F2 23-C5 07 61 E4-80 91 B2 13 ┼↕}Oα^≥#┼•aΣÇæ▓‼
................
0C0: E7 79 07 2A-CF 1B 66 39-8C F0 8E 7E-75 25 22 1D τy•*╧←f9î≡Ä~u%"↔ ................
0D0: A7 3B 49 4A-32 A4 3A 07-61 26 64 EA-6B 83 A2 8D º;IJ2ñ:•a&dΩkâóì ...............X
0E0: BE A3 FF BE-4E 71 AE 18-E2 D0 86 4F-20 00 30 22 ╛ú ╛Nq«↑Γ╨åO 0" ................
0F0: 0A 71 DE 1F-40 B4 F4 8F-9C 50 5C 78-DD CD 72 89 ◙q▐▼@┤⌠Å£P\x▌═rë
/
100: BA D1 BF F9-96 80 E3 06-96 F3 B9 7C-77 2D EB 25 ║╤┐∙ûÇπ♠û≤╣|w-δ%
110: 1E 56 70 D7-14 1F 55 4D-EC 11 58 59-92 45 E1 33 ▲Vp╫¶▼UM∞◄XYÆEß3
120: 3E 0E A1 6E-FF D9 90 AD-F6 A0 AD 0E-CA D6 88 12 >♫ín ┘É¡÷á¡♫╩╓ê↕
130: B8 74 F2 9E-DD 53 F7 88-19 73 85 39-AA 9B E0 8D ╕t≥₧▌S≈ê↓sà9¬¢αì
140: 82 BF 9C 5E-58 42 1E 3B-94 CF 5B 54-73 5F A8 4A é┐£^XB▲;ö╧[Ts_¿J
150: FD 5B 64 CF-59 D1 96 74-14 B3 0C AF-11 1C F9 47 ²[d╧Y╤ût¶│♀»◄∟∙G
160: C5 7A 2C F7-D5 24 F5 EB-BE 54 3E 12-70 24 67 3F ┼z,≈╒$⌡δ╛T>↕p$g?
170: 01 DD 95 76-8D 0D 58 FB-50 23 70 3A-BD ED BE AC ☺▌òvì♪X√P#p:╜φ╛¼
180: B8 32 DB AE-E8 DC 3A 83-7A C8 D5 0F-08 90 1D 99 ╕2█«Φ▄:âz╚╒☼◘É↔Ö
190: 2D 7D 17 34-4E A8 21 98-61 1A 65 DA-FC 9B A4 BA -}↨4N¿!ÿa→e┌ⁿ¢ñ║
1A0: E1 42 2B 86-0C 94 2A F6-D6 A4 81 B5-2B 2B E9 37 ßB+å♀ö*÷╓ñü╡++Θ7
1B0: 44 D2 E4 23-14 7C 16 B8-84 90 8B E0-A1 A7 BD 27 D╥Σ#¶|▬╕äÉïαíº╜'
1C0: C7 7E E6 17-1A 93 C5 EE-59 70 91 26-4E 9D C7 7C ╟~µ↨→ô┼εYpæ&N¥╟|
1D0: 1D 3D AB F1-B4 F4 F1 D9-86 48 75 77-6E FE 98 84 ↔=½±┤⌠±┘åHuwn■ÿä
1E0: EF 3C 1C C7-16 5A 1F 83-60 EC 5C FE-CA 17 0C 54 ∩<∟╟▬Z▼â`∞\■╩↨♀T
1F0: EB 8E 9D F6-90 A3 CD 08-65 D5 5A 4C-2E C6 BE 54 δÄ¥÷Éú═◘e╒ZL.╞╛T
Voici un journal de toute l'opération.
Shambles est une collision de préfixe choisi très coûteuse qui utilise 9 blocs.
Chaque bloc a le même motif xor que Shattered:``` 0C 00 00 02 C0 00 00 10 B4 00 00 1C 3C 00 00 04 BC 00 00 1A 20 00 00 10 24 00 00 1C EC 00 00 14 0C 00 00 02 C0 00 00 10 B4 00 00 1C 2C 00 00 04 BC 00 00 18 B0 00 00 10 00 00 00 0C B8 00 00 10
## Attacks summary
Hash | Nom | Date | Durée | Type de préfixe | Contrôle près de la diff
---- | --------- | ---- | -------- | ----------- | -----------------
MD5 | FastColl | 2009 | 2s | Identique | aucun
| UniColl | 2012 | 7-40min | Identique | 4-10 octets
| HashClash | 2009 | 72h | Choisi | n/a
| | | | |
SHA1 | Shattered | 2013 | 6500 ans | Identique | préfixe et suffixe
| Shambles | 2020 | ? | Choisi | n/a
# Exploitations
Les collisions à préfixe identique sont généralement considérées comme (très) limitées, mais celles à préfixe choisi prennent du temps.
Une autre approche consiste à fabriquer des préfixes réutilisables, soit via une attaque à préfixe identique comme UniColl - ou un préfixe choisi pour surmonter certaines limitations - puis à réutiliser cette paire de préfixes en combinaison avec deux charges utiles, comme dans une attaque classique à préfixe identique.
Une fois que la paire de préfixes a été calculée, elle rend la collision de deux contenus instantanée : il s'agit simplement de manipuler les données du fichier (selon les formats de fichiers spécifiques) pour qu'elles correspondent aux spécifications des formats de fichiers et aux exigences de préfixe précalculé.
## Stratégie standard
Collisions classiques de deux fichiers valides avec le même type de fichier.
### JPG
Limitations théoriques et contournements :
- le segment *Application* devrait en théorie se trouver juste après le marqueur *Start of Image*.
En pratique, ce n'est pas nécessaire, donc notre collision peut être générique : la seule limitation est la taille de la plus petite image.
- la longueur d'un commentaire est stockée sur deux octets, donc la quantité qu'il peut stocker est limitée à 65536 octets (soit environ la taille d'une photo 400x400)
- plutôt que de sauter par-dessus un fichier JPG complet, on peut découper ce fichier en ses segments et ajouter des trampolines de saut entre les segments
*commentaires sur chaque segment d'image*
*comment les trampolines de commentaires fonctionnent*
- alors que la majeure partie d'une structure JPG est composée de segments dont la taille est limitée à 65536 octets,
les données compressées réelles sont stockées dans le *Entropy Coded Segment* qui ne respecte pas ses limitations :
sa taille est inconnue à l'avance et dépasse cette limite.
Elle croît avec la taille de l'image, représentant la majeure partie de la taille du fichier dans une image de base (non progressive).
Pour faire tenir toute l'image dans des morceaux de 64 ko, la méthode simple consiste à d'abord essayer d'enregistrer l'image en mode progressif (ce que n'importe quel logiciel peut faire, et qui divise l'ECS en général en six scans au maximum). La méthode plus avancée consiste à utiliser *JPEGTran* avec son paramètre de ligne de commande `--scans` du 'wizard' et à définir des scans personnalisés.
Il n'y a pas d'autre restriction en dehors des segments de scans, donc une collision MD5 entre deux JPG arbitraires est *instantanée* et ne nécessite pas de collision à préfixe choisi, mais seulement UniColl.
Avec le [script](https://github.com/decalage2/collisions/blob/HEAD/scripts/jpg.py) :```
21:07:35.65>jpg.py Ange.jpg Marc.jpg
21:07:35.75>
Exemples:
⟷
2 JPG en collision MD5
Voici un exemple de définition de scans JPEGTran pour transformer une image RGB 1944x2508 en un JPG 100% avec 20 scans qui tiennent tous dans 64kb.``` // : -, , ;
// 0=luma 0: 0-0, 0, 0; 0: 1-1, 0, 0; 0: 2-6, 0, 0; 0: 7-10, 0, 0; 0: 11-13, 0, 0; 0: 14-20, 0, 0; 0: 21-26, 0, 0; 0: 27-32, 0, 0; 0: 33-40, 0, 0; 0: 41-48, 0, 0; 0: 49-54, 0, 0; 0: 55-63, 0, 0;
// 1=blueness 1: 0-0, 0, 0; 1: 1-16, 0, 0; 1: 17-32, 0, 0; 1: 33-63, 0, 0;
// 2=redness 2: 0-0, 0, 0; 2: 1-16, 0, 0; 2: 17-32, 0, 0; 2: 33-63, 0, 0;
Résultat :
*une image RGB 1944x2508 en JPG à 100 % avec 20 scans*
### PNG
Limitations théoriques et solutions de contournement :
- Le PNG utilise un CRC32 à la fin de ses chunks, mais en pratique ils sont ignorés. Ils peuvent être corrects, mais ce n'est pas requis.
- les métadonnées de l'image (dimensions, espace colorimétrique...) sont stockées dans le chunk `IHDR`,
qui devrait en théorie se trouver juste après la signature (c'est-à-dire avant tout commentaire éventuel),
ce qui signifierait que nous ne pouvons précalculer que des collisions d'images ayant les mêmes métadonnées.
Cependant, ce chunk peut en réalité se trouver après un bloc de commentaires (dans la grande majorité des lecteurs, sauf ceux d'Apple), nous pouvons donc placer les données de collision avant l'en-tête,
ce qui permet de faire entrer en collision n'importe quelle paire de PNG avec un seul précalcul.
Comme un chunk PNG a une longueur de quatre octets, il n'est pas nécessaire de modifier la structure de l'un ou l'autre fichier : on peut sauter par-dessus une image entière d'un seul coup.
Nous pouvons insérer autant de chunks ignorés que nous voulons, nous pouvons donc en ajouter un pour l'alignement, puis un dont la longueur sera modifiée par un UniColl, ainsi la longueur sera `00` `75` et `01` `75`.
Ainsi, une collision MD5 de deux images PNG arbitraires est *instantanée*, sans aucun prérequis (aucun calcul, juste quelques modifications mineures de fichiers), et ne nécessite pas de collision à préfixe choisi, mais simplement UniColl.
Avec le [script](https://github.com/decalage2/collisions/blob/HEAD/scripts/png.py) :```
19:27:04.79>png.py nintendo.png sega.png
19:27:04.87>
Exemples :
⟷
2 PNG en collision MD5 avec des propriétés différentes
Voici un enregistrement de toute l'opération.
La plupart des lecteurs acceptent sans problème les fichiers PNG qui commencent par un bloc qui n'est pas IHDR.
Cependant, certains (comme Safari et Preview - d'autres ?) ne le tolèrent pas. Dans ce cas, l'en-tête d'image et ses propriétés (dimensions, espace colorimétrique) doivent être placés en premier, avant tout bloc de collision.
Dans ce cas, les deux fichiers en collision doivent avoir les mêmes propriétés. Encore une fois, UniColl suffit, et bien sûr la paire de préfixes calculée peut être réutilisée pour toute autre paire de fichiers ayant les mêmes propriétés.
Voici un script pour faire entrer en collision toute paire de tels fichiers, qui lance UniColl si nécessaire pour calculer la paire de préfixes.
Exemples :
⟷
⟷
2 paires de PNG en collision MD5 avec des propriétés identiques pour une compatibilité maximale
Voici un enregistrement de toute l'opération lorsqu'UniColl est invoqué,
et une autre lorsque le préfixe a déjà été calculé.
GIF est délicat :
Cependant, les blocs de commentaire suivent une structure particulière : c'est une chaîne de <length:1> <data:length> jusqu'à ce qu'une longueur nulle soit définie.
Ainsi, tout octet non nul devient un 'saut en avant' valide. Ce qui le rend adapté à une utilisation avec FastColl,
comme illustré dans PoC||GTFO 14:11.
Donc au minimum, même si nous ne pouvons pas avoir de préfixe générique, nous pouvons faire entrer en collision toute paire de GIF ayant les mêmes métadonnées (dimensions, palette) et il ne nous faut qu'une seconde de FastColl pour calculer son préfixe.
Le problème est que nous ne pouvons pas sauter par-dessus une image entière comme en PNG ou par-dessus une grande structure comme en JPG.
Une solution de contournement possible est de manipuler les données compressées ou de découper l'image en petites zones comme dans le cas du hashquine GIF, mais ce n'est pas optimal.
Une autre idée qui fonctionne génériquement est que les données d'image sont également stockées à l'aide de cette structure de séquence length data :
donc si nous prenons deux GIF sans animation, il suffit de :
Avec une configuration mineure (seulement quelques centaines d'octets de surcharge), nous pouvons glisser sur n'importe quelle image GIF et contourner la limitation de 256 octets. Cette idée a été suggérée par Marc, et c'est brillant !
Au final, les limitations actuelles du GIF pour les collisions MD5 instantanées sont :
gifsicle --use-colormap webUn raccourci facile pour normaliser des images GIF fixes est d'en faire des images d'animation de la même image, ensuite nous pouvons utiliser un script pour réutiliser ou calculer des blocs FastColl afin de créer une paire de fichiers qui affiche chacun d'eux.
Exemples :
⟷
2 GIF en collision MD5 - images de KidMoGraph
Voici un enregistrement de toute l'opération.
Spécifications GZIP v4.3 : RFC 1952 (1996).
1F 8B. Si la signature ne correspond pas, l'analyse s'arrête, ce qui peut être utilisé pour forcer l'arrêt de l'analyse entre deux charges utiles, mais cela déclenchera certains avertissements qui pourraient poser problème. Une autre stratégie consiste à ajouter un membre vide supplémentaire à la fin du fichier et à faire en sorte que l'analyse des deux charges utiles se termine là - sur le membre ou sur son corps.filename et le file comment facultatifs sont terminés par un octet nul, tandis que le Extra field est défini sur 16 bits, donc exploitable. Il est constitué d'un ou plusieurs sous-champs, avec un ID et sa propre sous-longueur, mais les sous-champs ne sont pas obligatoires - très peu sont officiellement définis.Par conséquent, un membre gzip vide avec un champ supplémentaire est un hôte parasite parfait.
Si le fichier principal est trop gros pour tenir dans un champ supplémentaire, son flux non compressé peut être divisé en fichiers plus petits jusqu'à ce qu'ils tiennent tous dans des champs supplémentaires.
Après l'en-tête d'un membre viennent son corps compressé, son CRC32 et sa taille non compressée (non vérifiés). Par conséquent, un corps de données vide avec son CRC32 nul et sa taille nulle constitue une post-enveloppe générique, qui peut même être partagée par différents en-têtes de membres.
Diverses implémentations se fient à la taille non compressée du dernier membre plutôt qu'à la somme de tous les membres. Ainsi, nos fichiers en collision sembleront avoir une taille nulle, car ces fichiers se terminent par un membre vide utilisé comme trampoline.
Voici un script pour générer des collisions MD5 instantanées de deux fichiers GZip. Il passe la plupart de son temps à décompresser et recompresser les données si les fichiers d'entrée sont volumineux - les préfixes de collision sont précalculés. Diviser les membres sans décompresser n'est pas possible car le CRC32 non compressé doit être calculé.
Un .tar.gz n'est rien d'autre que l'archive gzip d'une archive tar. Cela fonctionnera très bien avec un tar compressé par gzip, contrairement à tar lui-même.
Exemples : collision1.tar.gz (Pacome) ⟷ collision2.tar.gz (Reg)
Le Portable Executable a une structure particulière :
La stratégie est donc :
DOS/Collisions/Header1/Header2. Il suffit d'appliquer un delta aux offsets des deux tables de sections.Cela signifie qu'il est possible de faire entrer en collision instantanément n'importe quelle paire d'exécutables PE. Même s'ils utilisent des sous-systèmes ou des architectures différents.
Bien que les collisions d'exécutables soient généralement triviales via n'importe quel chargeur, ce type d'exploitation est ici transparent : le code est identique et chargé à la même adresse.
Exemples : tweakPNG.exe (GUI) ⟷ fastcoll.exe (CLI)
Voici un script pour générer des collisions MD5 instantanées d'exécutables Windows.
Le conteneur de ce format est une séquence de blocs Length Type Value appelés Atomes.
La longueur est un entier 32 bits big-endian et couvre elle-même, le type et la valeur, donc la longueur normale minimale est de 8
(le type est une chaîne de 4 caractères ASCII).
Si la longueur est nulle, l'atome occupe le reste du fichier - comme les atomes jp2c dans les fichiers JP2.
Si elle vaut 1, le type est suivi d'une longueur 64 bits, transformant l'atome en Type Length Value, ce qui le rend compatible avec d'autres collisions comme Shattered.
Certains atomes contiennent d'autres atomes : dans ce cas, on les appelle des boîtes. C'est pourquoi cette structure autrement sans nom est appelée "atom/box".
Ce format "atom/box" utilisé dans MP4 est en réalité un dérivé d'Apple Quicktime, et est utilisé par de nombreux autres formats (JP2, HEIF, F4V).
Le premier type d'atome est généralement ftyp, ce qui permet de différencier le format de fichier réel.
Le format est assez permissif :
il suffit d'enchaîner des atomes free, d'abuser de la longueur de l'un d'eux avec UniColl, puis de sauter par-dessus la première charge utile.
Pour les fichiers MP4, la seule chose à ajouter est d'ajuster les tables stco (Sample Table - Chunk Offsets) ou co64 (l'équivalent 64 bits), car ce sont des offsets absolus (!) pointant vers les données vidéo mdat - et ils sont réellement vérifiés !
Cela donne un script qui fait entrer en collision instantanément n'importe quelle vidéo arbitraire - et comme mentionné, cela peut fonctionner sur d'autres formats que MP4.

Exemples (vidéos de KidMoGraph) :
longueurs 32b (standard) collision1.mp4 ⟷ collision2.mp4
⟷
longueurs 64b collisionl1.mp4 ⟷ collisionl2.mp4
⟷
Notez que certains lecteurs (OS X, Safari, FireFox) n'autorisent pas un fichier commençant par un atome qui n'est pas ftyp.
Dans ce cas, le préfixe doit couvrir cela, et il n'est pas si générique, mais à part ça, c'est la même stratégie - seulement limitée à un seul type de fichier.
Les fichiers JPEG2000 commencent généralement par la structure Atom/Box comme MP4,
puis le dernier atome jp2c s'étend typiquement jusqu'à la fin du fichier (longueur nulle),
puis à partir de ce point, la structure JFIF est suivie, comme pour JPEG (commençant par FF 4F comme marqueur de segment).
La forme pure-JFIF est également tolérée, auquel cas la collision est comme pour JPEG : compatible Shattered, mais avec des commentaires limités à 64Kb.
En revanche, si vous manipulez des fichiers JPEG2000 avec la structure Atom/Box, vous n'avez pas cette limitation.
Comme mentionné précédemment, si vous essayez de faire entrer en collision cette structure et
s'il y a plus de restrictions - par exemple, commencer par un atome free n'est pas toléré par certains formats -
alors vous pouvez calculer d'autres paires de préfixes UniColl spécifiques à ce format :
JPEG2000 semble exiger un atome 'jP ' en premier avant le ftyp habituel,
mais à part cela, c'est la seule restriction : il n'y a pas besoin de déplacer quoi que ce soit.
Le script qui en résulte est donc encore plus simple !

Exemples : collision1.jp2 ⟷ collision2.jp2
à propos de Shattered
L'exploitation de Shattered n'était pas une astuce PDF, mais une astuce JPG dans un PDF.
Elle permettait seulement à un PDF de contenir un objet compressé en JPG qui pouvait avoir deux contenus différents. Les deux PDF devaient par ailleurs être totalement identiques.
Notez que les documents peuvent être tout à fait normaux et peuvent simplement découper le JPG en collision et l'afficher à différents endroits, comme dans des documents multi-pages.
Exemples : l'article Shattered, modifié ⟷ l'article Shattered, original
l'article Shattered utilisant un JPG en collision à deux endroits
Collisions PDF avec MD5
Avec MD5 (et d'autres modèles de collision), nous pouvons réaliser des collisions PDF au niveau du document, sans aucune restriction sur l'un ou l'autre fichier !
Le PDF a une structure très différente des autres formats de fichiers. Il utilise des numéros d'objet et des références pour définir une arborescence. L'ensemble du document dépend de l'élément Root.
Ce PDF (valide)``` text %PDF-1. 1 0 obj<</Pages 2 0 R>>endobj 2 0 obj<</Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Parent 2 0 R>>endobj trailer <</Root 1 0 R>>
est équivalent à :``` text
%PDF-1.
11 0 obj<</Pages 12 0 R>>endobj
12 0 obj<</Kids[13 0 R]/Count 1>>endobj
13 0 obj<</Parent 12 0 R>>endobj
trailer <</Root 11 0 R>>
Astuces :
XREF.Il est donc possible de stocker deux arbres de documents dans le même fichier. Il suffit que l'objet racine référence l'une ou l'autre des racines des deux documents.
Nous avons donc simplement besoin de prendre deux documents,
renuméroter les objets et les références afin qu'il n'y ait aucun chevauchement,
concevoir une collision pour que le numéro d'objet référencé comme objet racine puisse être modifié tout en conservant la même valeur de hachage,
ce qui est un cas idéal pour UniColl avec N=1, et ajuster la table XREF en conséquence.
De cette manière, nous pouvons provoquer en toute sécurité la collision de n'importe quelle paire de PDF, quels que soient les numéros de page, les dimensions, les images...
commentaires
Un PDF peut stocker des données étrangères de deux manières :
\r et \n).
Cela peut être utilisé à l'intérieur d'un objet dictionnaire, pour modifier par exemple une référence d'objet, via UniColl.
Il s'agit donc d'un objet PDF valide même s'il contient des blocs de collision binaires - il suffit de réessayer jusqu'à ce qu'il n'y ait plus de caractères de saut de ligne : ```
1 0 obj
<< /Type /Catalog /MD5_is /REALLY_dead_now__ /Pages 2 0 R
%¥┬•σe╕█╙X₧_~π▌╒εX∟■φe♦%τ8╞■[...]p╛╬ûFZ»‼v◘Åp↑╝%▓% ▼σφj╔◄dZ▀c²aU≤╨╩[├└─yNΓ5╔+▀╪yδ☻ß⌐░¼à(☺z₧
endobj
texte en collision
Le premier cas permet de souligner la beauté d'UniColl, une collision où les différences sont prévisibles, pour que vous puissiez écrire de la poésie sur des données en collision - merci Jurph!
Plutôt que de modifier la structure du document et de tromper les analyseurs, nous allons simplement utiliser des blocs de collision directement pour produire directement du texte, avec une lecture alternative!``` V V Now he hash MD5, Now he hath MD5, No enemy cares! No enemy dares! Only he gave Only he have the shards. the shares. Can’t be owned & Can’t be pwned & his true gold, his true hold, like One Frail, like One Grail, sound as fold. sound as gold. ^ ^
Exemples : [poeMD5 A](https://github.com/decalage2/collisions/blob/HEAD/examples/poeMD5_A.pdf) ⟷ [poeMD5 B](https://github.com/decalage2/collisions/blob/HEAD/examples/poeMD5_B.pdf)
*Une véritable création artistique cryptographique :)*
(Note : j'ai fait une erreur avec la compatibilité Adobe, mais c'est de ma faute, pas celle d'UniColl)
**Structure du document en collision**
Que vous utilisiez UniColl comme commentaire en ligne ou comme préfixe choisi dans un objet de flux factice, la stratégie est similaire :
mélangez les numéros d'objets, puis faites pointer l'objet Root vers différents objets, donc contrairement à Shattered, cela signifie une collision instantanée de n'importe quelle paire de PDF, au niveau du document.
Une astuce utile est que la sortie de [`mutool clean`](https://mupdf.com/docs/manual-mutool-clean.html) est prévisible de manière fiable,
donc elle peut être utilisée pour normaliser les PDF en entrée et réparer votre PDF fusionné tout en conservant les parties importantes du fichier non modifiées.
MuTool ne supprime pas les clés/valeurs factices - sauf si on le lui demande, et les conserve dans le même ordre,
donc utiliser de fausses entrées de dictionnaire telles que `/MD5_is /REALLY_dead_now__` est parfait pour aligner les choses de manière prévisible sans avoir besoin d'un autre type de commentaires.
Cependant, il ne conserve pas les commentaires dans les dictionnaires (donc pas d'astuce de commentaire en ligne).
Un moyen simple d'effectuer l'opération de mélange d'objets sans tracas consiste simplement à fusionner les deux fichiers PDF
via `mutool merge`, puis à diviser l'objet `/Pages` en deux.
Pour faire de la place pour cet objet, il suffit de fusionner un PDF factice devant les deux documents.
Éventuellement, créez une fausse référence au tableau orphelin
pour empêcher le ramasse-miettes de supprimer le deuxième ensemble de pages.
**Exemple** :
avec ce [script](https://github.com/decalage2/collisions/blob/HEAD/scripts/pdf.py),
il faut [moins d'une seconde](https://github.com/decalage2/collisions/blob/HEAD/examples/pdf.log) pour faire entrer en collision les deux articles PDF publics comme Spectre et Meltdown :
Exemples : [spectre.pdf](https://github.com/decalage2/collisions/blob/HEAD/examples/collision1.pdf) ⟷ [meltdown.pdf](https://github.com/decalage2/collisions/blob/HEAD/examples/collision2.pdf)
Extension possible : enchaîner les blocs UniColl pour conserver également les paires des différents [objets non critiques](https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf#page=81)
qui peuvent être référencés dans l'objet Root - tels que `Outlines`, `Names`, `AcroForm` et Actions supplémentaires (`AA`) - dans les fichiers source d'origine.
**en PDFLaTeX**
Les techniques précédentes fonctionnent avec une simple paire de fichiers PDF,
mais il est également possible de le faire directement à partir des sources TeX
via [les opérateurs PDFTeX spécifiques](http://texdoc.net/texmf-dist/doc/pdftex/manual/pdftex-a.pdf).
Vous pouvez définir des objets directement - y compris des clés et valeurs factices pour les alignements - et définir des objets vides pour réserver certains emplacements d'objets en incluant ceci au tout début de vos sources TeX :``` latex
% set PDF version low to prevent stream XREF
\pdfminorversion=3
\begingroup
% disable compression to keep alignments
\pdfcompresslevel=0\relax
\immediate
\pdfobj{<<
/Type /Catalog
% cool alignment padding
/MD5_is /REALLY_dead_now__
% the first reference number should be on offset 0x49,
% so the '2' object number will be changed to '3' by UniColl
/Pages 2 0 R
% now padding so that the collision blocks (ends at 0xC0) are covered
/0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
% with an extra character to be replaced by a return char
/0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0
>>}
% the original catalog of the shifted doc
\immediate\pdfobj{<</Type/Pages/Count 1/Kids[8 0 R]>>}
% the original catalog of the host doc
\immediate\pdfobj{<</Type/Pages/Count 1/Kids[33 0 R]>>}
% now we need to reserve PDF Objects so that there is no overlap
\newcount\objcount
% the host size (+3 for spare object slots) - 1
% putting a higher margin will just work, and XREF can have huge gaps
\objcount=25
\loop
\message{\the\objcount}
\advance \objcount -1
\immediate\pdfobj{<<>>} % just an empty object
\ifnum \objcount>0
\repeat
\endgroup
N'oubliez pas de normaliser la sortie PDFLaTeX - avec mutool par exemple - si nécessaire :
PDFLaTeX est difficile à rendre reproductible d'une distribution à l'autre - vous pouvez même vouloir fixer l'heure à l'exécution pour obtenir le hash exact si nécessaire.
Vous pourriez vous attendre à ce que le JPG ne soit que des images, mais dans un PDF et certains lecteurs PDF (hors navigateurs, comme Evince et Adobe Reader), il peut être utilisé comme contenu de page, tout comme n'importe quel autre objet intégré, lui-même embarqué dans une image JPEG.
Pour stocker les données JPEG sans perte, stockez-les en niveaux de gris à 100 %, puis utilisez soit une image d'une seule ligne/colonne, soit répétez la ligne de données 8 fois (car les blocs JPEG sont en 8x8), et vos données sont stockées sans perte et référencées par les pages PDF.
Exemples de deux PDF en collision SHA-1 via des données de page JPEG (une image en niveaux de gris restituant des couleurs) comme contenu de page vectoriel :
2 PDFs en collision SHA-1 avec des données d'image stockées au format JPG
Il est possible de référencer deux fois le JPG en collision : comme contenu de page, sans perte, et comme image avec perte à afficher. Là encore, l'image à afficher est en niveaux de gris, mais le contenu de la page peut restituer certaines couleurs via les opérateurs PDF.
Le haut de l'image montre le contenu de la page répété 8 fois.
Exemples de deux PDF en collision SHA-1 via un JPEG utilisé comme données de page et comme image à afficher :
Skulls & Crossbones ⟷ Golden Axe
2 PDFs en collision SHA-1 avec un JPG utilisé comme image et comme contenu de page
En bref Il n'existe pas de collision générique réutilisable pour ZIP, mais il y en a pour les formats basés sur ZIP. Il devrait être possible de faire entrer deux fichiers en collision en 2h.core (36 fois plus rapide que chosen-prefix)
Les archives ZIP sont un sandwich de 3 couches (au moins).
D'abord vient le contenu des fichiers (séquence de structures Local File Header, une par fichier ou répertoire archivé),
puis un index (encore une fois, une séquence de Central Directory),
puis une structure unique qui pointe vers cet index (End Of Central Directory).
L'ordre de ces couches ne peut pas être modifié. Certains parseurs n'ont besoin que de la structure du contenu des fichiers, mais ce n'est pas une façon correcte d'analyser et cela peut être abusé.
En raison de cet ordre imposé, il n'existe pas de préfixe générique qui puisse aider pour une collision quelconque.
approche non générique
Une autre approche pourrait consister à simplement fusionner les deux archives, avec leurs couches fusionnées, et à utiliser UniColl - mais avec N=2, ce qui introduit une différence sur le 4ème octet - pour détruire la signature magique du End of Central Directory.
Cela signifie qu'on pourrait faire entrer en collision deux ZIP arbitraires avec un seul UniColl et 24 octets de préfixe défini.
Un End of Central Directory typique, qui fait 22 octets si le commentaire est vide :```
00: 504b 0506 0000 0000 0000 0000 0000 0000 PK..............
10: 0000 0000 0000 ......
Si nous utilisons ceci comme préfixe (compléter le préfixe à 16 bits) pour UniColl et `N=2`, la différence se situe sur le 4ème octet, détruisant la valeur magique `.P .K 05 06` en la changeant de manière prévisible en `.P .K 05 86`.```
00: 504b 0506 0000 0000 0000 0000 0000 0000 PK..............
10: 0000 0000 0000 2121 eb66 cf9d db01 83bb ......!!.f......
20: 2888 4c41 e345 7d07 1634 5d4a 3b61 89a0 (.LA.E}..4]J;a..
30: 0029 94af 4168 2517 0bbc b841 cbf2 9587 .)..Ah%....A....
40: e438 0043 6390 279d 7c9e a01e e476 4c36 .8.Cc.'.|....vL6
50: 527f b1f4 653e d866 f98d 7278 5324 0bd5 R...e>.f..rxS$..
60: b31d ef6d d5d6 1163 5a2e a8a5 21bf eab4 ...m...cZ...!...
70: c59c 028e a913 f6b7 0036 c93f 5092 a628 .........6.?P..(
I'm ready to translate the Markdown content. However, I notice that the input chunk appears to be empty — no text was provided after "INPUT:".
Please provide the chunk content you'd like translated, and I'll proceed with the translation from English to French following all the specified rules.``` 00: 504b 0586 0000 0000 0000 0000 0000 0000 PK.............. 10: 0000 0000 0000 2121 eb66 cf1d db01 83bb ......!!.f...... 20: 2888 4c41 e345 7d07 1634 5d4a 3b61 89a0 (.LA.E}..4]J;a.. 30: 0029 94af 4168 251f 0bbc b841 cbf2 9587 .)..Ah%....A.... 40: e438 00c3 6390 279d 7c9e a01e e476 4c36 .8..c.'.|....vL6 50: 527f b1f4 653e d866 f98d 72f8 5324 0bd5 R...e>.f..r.S$.. 60: b31d ef6d d5d6 1163 5a2e a8a5 21bf eab4 ...m...cZ...!... 70: c59c 028e a913 f6af 0036 c93f 5092 a628 .........6.?P..(
Ce n'est pas générique du tout, mais beaucoup plus rapide qu'une collision de préfixe choisi :```
real 12m23.993s
user 112m24.072s
sys 2m0.194s
Un problème est que certains parseurs analysent encore les fichiers ZIP à l'envers alors qu'ils devraient être analysés de bas en haut:
un moyen de s'assurer que les deux fichiers sont correctement analysés est d'enchaîner deux blocs UniColl,
pour activer/désactiver chaque End of Central Directory.
Pour éviter que les parseurs ZIP ne se plaignent de l'espace inutilisé,
on peut abuser des Extra Fields,
des commentaires de fichier dans le Central Directory et des commentaires d'archive dans le End of Central Directory.

Exemple: voici une source assembleur qui décrit la structure d'un double ZIP, qui peut héberger deux fichiers d'archive différents.
Après deux calculs Unicoll, cela donne les deux fichiers en collision: collision1.zip ⟷ collision2.zip
Même si le format Zip lui-même ne peut pas être exploité génériquement comme Gzip, certains formats reposant sur Zip peuvent être exploités génériquement dans des archives Zip avec une structure prédéfinie. Certaines précautions doivent être prises pour rendre la collision Zip générique.
Certains formats sont constitués de plusieurs fichiers stockés dans une archive Zip et reposent sur un fichier racine avec un nom de fichier fixe qui pointe vers d'autres fichiers de l'archive. Beaucoup d'entre eux utilisent du XML ou du texte pour le fichier racine, et stockent les autres fichiers tels quels.
Idée : faire coexister 2 ensembles de fichiers dans la même archive, et pointer vers l'un ou l'autre ensemble. Une racine générique peut être stockée d'abord au début du fichier, mais les blocs de collision sont stockés hors du contenu du fichier, dans l'archive (car les collisions ont une entropie très élevée, il est impossible d'exploiter des fichiers XML ou uniquement ASCII avec des collisions).
Étapes:
Placer 2 ensembles de fichiers provenant de 2 origines dans la même archive - c'est-à-dire dans des sous-répertoires différents.
Modifier le fichier racine pour pointer alternativement vers chaque ensemble.
Comme l'horodatage, la longueur et le CRC du fichier racine sont stockés à la fois dans le Local File Header - avant le contenu du fichier - et dans le Central Directory - après le contenu du fichier - ces valeurs ne devraient pas changer entre les deux versions des fichiers.
Central Directory, cette copie de la valeur pourrait être ignorée par le parseur, mais forger un CRC32 à une valeur constante est utile pour éviter entièrement le problème.
Forger le CRC en ajoutant 4 octets aléatoires ne suffira probablement pas, car ces fichiers racines sont généralement en XML ou en texte avec des syntaxes strictes, ils deviendraient donc invalides.
CrcHack aide grandement à forger des CRC avec des bits arbitraires et sans force brute, en garantissant que le fichier de sortie est en ASCII et que les bits modifiés restent dans un commentaire.Utiliser le extra field d'un fichier factice supplémentaire -- même vide -- dans l'archive après le fichier racine est une manière élégante de stocker les blocs de collision Hashclash: ainsi, l'archive Zip conserve une structure standard et peut être facilement manipulée ensuite, même avec des outils standards.
Les Extra Fields n'ont pas de CRC32, et leur longueur de 16 bits est déclarée dans les en-têtes précédents. Ils ont leur propre format interne ID:2 Size:2 Data mais il est généralement ignoré, et ils sont présents à la fois dans le Local File Header et dans le Central Directory, mais ils peuvent être absents du Central Directory pour conserver un suffixe identique après les blocs de collision.
La présence du fichier supplémentaire qui couvre les blocs de collision dans son extra field peut devoir être déclarée dans la structure du format, comme dans le fichier [Content_Types].xml d'un document OOXML. D'autres fichiers XML du suffixe peuvent devoir être modifiés, car certains formats exigent l'utilisation de chemins absolus.
Voici la structure globale de l'exploit générique pour un format spécifique basé sur Zip:``` [Root file] (with constant CRC32)
[Dummy file] (with collision blocks in the extra field)
[...] <- rest of the archive, with 2 documents merged
Ainsi, en prédéfinissant le contenu du fichier racine et en forgeant des CRC32 ASCII, on peut calculer une collision Hashclash générique réutilisable pour un format basé sur ZIP spécifique.
### Résumé des exigences
- deux préfixes ou plus
- un ou plusieurs types de fichiers (les polyglottes fonctionnent sans problème)
- un fichier racine XML avec un nom de fichier, une longueur de fichier et un CRC fixes : cette information est présente deux fois, avant et après les blocs de collision
- le contenu est un XML arbitraire
- le remplissage est possible, même via un commentaire XML, pour atteindre la même longueur.
- le CRC peut être défini (via CrcHack) pour chaque contenu.
- les deux ensembles de fichiers coexistent dans le suffixe, probablement dans des répertoires différents. Certains outils codent en dur le chemin, ce qui peut réduire la compatibilité.
- un fichier XML *Content type* peut devoir être fusionné pour couvrir tous les fichiers, pris en charge ou non (blocs de collision et document alternatif)
### Exemples
#### CRC32
Un commentaire XML minimal (uniquement ASCII) avec un CRC32 forgé (calcul instantané) avec CrcHack.``` bash
echo "<!--ABCDEF-->" | crchack -b 4.0:+.8*6:1 -b 4.1:+.8*6:1 -b 4.2:+.8*6:1 -b 4.3:+.8*6:1 -b 4.4:+.8*6:1 -b 4.5:+.8*5:1 - 0xdeadf00d
<!--X{]EZF-->
Un autre exemple où vous ajustez le CRC avec la casse d'un message alphabétique.```bash echo "" | crchack.exe -b 4:+.8*32:.8 - 0xcafebabe
#### Collisions
[zInsider](https://github.com/decalage2/collisions/blob/HEAD/scripts/zinsider.py) est un script permettant de générer instantanément des collisions MD5 de paires de documents arbitraires à l'aide de ces formats ZIP+XML :
- Office Open XML : docx / pptx / xlsx
- Open Container Format : epub
- Open Packaging Conventions :
- format de fabrication 3D : 3mf
- XML Paper Specification : xps / oxps
Pour générer vos propres préfixes de collision, [voici un script](https://github.com/decalage2/collisions/blob/HEAD/scripts/makezip.py) pour générer une paire de zips racines.
Après avoir calculé les collisions, utilisez [cet autre script](https://github.com/decalage2/collisions/blob/HEAD/scripts/extendzip.py) pour combiner cette paire de racines avec un suffixe commun.
Quelques PoC de collisions :
- Office Open XML : Excel ([1](https://github.com/decalage2/collisions/blob/HEAD/examples/free/md5-1.xls) - [2](https://github.com/decalage2/collisions/blob/HEAD/examples/free/md5-2.xls)), Powerpoint ([1](https://github.com/decalage2/collisions/blob/HEAD/examples/free/md5-1.pptx) - [2](https://github.com/decalage2/collisions/blob/HEAD/examples/free/md5-2.pptx)), Word ([1](https://github.com/decalage2/collisions/blob/HEAD/examples/free/md5-1.docx) - [2](https://github.com/decalage2/collisions/blob/HEAD/examples/free/md5-2.docx)).
- Open Container Format : Epub ([1](https://github.com/decalage2/collisions/blob/HEAD/examples/collision-1.epub) - [2](https://github.com/decalage2/collisions/blob/HEAD/examples/collision-2.epub)).
- Open Packaging Conventions : 3MF ([1](https://github.com/decalage2/collisions/blob/HEAD/examples/collision-1.3mf) - [2](https://github.com/decalage2/collisions/blob/HEAD/examples/collision-2.3mf)), XPS ([1](https://github.com/decalage2/collisions/blob/HEAD/examples/collision-1.xps) - [2](https://github.com/decalage2/collisions/blob/HEAD/examples/collision-2.xps)).
Certains formats à fichiers multiples basés sur Zip ne peuvent pas être exploités de manière générique :
- Quake PK3 : un zip de fichiers sans racine spécifique.
- Open Document Format : le fichier `META-INF/manifest.xml` doit mentionner tous les autres fichiers, il ne peut donc pas être générique.
- APK, JAR, XPI : le fichier `META-INF/MANIFEST.mf` doit également mentionner tous les autres fichiers, avec ses hashs.
Merci à [Philippe Lagadec](https://twitter.com/decalage2) pour son aide sur les formats de fichiers Office !
## Stratégies inhabituelles
Les collisions concernent généralement deux fichiers valides du même type.
### MultiColls : chaîne de collisions multiples
Rien n'empêche d'enchaîner plusieurs blocs de collision,
et d'avoir plus de deux contenus avec la même valeur de hash.
Un exemple en est les *hashquines* — qui affichent leur propre valeur MD5.
Le fichier [PoCGTFO 14](https://github.com/angea/pocorgtfo#0x14) contient 609 collisions FastColl,
pour ce faire à travers deux types de fichiers dans le même fichier.
### Validité
Une stratégie différente consisterait à tuer le type de fichier pour contourner l'analyse en tant que fichier corrompu.
Il suffit de réécrire la signature magique.
L'ajout d'un format qui n'a pas besoin d'être à l'offset 0 (archive, comme ZIP/RAR/...) à la suite des deux fichiers (valides ou invalides) révélerait un autre type de fichier.
Cela permet des collisions polyglottes sans utiliser de collision à préfixe choisi :
1. utiliser UniColl pour activer ou désactiver une signature magique, par exemple un PNG :
2. ajouter une archive ZIP
Bien que techniquement les deux fichiers soient des ZIP valides, comme la plupart des analyseurs renvoient le premier type de fichier trouvé et commencent leur analyse à l'offset 0, ils verront un type de fichier différent.
Exemples :
⟷ [invalide](https://github.com/decalage2/collisions/blob/HEAD/examples/png-invalid.png)
### PolyColls : collisions de différents types de fichiers
Il est également possible d'avoir les deux côtés d'une collision avec des types différents pour éveiller moins de soupçons :
Scénario d'attaque :
1. envoyer `holiday.jpg`
2. le faire mettre sur liste blanche
3. envoyer `evil.exe`, qui a le même MD5.
Dans ces cas, une collision à préfixe choisi est requise
si les deux formats de fichiers doivent démarrer à l'offset 0.
Quelques exemples de dispositions polycoll :

*Polycoll PDF/JPG*

*Polycoll PE/PNG*
#### PE - JPG
Comme un en-tête PE est généralement plus petit que 0x500 octets, il s'intègre parfaitement dans un commentaire JPG :
1. commencer par les en-têtes DOS/JPG
2. le commentaire JPEG saute par-dessus l'en-tête PE
3. placer l'image JPG complète
4. placer toutes les spécifications PE
Encore une fois, la collision est [instantanée](https://github.com/decalage2/collisions/blob/HEAD/scripts/jpgpe.py)
Exemples : [fastcoll.exe](https://github.com/decalage2/collisions/blob/HEAD/examples/jpg-pe.exe) ⟷ [Marc.jpg](https://github.com/decalage2/collisions/blob/HEAD/examples/jpg-pe.jpg)
#### PDF - PE
Fusionner un PDF avec un fichier factice à l'aide de `mutool` est un bon moyen générique de réorganiser les objets
et d'obtenir les deux premiers objets jetables (page factice et contenu),
ce qui est parfait pour héberger un objet `stream` de longueur inconnue en `1 0`,
et dont la longueur est référencée plus loin (après les blocs de collision) dans le second objet.
Le seul problème est que `mutool` intègre toujours la longueur — et supprime la référence de longueur —,
il faut donc la réinsérer dans le PDF à la place de la valeur,
mais la plupart des références `2 0 R` seront plus petites que les longueurs codées en dur.
Heureusement, cela peut être corrigé sans modifier aucun offset d'objet,
donc pas besoin de corriger le XREF.
Voici un [script](https://github.com/decalage2/collisions/blob/HEAD/scripts/pdfpe.py) pour, par exemple, faire instantanément entrer en collision un visualiseur PDF ([Sumatra](https://www.sumatrapdfreader.org/free-pdf-reader.html) est léger et autonome) et un document PDF :
Exemples : [Poster.pdf](https://github.com/decalage2/collisions/blob/HEAD/examples/pepdf.pdf) ⟷ [Sumatra.exe](https://github.com/decalage2/collisions/blob/HEAD/examples/pepdf.exe)

*un visualiseur PDF affichant un PDF (qui affiche lui-même un PDF) avec le même MD5*
#### PDF - PNG
De même, il est possible de faire entrer en collision par exemple des fichiers PDF et PNG arbitraires sans restriction d'aucun côté. C'est instantané, réutilisable et générique.
Exemples : [Hello.pdf](https://github.com/decalage2/collisions/blob/HEAD/examples/png-pdf.pdf) ⟷ [1x1.png](https://github.com/decalage2/collisions/blob/HEAD/examples/png-pdf.png)
### PileUps (multi-collision)
Les collisions cryptographiques ne se limitent pas à deux fichiers !
Comme démontré dans l'expérience [Nostradamus](https://www.win.tue.nl/hashclash/Nostradamus/) en 2008,
l'enchaînement de collisions permet de faire entrer plus de deux fichiers en collision.
Les premières collisions peuvent être identiques ou à préfixe choisi, les suivantes doivent être à préfixe choisi.
Vous pouvez les appeler multi-collisions, je préfère *pileups* — c'est plus court :)
#### PE - PNG - MP4 - PDF
En combinant toutes les connaissances acquises précédemment,
j'ai utilisé 3 collisions à préfixe choisi pour créer 4 préfixes différents pour différents types de fichiers :
document (PDF), vidéo (MP4), exécutable (PE) et image (PNG).

*schéma d'un pileup PE/PNG/MP4/PDF*
Ce script est générique et instantané :

Exemples : [commodore.pdf](https://github.com/decalage2/collisions/blob/HEAD/examples/pileup.pdf) ⟷ [diagram.png](https://github.com/decalage2/collisions/blob/HEAD/examples/pileup.png) ⟷ [kidmo.mp4](https://github.com/decalage2/collisions/blob/HEAD/examples/pileup.mp4) ⟷ [sumatra18.exe](https://github.com/decalage2/collisions/blob/HEAD/examples/pileup.exe)
Comme vous ne pouvez distribuer qu'un seul fichier
et qu'il est impossible de deviner les autres valeurs de préfixe à partir de celui-ci,
une solution consiste à intégrer tous les préfixes de la collision dans du code JavaScript
et à les insérer dans vos PoC,
transformant vos fichiers en [polyglottes HTML](https://github.com/decalage2/collisions/blob/HEAD/examples/polyglot.html) pour partager facilement les fichiers en collision associés.
Le [numéro 19](https://github.com/angea/pocorgtfo#0x19) de « PoC or GTFO » est un tel pileup **et** polyglotte,
combinant un document de 80 pages généré avec PDFLaTeX, un visualiseur PDF pour Windows,
un schéma PNG et une courte vidéo MP4 de « collision » par [KidMoGraph](https://www.kidmograph.com/)
avec une charge utile HTML pour générer les autres fichiers à partir de la version PDF
(et aussi une archive ZIP) :
Merci à Rafał Hirsz pour son aide permanente sur JavaScript.
## Cas d'utilisation
Mieux vaut abandonner complètement MD5, car l'introspection des fichiers est tout simplement trop longue et trop risquée !
### Il faut tous les faire collisionner !
Une autre utilisation des collisions instantanées, réutilisables et génériques serait de cacher n'importe quel fichier d'un type donné — disons PNG — derrière des fichiers factices (ou le même fichier à chaque fois) — ce qui consiste en fait simplement à le concaténer au même préfixe après avoir retiré la signature — vous pourriez même le faire au niveau de la bibliothèque !
D'un point de vue strictement analytique,
tous vos fichiers afficheront le même contenu,
et les images malveillantes seraient révélées comme un fichier ayant le même MD5 que ceux précédemment collectés.
Prenons deux fichiers :
⟷
et faisons-les entrer en collision avec le même PNG.
Ils affichent désormais la même image factice, et ils sont absolument identiques jusqu'à la 2e image au niveau du fichier !
⟷
Leur charge utile malveillante est cachée derrière un fichier ayant le même MD5, respectivement.
### Fichiers compromettants
Un autre cas d'utilisation des collisions est de cacher quelque chose de compromettant dans quelque chose d'innocent,
mais désirable : si la seule chose pour recueillir des preuves est de comparer des hashs faibles,
alors vous ne pouvez pas nier que vous n'avez pas l'autre fichier (affichant un contenu compromettant mais cachant un contenu innocent).
Les logiciels se concentrent généralement sur l'analyse (rapide), pas sur une analyse détaillée des fichiers.
*une image montrant différents aperçus sous différents onglets d'EnCase Forensic*
## Échecs
Tous les formats ne peuvent pas avoir de préfixes génériques réutilisables :
si une sorte de conteneur de données ne peut pas être insérée entre la signature magique
et les en-têtes standard, critiques et spécifiques à chaque fichier,
alors les collisions génériques ne sont pas possibles.
Bien sûr, on pourrait toujours transformer les anciens fichiers en un nouveau,
et même utiliser du code pour bifurquer vers deux charges utiles différentes,
mais cela ressemble plus à du portage de charges utiles qu'à une collision de structures de fichiers.
### ELF
L'en-tête ELF est requis à l'offset 0 et contient des informations critiques telles que 32b/64b,
l'endianness et l'ABI dès le début,
il est donc impossible d'avoir un préfixe universel puis des blocs de collision
avant des paramètres critiques spécifiques au fichier d'origine.
### Mach-O
Les fichiers Mach-O ne commencent même pas avec la même valeur magique pour 32b (`feedface`) et 64b (`feedfacf`).
Peu après, on trouve le nombre et la taille des commandes (telles que la définition de segment, symtab, version,...).
Comme pour ELF, les collisions réutilisables ne sont pas possibles.
### Java Class
Juste après la magie de départ se trouvent les versions (qui peuvent être problématiques)
mais aussi le nombre d'entrées du constant pool, qui est assez spécifique à chaque fichier,
donc pas de collisions universelles pour tous les fichiers.
Cependant, de nombreux fichiers ont encore une version commune et nous pouvons compléter le constant pool le plus court pour atteindre le compte le plus long.
D'abord, insérez un *littéral UTF8* pour aligner les informations,
puis déclarez-en un autre avec sa longueur détournée par un UniColl (la longueur est stockée sur 16 octets en big endian).
Cependant, cela nécessitera une manipulation du code car tous les index du pool seront décalés.
Des collisions MD5 instantanées et réutilisables de Java Class devraient être possibles, mais nécessitent une analyse et une modification du code.
### TAR
**TL;DR** Pas de collision réutilisable pour les fichiers TAR, pas d'autre stratégie que le préfixe choisi.
Les Tape Archives sont une séquence d'en-têtes et de contenus de fichiers concaténés, tous alignés sur 512 octets.
Il n'y a pas de structure centrale pour l'ensemble du fichier. Donc aucun en-tête global ni commentaire d'aucune sorte à détourner.
Une astuce serait de commencer un fichier factice de longueur variable, mais la longueur est toujours au même offset, ce qui n'est pas compatible avec UniColl, ce qui signifie que seules les collisions à préfixe choisi sont utiles ici.
## Résumé des exploitations
Format | Générique ? | FastColl | UniColl | Shattered | HashClash / Shambles
-------- | -------- | :------: | :-----: | --------- | :-------:
PDF | Y | | x | | x
JPG | Y (1) | | x | x (2) | x
GZ | Y | | x | | x
PNG | Y/N (3) | | x | | x
MP4 | Y (4) | | x | x (5) | x
PE | Y | | | | x
Basés sur ZIP (6) | Y | | | | x
| | | | |
GIF | N | x | | | x
ZIP | N | | x (7) | | x
| | | | |
ELF | N | | | | x
TAR | N | | | | x
Mach-O | N | | | | x
Class | N | | | | x
1. Le JPG a certaines limitations sur les données qui peuvent être améliorées dans une certaine mesure en manipulant l'encodage des scans.
2. PDF avec JPG est l'[implémentation initiale](http://shattered.io) de l'attaque Shattered, mais ce n'est qu'une pure astuce JPG dans un document PDF.
3. PNG : Safari/Preview exige que le chunk `IHDR` du PNG soit dans la première position, avant tout bloc de collision. Cela empêche un préfixe générique, auquel cas la collision est limitée à des dimensions, un espace colorimétrique, un BPP et un entrelacement spécifiques.
4. Les formats Atom/Box comme MP4 peuvent fonctionner avec le même préfixe pour différents sous-formats. Certains sous-formats comme JPEG2000 ou HEIF nécessitent un toilettage supplémentaire, mais la stratégie d'exploitation est la même — c'est juste que la collision n'est pas possible entre sous-formats, seulement avec une paire de préfixes pour un sous-format spécifique.
5. Atom/Box est compatible avec Shattered lors de l'utilisation de longueurs 64 bits.
6. Certains formats basés sur Zip peuvent être exploités de manière générique.
7. Pour une meilleure compatibilité, ZIP nécessite deux UniColl pour une archive complète, et ces collisions dépendent du contenu des deux fichiers.
## Fichiers de test
[Voici](https://github.com/decalage2/collisions/blob/HEAD/examples/free/README.md) des paires de test en collision libres (exemptes de droits d'auteur, exemptes de données personnelles).
# Références
Articles :
- 2004
- [MD5 To Be Considered Harmful Someday](https://eprint.iacr.org/2004/357.pdf) - Dan Kaminsky
- [Practical Attacks on Digital Signatures Using MD5 Message Digest](https://eprint.iacr.org/2004/356.pdf) - Ondredj Mikle
- 2005 :
- [A Note on Practical Value of Single Hash Collisions for Special File Formats](https://github.com/decalage2/collisions/blob/HEAD/papers/Illies_NIST_05.pdf) - Max Gebhardt, Georg Illies, Werner Schindler
- 2014 :
- [Malicious Hashing: Eve's Variant of SHA-1](https://malicioussha1.github.io/) - Ange Albertini, Jean-Philippe Aumasson, Maria Eichlseder, Florian Mendel, Martin Schläffer
- 2017 :
- [The first collision for full SHA-1](http://shattered.io) - Marc Stevens, Elie Bursztein, Pierre Karpman, Ange Albertini, Yarik Markov
- [Postscript that shows its own MD5](https://archive.org/stream/pocorgtfo14#page/n45/mode/1up) par Gregor "Greg" Kopf
- [A PDF That Shows Its Own MD5](https://archive.org/stream/pocorgtfo14#page/n49/mode/1up) par Mako
- [This GIF shows its own MD5!](https://archive.org/stream/pocorgtfo14#page/n52/mode/1up) par Kristoffer "spq" Janke
- [This PDF is an NES ROM that prints its own MD5 hash!](https://archive.org/stream/pocorgtfo14#page/n55/mode/1up) par Evan Sultanik, Evan Teran
- 2018 :
- [Easy SHA-1 Colliding PDFs with PDFLaTeX.](https://archive.org/stream/pocorgtfo18#page/n62/mode/1up) par Ange Albertini
- 2020 :
- [SHA-1 is a Shambles](https://eprint.iacr.org/2020/014.pdf) par Gaëtan Leurent, Thomas Peyrin
Présentations :
- 2017 Exploiting Hash Collisions at Black Alps :
- [diapositives](https://speakerdeck.com/ange/exploiting-hash-collisions)
[](https://speakerdeck.com/ange/exploiting-hash-collisions)
- [vidéo](https://www.youtube.com/watch?v=Y-oJWEYKVLA)
[](https://www.youtube.com/watch?v=Y-oJWEYKVLA)
- 2019 KILL MD5 at Pass the Salt :
- [diapositives](https://speakerdeck.com/ange/kill-md5)
[](https://speakerdeck.com/ange/kill-md5)
- [vidéo](https://passthesalt.ubicast.tv/videos/kill-md5-demystifying-hash-collisions/)
[](https://passthesalt.ubicast.tv/videos/kill-md5-demystifying-hash-collisions/)
Atelier (CollTris) :
- [diapositives](https://speakerdeck.com/ange/colltris)
[](https://speakerdeck.com/ange/colltris)
- [vidéo](https://www.youtube.com/watch?v=BcwrMnGVyBI)
[](https://www.youtube.com/watch?v=BcwrMnGVyBI)
- [supports](https://github.com/decalage2/collisions/blob/HEAD/workshop/README.md)
- sessions
- 2019/07/02 150p, Pass The Salt
- 2019/07/24 199p, Google
- 2019/08/19 208p, Google
- 2019/10/23 222p, Hack.lu
- 2019/11/07 225p, Black Alps
- 2019/12/03 229p, Google
Épreuves CTF :
- [Prudentialv2](https://ctftime.org/task/3453), du *Boston Key Party CTF 2017*.
- [HREFIN](https://ctftime.org/task/6965), du *Google CTF 2018*.
- [Looking glass](https://ctftime.org/task/9271) du *Dragon Sector Teaser CTF 2019*.
<!-- - [Not my digest](https://ctftime.org/task/4784) de *Hack.lu CTF 2017* : pas lié aux collisions, mais résolu par Marc lui-même :p -->
Un défi courant pour de telles épreuves CTF est de ne pas donner un avantage ou un handicap trop important selon la puissance de calcul à laquelle chaque joueur a accès.
# Crédits
Tout cela a été possible grâce à [Marc Stevens](https://marc-stevens.nl/research/),
non seulement pour ses contributions cryptographiques, mais aussi pour son aide et ses suggestions permanentes !
Merci également à Philippe Teuwen pour ses retours très complets sur les formats de fichiers en général.
# Conclusion
**Tuez MD5 !**
Sauf si vous vérifiez activement la présence de malformations ou de blocs de collision dans les fichiers, n'utilisez pas MD5 !
Ce n'est pas un hash cryptographique, c'est une fonction jouet !
| Prefix | = | Prefix |
|---|
| Collision A | ≠ | Collision B |
| A | = | |
| = | B |