实验目的
本次实验主要是加深大家对MD5碰撞及其原理的理解,使用SEED实验环境中的工具及编程语言,完成以下任务:
- 使用md5collgen生成两个MD5值相同的文件,并利用bless十六进制编辑器查看输出的两个文件,描述你观察到的情况;
- 参考Lab3_task2.c的代码,生成两个MD5值相同但输出不同的两个可执行文件;
- 参考Lab3_task3.c的代码,生成两个MD5值相同但代码行为不相同的可执行文件;
- 回答问题:通过上面的实验,请解释为什么可以做到不同行为的两个可执行文件具有相同的MD5值?
实验工具及原理介绍
md5collgen原理如下图所示
由MD5的特性:如果MD5(M) = MD5(N),也就是说,MD5哈希的M和N是相同的,那么对于任何输入T,MD5(M || T)= MD5(N || T),其中||表示连接。
md5collgen可以生成两个128字节的MD5哈希值相同但内容不同的字节分组,假设为P和Q。并且将P和Q分别连接在一个前缀文件之后(前缀文件的长度一定要是64字节的倍数),那么就可以得到两个内容不同但MD5哈希值相同的文件,其中内容不同体现在最后128个字节中。
实验步骤及结果
一、使用md5collgen生成两个MD5值相同的文件,并利用bless十六进制编辑器查看输出的两个文件,描述你观察到的情况;
1. 首先创建一个prefix.txt文件,输入任意内容。
2. 运行md5collgen工具,用prefix.txt文件作为前缀生成两个具有相同MD5哈希值的不同文件,分别命名为test1.bin1和test2.bin。
3. 用diff命令比较两个文件的异同,发现文件并不相同;用md5sum查看两个文件的MD5值,结果相同。说明两个不同的文件有相同的MD5值。
4. 使用bless十六进制编辑器查看输出的两个文件,可以看出两个文件的前缀相同,但有两处的十六进制的值不同,证明这是两个不同的文件。
附:实验pdf中的一些问题:
问题一:如果前缀文件的长度不是64字节的倍数,会发生什么?
从图中可以看出,不足64字节倍数的部分被补0.
问题二:创建一个长度为64字节倍数的前缀文件使用工具进行碰撞产生输出文件,观察会发生什么?
这个问题可以从后面的实验中得到答案:md5collgen工具直接添加了128个不同的字节在前缀文件后面。
问题三:md5collgen产生的128个字节是完全不同的吗?找出所有不同的地方。
从实验一两个二进制文件的对比图中就可以看出, 128个字节只有两个字节是不同的。
二、 参考Lab3_task2.c的代码,生成两个MD5值相同但输出不同的两个可执行文件;
1. 原理:
给定两个输入M和N,如果MD5(M) = MD5(N),即M和N的MD5散列是相同的,那么对于任何输入T,MD5(M || T)= MD5(N || T),其中||表示连接。基于MD5的属性,我们知道,如果我们在上面的两个输出中附加相同的后缀,所得到的数据也将具有相同的哈希值。基本上,以下内容对任何后缀都适用:
因此,我们只需要使用P和Q来替换数组的128个字节(在两个分法点之间),就能够创建两个具有相同哈希值的可运行程序。
2. 构造可运行代码,补充字符串内容
3. 编译运行
4. 打开bless编辑器,找到xyz数组在文件中对应的位置:第12320个字符到第12529个字符。
5. 根据文档中的描述,我们需要将该文件分为三部分,其中在数组内部,我们可以找到两个位置,在那里我们可以将可执行文件分为三个部分:一个前缀、一个128字节的区域和一个后缀。该前缀的长度需要是64个字节的倍数。关于文件是如何分割的说明,请参见下图。
6. 经过计算,我将文件分为了三个部分:前12352个字节作为前缀,中间12352到12480作为中间的128个字节,后面12481到最后的一个字节作为后缀部分。
第一行命令将task2文件的前12352个字符作为前缀,第二行命令将task2文件第12481个字节及以后的字符作为后缀。
7. 用生成的前缀文件运行md5collgen 来生成两个具有相同MD5散列值的输出。
8. 检查两个生成的文件是否相同,MD5哈希值是否相同
可视化检查:
可以看到两个二进制文件有两处的两个字节不相同。
9. 将两个文件与后缀文件连接,分别生成新的可执行文件
10. 分别运行这两个程序(运行前要授予运行权限),观察两个文件的输出结果
可以发现,两个程序的前缀部分和后缀部分是相同的,中间128个字符有些许的不同。
11. 检查两个可执行文件的MD5哈希值
对比发现,两个文件的MD5哈希值相同,至此,任务2成功完成,生成了两个MD5值相同但输出不同的两个可执行文件。
三、 参考Lab3_task3.c的代码,生成两个MD5值相同但代码行为不相同的可执行文件;
1. 代码逻辑:
如果数组X和数组Y的内容相同,那么运行正常的代码;反之,如果数组X和数组Y的内容不同,那么运行恶意的代码。
根据上述逻辑,我们能通过生成两个数组内容不同但MD5哈希值相同的可执行文件来实现目标,其中一个文件的X和Y内容相同,另一个不同。类似于任务2中的构造,我们可以用相似的思路来实现:
图中的前缀和后缀可以取自原来的可运行文件,而Q用来替代原本的128个字节P实现MD5碰撞,以此实现运行结果不同。具体的思路见后。
2. 将代码补充完整,为了实现上述功能,我们将X和Y填充相同的内容:
主函数逻辑部分:
3. 生成可运行文件,使用bless编辑器查看内容
定位到了X数组的位置:12320字节到12519字节,Y数组的位置:12544字节到12743字节。根据步骤a中的思路,我作了以下划分:将12352字节及以前的内容作为前缀task3_prefix,12481字节到12576字节部分的内容作为中间部分mid,12705字节及以后的内容作为后缀,两数组中间128个字节替换实现碰撞。
4. 首先生成三部分需要的文件:前缀,后缀以及中间部分:
前缀部分:前12352个字节
中间部分:我们可以通过先截取原文件的前12576个字节,再截取第12481个字节及以后的部分来获得
后缀部分:第12705个字节及以后
5. 利用md5collgen工具用前缀文件生成两个MD5哈希值相同的文件
根据工具的原理,这两个MD5哈希值相同的文件除了最后128个字节的内容外,其余内容都相同,而且添加相同的后缀后,MD5哈希值依然会相同,所以我们将这两个文件作为我们目标的第一部分
6. 获取P部分,作为填充段用于填充两个文件空缺的部分
7. 将剩余各部分连接起来得到完整的可运行文件
生成善意代码可执行文件:
生成恶意代码可执行文件:
生成的文件的示意图:
8. 根据MD5原理,我们连接后得到的两个可执行文件的MD5哈希值是相同的,检验如下:
9. 运行这两个文件,观察结果:
运行成功,结果显示两程序运行结果不同,任务3完成。
四、 回答问题:通过上面的实验,请解释为什么可以做到不同行为的两个可执行文件具有相同的MD5值?
究其根本,是因为可以实现两个具有不同的字节分组的文件的MD5值相同,即实现了碰撞。
我们通过md5collgen工具能够生成两个末尾128字节分组内容不同的MD5哈希值相同的文件,并且在其后添加相同的后缀时,哈希值仍然相同。
原因就是MD5算法的特性:
基于MD5的工作原理,我们可以得出以下属性的MD5算法:给定两个输入M和N,如果MD5(M) = MD5(N),也就是说,MD5哈希的M和N是相同的,那么对于任何输入T,MD5(M || T)= MD5(N || T),其中||表示连接。也就是说,如果输入M和N具有相同的散列值,那么向它们添加相同的后缀T将得到两个具有相同散列值的输出。这个属性不仅适用于MD5哈希算法,也适用于许多其他哈希算法。
因此,我们就可以给生成的两个不同的文件加上相同的后缀,导致的结果就是一个文件的两数组内容相同,另一个则不同,但两文件的MD5哈希值依然相同。