SHA-1 is vulnerable to chosen-prefix attack, due to the construction of the SHA-1 algorithm. This means that if an attacker managed to find two different strings with the same prefix, they will be able to append arbitrary data to both data and they'd get the same SHA-1 for the resultant file.
In other words, the chosen prefix collision attack exploits the property that given two strings a and b such that SHA1(a) == SHA1(b)
, then SHA1(a + c) == SHA1(b + c)
for any a
and b
even when a != b
.
As mentioned in the shattered.io, the attack works for PDF because the PDF file format has a vulnerable structure:

To put it simply, a file format that's vulnerable to prefix attack has the structure:
- prefix, which contains a user-visible data that is referenced later in the body
- collision block, a space for arbitrary, non-user-visible data
- body, which is the same between the two collided files
A prefix collision attack works by finding a string in the collision block that will cause the prefix + collision block
of two different prefixes produce the same hash. Once you discover a colliding prefix, you can then append arbitrary bodies to the PDF and this will alter what is shown on the PDF while keeping the hashes equal. To put it simply, once you discovered a colliding prefix, you can append anything to the body, and as long as the appendages are the same, your two resultant files will also have equal hashes.
As a result, user-visible data are altered as the interpretation of the body depends on the data in the headers.
If you look at the hexdump diff of the published PDF file, the only difference between the shattered-1.pdf and shattered-2.pdf is just a very small section near the start of the file:
$ diff -u <(od -A x -t x1z -v ./shattered-1.pdf) <(od -A x -t x1z -v ./shattered-2.pdf)
--- /dev/fd/63 2017-02-28 00:27:15.844105847 +1100
+++ /dev/fd/62 2017-02-28 00:27:15.840104052 +1100
@@ -10,14 +10,14 @@
000090 72 65 61 6d 0a ff d8 ff fe 00 24 53 48 41 2d 31 >ream......$SHA-1<
0000a0 20 69 73 20 64 65 61 64 21 21 21 21 21 85 2f ec > is dead!!!!!./.<
0000b0 09 23 39 75 9c 39 b1 a1 c6 3c 4c 97 e1 ff fe 01 >.#9u.9...<L.....<
-0000c0 73 46 dc 91 66 b6 7e 11 8f 02 9a b6 21 b2 56 0f >sF..f.~.....!.V.<
-0000d0 f9 ca 67 cc a8 c7 f8 5b a8 4c 79 03 0c 2b 3d e2 >..g....[.Ly..+=.<
-0000e0 18 f8 6d b3 a9 09 01 d5 df 45 c1 4f 26 fe df b3 >..m......E.O&...<
-0000f0 dc 38 e9 6a c2 2f e7 bd 72 8f 0e 45 bc e0 46 d2 >.8.j./..r..E..F.<
-000100 3c 57 0f eb 14 13 98 bb 55 2e f5 a0 a8 2b e3 31 ><W......U....+.1<
-000110 fe a4 80 37 b8 b5 d7 1f 0e 33 2e df 93 ac 35 00 >...7.....3....5.<
-000120 eb 4d dc 0d ec c1 a8 64 79 0c 78 2c 76 21 56 60 >.M.....dy.x,v!V`<
-000130 dd 30 97 91 d0 6b d0 af 3f 98 cd a4 bc 46 29 b1 >.0...k..?....F).<
+0000c0 7f 46 dc 93 a6 b6 7e 01 3b 02 9a aa 1d b2 56 0b >.F....~.;.....V.<
+0000d0 45 ca 67 d6 88 c7 f8 4b 8c 4c 79 1f e0 2b 3d f6 >E.g....K.Ly..+=.<
+0000e0 14 f8 6d b1 69 09 01 c5 6b 45 c1 53 0a fe df b7 >..m.i...kE.S....<
+0000f0 60 38 e9 72 72 2f e7 ad 72 8f 0e 49 04 e0 46 c2 >`8.rr/..r..I..F.<
+000100 30 57 0f e9 d4 13 98 ab e1 2e f5 bc 94 2b e3 35 >0W...........+.5<
+000110 42 a4 80 2d 98 b5 d7 0f 2a 33 2e c3 7f ac 35 14 >B..-....*3....5.<
+000120 e7 4d dc 0f 2c c1 a8 74 cd 0c 78 30 5a 21 56 64 >.M..,..t..x0Z!Vd<
+000130 61 30 97 89 60 6b d0 bf 3f 98 cd a8 04 46 29 a1 >a0..`k..?....F).<
000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
The section that are different here is in the middle of an embedded JPEG image header. If you extract the JPEG image out of the PDF, you'll notice that the image has an unusual comment metadata:
$ file shattered-1-img.jpg shattered-2-img.jpg
shattered-1-img.jpg: JPEG image data, comment: "F\334\221f\266~\021\217\002\232\266!\262V\017\371\312g\314\250\307\370[\250Ly\003\014+=\342\030\370m\263\251\011\001\325\337E\301O&\376\337\263\3348\351j\302/\347\275r\217\016E\274\340F", comment: "", comment: "\377\332", comment: "\377\332", comment: "\377\332", comment: "\377\332", comment: "\377\332", comment: "\377\332", comment: "\377\332", comment: "\377\332", comment: "\377\332", comment: "\377\332", Exif Standard: [TIFF image data, big-endian, direntries=1], baseline, precision 8, 1024x740, frames 3
shattered-2-img.jpg: JPEG image data, comment: "F\334\223\246\266~\001;\002\232\252\035\262V\013E\312g\326\210\307\370K\214Ly\037\340+=\366\024\370m\261i\011\001\305kE\301S", comment: "\377\376'\364", progressive, precision 8, 1024x740, frames 3
If you pay close attention to the diff of the pdf and the jpg, you'll notice several things:
- the size of the diff is 64 bytes (= 512 bits), which corresponds to SHA-1 blocksize
- the start of the diff (0x00c0-0x0140 in the PDF) is aligned to 64 bytes boundary, note that SHA-1 works in 64-bytes chunks
- the bytes in the collision block are not entirely random, it follows the pattern two bytes same and two bytes different. For example, the first 16 bytes of each collision block:
73 46 dc 91 66 b6 7e 11 8f 02 9a b6 21 b2 56 0f
7f 46 dc 93 a6 b6 7e 01 3b 02 9a aa 1d b2 56 0b
- just before the collision block are the JPEG comment segment marker (
ff fe
), which is followed by two bytes that specifies the length of the comment segment
- the comment segment length marker (
01 73
) are split between the collision block boundary, 01
is outside the collision block boundary, while 73
and 7f
are inside the boundary
- the length of the comment segment are different (!), for shattered-1.pdf the length of the comment segment is 0x173 (= 371 bytes) while for shattered-2.pdf the length of the comment segment is 0x017f (= 383 bytes)
- which means that there are 12 bytes difference in where the comment segment ends between the two files
Let's investigate where the comment segment ends:


I've marked where the comment segment ends in the above dump. shattered-1.pdf ends the comment segment in the place marked in blue (address 0x0232), whereas shattered-2.pdf ends the comment segment in the place marked in red (address 0x023e). footnote-1
In the place marked with blue where shattered-1.pdf image's comment segment ends, we find:
1a. a comment section (ff fe
) of length 0x00fc (= 252 bytes), which jumps over shattered-2.pdf's metadata section
1b. a comment section (ff fe
) of 0x27f4 (= 10228 bytes), which jumps a chunk of shattered-2.pdf's SOS data (see below)
1*. these series of sections coincide with 2*. Within these sections, shattered-1.pdf simply have a number of comment sections to jump over shattered-2.pdf's image data.
1c. at address 0x2daa9 is the real start of shattered-1.pdf's image data
In the place marked with red where shattered-2.pdf image's comment segment ends, we find a fairly regular JPEG metadata section:
2a. a JFIF-APP0 segment marker (ff e0) of length 0x0010 (=16 bytes)
2b. a DQT (Define Quantization Table) segment (ff db
) of length 0x0043 (= 67 bytes)
2c. another DQT (Define Quantization Table) segment (ff db
) of length 0x0043 (= 67 bytes)
2d. a SOF2 (Start of Frame 2 - Progressive DCT) segment (ff c2
) of length 0x0011 (= 17 bytes)
2e. a DHT (Define Huffman Table) segment (ff c4
) of length 0x001e (= 30 bytes)
2f. another DHT (Define Huffman Table) segment (ff c4
) of length 0x001d (= 29 bytes)
2g. a comment segment (ff fe
) of length 0x0006 (= 6 bytes)
2h. an SOS (Start of Scan) header segment (ff da
) of length 0x0c (= 12 bytes), which would be immediately followed by image data (a1 fa ...
). A scan segment are terminated by a segment start marker (anything that starts with ff
, except ff 00
which is an escape sequence when the image data itself need to contain literal ff
.
2*. these series of sections coincide with 1*. Within these sections, we find a sequence of DHT and SOS sections interleaved with shattered-1.pdf image's comment segment markers to ensure that these sequences are skipped when the JPEG renderer parses shattered-1.pdf's image. I believe this chunking was needed because a comment segment can only contain up to 0xffff (= 65535 bytes) of comment data, while the image actually need to be larger than that.
2i. at address 0x02daa3, we find an EOI (End of Image) marker (ff d9
), which marks the end of shattered-2.pdf's JPEG data. Any data after this is effectively discarded when parsing shattered-2.pdf's image data. Four bytes later, is the real start of shattered-1.pdf's image data (1c).
Final notes:
- From what I can see, there is nothing in this attack that actually would have required using PDF at all. The entire attack looks like it could have been done entirely in JPEG.
- Given the right know-how, it should be possible to use the collision block with any two images. The two images don't have to be similar at all.
Footnotes:
- JPEG block length bytes counts the number of data bytes plus the length marker itself, but excludes the block identifier, which means that the start of the initial comment segment was 0x199, not 0x201.