前言
我们在ctf赛题中不乏看到这样的判定
1 |
|
我们可以看到这是一个典型的md5碰撞题目,题目中判定了a和b的md5值是否相等,所以我们可以构造a和b的md5值相等,但是a和b不相等的情况,从而绕过判定。sha1也存在这样的问题,这里会稍微牵扯一下。
md5简介
MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希函数,它将任意长度的消息压缩成一个128位的哈希值。
MD5算法由Ronald Rivest在1991年设计,旨在提供一种快速且高效的消息摘要生成方法。MD5主要用于验证数据完整性和数字签名,但由于其安全性问题,现已被认为不适合用于密码学应用。
我院王小云院士之前的研究就与md5碰撞相关……
可行的手段
弱比较
0e绕过
在php中,使用==
进行比较时,会进行类型转换,这就导致了一些意想不到的结果。
我们知道,md5格式为32位16进制数,必然存在一些特殊的md5长这个样子:0e830400451993494058024219903391
0e开头,在弱比较中,0e表示科学计数法中的0乘以10的某次方,因此无论后面的数字是什么,都会被认为是0。
所以,当我们构造a和b的md5值相等,但是a和b不相等的情况时,a和b的md5值都会被认为是0,从而绕过判定。
sha1的0e绕过
1 | aaroZmOk |
自身绕过
存在这样一个判断
1 | $a==md5($a) |
这就要求我们找到一个0e开头的$a,MD5后也是0e开头
$a=0e215962017
双重md5下的0e绕过
存在这样一个判断
1 | $a==md5(md5($a)) |
比如这些
1 | 7r4lGXCH2Ksu2JNT3BYM |
即可绕过
强比较
一般来说强比较能行的也能过弱比较()
因此我们就直接来谈它吧
数组绕过
MD5一个数组返回了null,这样null===null就成立了
1 |
|
就进去了()
内置类绕过
我们知道当一个对象被转换为字符串时,会调用__toString()方法,而当一个对象被转换为整数时,会调用__intval()方法。
我们可以利用这两个方法,来绕过强比较。
比如这样
1 |
|
这里面有很多需要注意,否则就会像我一样开始进不去()
- Exception的第一个参数是message,第二个参数是code,code必须是整数,否则会报错
- Exception第一个参数message必须一样,否则会报错
- 最关键的是,必须在一行,不能换行,否则会报错,这个时候可能牵扯到适用性问题,注意即可,小trick
应用
当然,比起它可以绕过的作用,我认为可以关注一种具体情形
详细可见[极客大挑战 2020]Greatphp
即在反序列的情景下,既可以满足不可换行,绕过md5验证,又可以控制message的值,从而实现RCE,第一次见还是很惊讶的
限制
目前有两种内置类可供使用
1 | Error(只在php7) |
天选payload
有可打印字符鉴定,就无法使用fastcoll工具(后续会讲到)
如果有字符串鉴定,就无法使用数组绕过
有换行,也不能内置类绕过
没招了()
可以使用这个payload
1 | TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak |
如果看到这个,你之前不知道,那你绝对没白来()
两个字符串中间只有一个字符的差异,为何会MD5相等,它们是 一对 MD5 碰撞样本,等待大佬解释
拓展
md5碰撞生成:fastcoll工具
fastcoll是一个用于生成MD5碰撞的工具。它利用了MD5算法的弱点,能够在短时间内找到两个不同的输入数据,这些数据在经过MD5哈希函数处理后会产生相同的哈希值。
使用场景
如果一道题目会对你上传的两张图片进行md5验证,而你上传的两张图片的md5值相等,但是它们的内容不相等,这时候就可以使用fastcoll工具生成碰撞样本,从而绕过md5验证。
fastcoll工具下载
使用方法
详细见工具说明
一般我们根据一个文件生成两个md5值一样的不同文件,这个时候可以
1 |
|
即可得到urlencode后的字符串,直接提交即可
sql里的MD5
如果大家了解到sql的万能密码就可以继续看下去了
使用 md5($val, true)
计算的 md5 转换为字符串时会被以16进制数据解析为字符串
即,如果实现了md5($val, true)
,那么只要我们传入一个字符,它的md5值被解析为16进制数时,正好可以实现这种效果
1 | $sql = "SELECT * FROM admin WHERE username = 'admin' and password = '' or true"; |
那么就可以万能密码登录
比如如下字符
1 | ffifdyop |
哈希长度扩展攻击(加盐)
哈希长度扩展攻击(Hash Length Extension Attack)是一种针对某些哈希函数的攻击方法,允许攻击者在不知道原始消息内容的情况下,计算出一个新的消息及其对应的哈希值。
示例
1 |
|
基于此,可以进行哈希拓展攻击
具体需要了解md5的实现,当然网上有很多文章,我这里简述一下
MD5会把字符转化为512位的二进制块
填充的逻辑在这
1 | 明文数据的二进制数据长度<=448,填充padding(无意义占位)数据使其长度为448,再添加原始明文数据的二进制长度信息(64位)使其长度为512位即可。 |
这样的话,我们在$v1这一部分操作一下
即
md5($secret.$v1)
v1="test" + padding数据 + 长度数据 + "abc"
逻辑是,知道位数之后就可以知道padding数据和长度数据,这样的话可以生成
$secret."test".padding数据 + 长度数据
—>md5
这样的话可以从md5推出最后的一个向量串
因为我们知道
1 | 而最后的MD5值就是这最后的向量串经过如下转换的结果。 |
我们根据服务回显出的md5反推出最后一个向量串
再回到v1="test" + padding数据 + 长度数据 + "abc"
这里前部分是完整的若干512块,会生成一个向量串
然后倒数第二个向量串和abc那块512位进行运算,得到最后的md5
工具
hashdump
详细见文档
后记
ctf里面有关md5的考点(我见过)大抵如此,如果有其他考点,欢迎补充