0x00 起因
几年前在网上见过一个md5碰撞生成工具(fastcoll)
,当时也没感觉有什么用处。不过不久前看见了一篇工具作者的paper,才大概明白工具的用处:
Hash collisions and exploitations
看见知乎上也有人拿gif搞了个生成显示自己md5值图片
的工具,稍微研究了下md5格式,实现了不同图案相同md5值:
其实类似的思路还可以实现相同md5值,打印不同数据的exe(这里就不展开了,大家可以自己思考下怎么做)下载这两个exe文件:
0x01 先研究下大佬的paper
在读了一遍Hash collisions and exploitations这篇文章后,大致了解了fastcoll
这个工具的用处
fastcoll
可以根据已知的数据头,在其后面分别附加两组128字节的数据(如果没对齐,还会加上其他数据),生成两个文件,并保证两个文件的MD5值相同。
并且根据MD5的特性:在两个MD5相同的文件后,如果附加上MD5相同的数据,生成的两个文件MD5依旧相同(虽然MD5会变,但是两个文件MD5相同)。就是文章中给出的这个公式:
hash(A) = hash(B) -> hash(A + C) = hash(B + C)
根据这个结论,我们可以得到如下结论:
利用fastcoll
,可以对固定开头和固定结尾的数据,生成两组不同的数据(数据内容不可控)拼接上头和尾,分别生成两个文件,保证他们的MD5相同。
0x02 分析fastcoll生成的数据
如果是写一个exe的话,利用起来比较简单,按规则判断下内存区域的哪部分数据就好了(也就是上面举的例子)。但是因为数据内容不可控,所以gif利用起来有些困难。
不过在分析了fastcoll
生成的数据后,发现工具只会在几个区域内产生不同的数据(只是位置确定,数据内容依旧不可控),如图:
经过多次实验,发现最后一位数据,两组输出的值相差总是为0x60。可以利用这一点做些文章
0x03 分析下GIF格式
可以看一遍glib出的文章:What’s In A GIF
如果打不开上面的链接,可以看我备份的页面:What’s In A GIF backup
根据格式,我们可以利用Comment Extension
来包住fastcoll
生成的“乱码”,然后利用上最后一位字节数据。
如果我们将fastcoll
生成的数据第123位(最后一处的不同位置),数据值用x
和y
代替(x
<y
),那么大体处理方式如下:
+----+
length below | 21 | explaination below
+----+
| ef |
+----+
|lenA| <--+ A区域的长度(填充数据+123字节)
+----> +----+
| |....| <-----+可能有的0x00填充数据 (实际确实有)
| |....|
| +----+ <----------------------------------+
| | | |
| | | |
A | | | |
| | | |
| |....| | fastcoll生成的128字节碰撞数据
| |....| |
| | | |
| | | |
+----> +----+ |
|0x??| <-----+生成数据的第124位, |
+---+-------+--> +----+ 就是上面讨论过的要利用的那个字节 |
| | 4bytes| |....| 会被当作接下来的注释长度用 |
| | +--> +----+ <----------------------------------+
| x | | |
| | |mess| <-----+垃圾数据,凑数用的
| | | |
| +----------> +----+
| |0x00| <-----+注释结束字符
| +----+
| | |
| | |
| | | 实际的图片数据
| |pic | <-----+ 一张图会显示
| |data| 另一张图会忽略
y | | |
| | |
| +----+
| |0x00| <-----+ 图片结束
| +----+ <-----+
| | 21 | |
| +----+ |
| | ef | |
| +----+ |
| |lenA| | 纯属填充用的一片注释区域
| +----+ |
| |....| |
| |....| |
+--------------> +----+ <-----+
|0x00| <-----+注释结束字符
+----+
总的来说,就是一个文件会把图片数据包在注释里当注释处理,而另一个文件会把它当正常图片数据处理
0x04 开工
具体代码见https://github.com/chenxuuu/different-gif-same-md5
代码里的
md5_h
和md5_s
需要根据你是实际的图片内容进行重新生成(懒得写自动生成处理逻辑了)
根据代码生成的图片数据,需要从前半部分分割开来,删掉后面的全部数据,重新生成碰撞块数据。如图所示圈住的地方就是要去掉的部分:
然后根据生成后的开头数据,生成对应的碰撞块:
可以看到,我们需要的最后一位不同数据差值正好为128
字节,我们可以最多显示一百多字节的不同图片数据
同时数据前面还填充了一堆0x00用于对齐,这些数据在写这堆代码的时候就考虑到了,不需要再理会,我们只需要把下面的碰撞代码拎出来就行:
//碰撞用的小数组
const unsigned char md5_s[] =
{
0x14,0xba,0x1f,0x3a,0x94,0x14,0xc7,0x5b,0x6e,0xb1,0x32,0xc3,0xbc,0x6f,0xb8,0x13,
0x58,0x9b,0xa0,0x44,0x73,0x42,0x09,0x4f,0x44,0x9e,0x78,0xe9,0xb7,0xbb,0x2f,0xc2,
0x5a,0xfd,0xee,0xc0,0xf2,0x62,0x2a,0x98,0x0b,0x5e,0xd3,0xf9,0xd3,0xf9,0x05,0x90,
0x94,0x22,0x1f,0xf9,0x56,0xaa,0x1e,0xd9,0xe3,0x20,0x74,0x19,0xca,0xa1,0x2a,0x0e,
0x29,0xaa,0xe8,0x7e,0x5c,0x4b,0xf0,0xec,0x4d,0xd0,0x7c,0x20,0xd9,0x1c,0xcc,0x9e,
0x2c,0xf6,0xb4,0x9a,0x18,0xbb,0xc0,0x20,0xc5,0xb7,0xf4,0xc0,0xd1,0x61,0x7d,0x1e,
0x71,0x59,0x96,0xda,0x26,0x84,0x73,0x22,0x77,0x53,0xbd,0xcf,0x50,0x51,0x53,0xc8,
0x7d,0x3c,0x17,0x72,0x7d,0x95,0x00,0xa0,0xcc,0x21,0x6d,0x25,0xcd,0x1b,0xd3,0x12,
// ------------------------------------------------------^^-----差异点
};
//碰撞用的大数组
const unsigned char md5_h[] =
{
0x14,0xba,0x1f,0x3a,0x94,0x14,0xc7,0x5b,0x6e,0xb1,0x32,0xc3,0xbc,0x6f,0xb8,0x13,
0x58,0x9b,0xa0,0xc4,0x73,0x42,0x09,0x4f,0x44,0x9e,0x78,0xe9,0xb7,0xbb,0x2f,0xc2,
0x5a,0xfd,0xee,0xc0,0xf2,0x62,0x2a,0x98,0x0b,0x5e,0xd3,0xf9,0xd3,0x79,0x05,0x90,
0x94,0x22,0x1f,0xf9,0x56,0xaa,0x1e,0xd9,0xe3,0x20,0x74,0x99,0xca,0xa1,0x2a,0x0e,
0x29,0xaa,0xe8,0x7e,0x5c,0x4b,0xf0,0xec,0x4d,0xd0,0x7c,0x20,0xd9,0x1c,0xcc,0x9e,
0x2c,0xf6,0xb4,0x1a,0x18,0xbb,0xc0,0x20,0xc5,0xb7,0xf4,0xc0,0xd1,0x61,0x7d,0x1e,
0x71,0x59,0x96,0xda,0x26,0x84,0x73,0x22,0x77,0x53,0xbd,0xcf,0x50,0xd1,0x53,0xc8,
0x7d,0x3c,0x17,0x72,0x7d,0x95,0x00,0xa0,0xcc,0x21,0x6d,0xa5,0xcd,0x1b,0xd3,0x12,
// ------------------------------------------------------^^-----差异点
};
最终就可以生成两张md5相同的图片了:
结束
是不是还可以做点其他更好玩的东西?
转载保留版权:晨旭的博客 » 《利用MD5碰撞,生成两张显示不同,但是MD5相同的GIF图片》如果喜欢可以: 点击右侧上方的邮件订阅,订阅本站
怎么生成两张显示不同MD5相同的图片