md5
弱碰撞
php中的MD5碰撞常与若比较进行结合
这种情况下,弱碰撞即可解决
弱比较:
如果两个字符经MD5加密后的值为 0exxxxx形式,就会被认为是科学计数法,且表示的是0*10的xxxx次方,还是零,都是相等的。
下面代码为具体情况,
1 2 3
| if($_POST['a']!=$_POST['b'&& md5($_POST['a'])==md5($_POST['b'])){ die("success!"); }
|
下列的字符串的MD5值都是0e开头的:
1 2 3 4 5 6
| QNKCDZO 240610708 s878926199a s155964671a s214587387a s214587387a
|
双重MD5加密后0E开头:
1 2 3
| 7r4lGXCH2Ksu2JNT3BYM CbDLytmyGm2xQyaLNhWn 770hQgrBOjrcqftrlaZk
|
强比较:
md5()函数无法处理数组,如果传入的为数组,会返回NULL,所以两个数组经过加密后得到的都是NULL,也就是相等的。 例如 a[]=1&b[]=2。
具体情况如下,
1 2 3
| if ($_POST['a'] !== $_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { die("success!"); }
|
强比较:
NAN和INF,分别为非数字和无穷大,但是var_dump一下它们的数据类型却是double,那么在md5函数处理它们的时候,是将其直接转换为字符串”NAN”和字符串”INF”使用的,但是它们拥有特殊的性质,它们与任何数据类型(除了true)做强类型或弱类型比较均为false,甚至NAN=NAN都是false,但md5('NaN')=md5('NaN')为true。
强碰撞
加了一个string转换,导致==绕不过去(因为空数组转字符串为null,数组转换为字符串时都会变成Array)
具体情况如下,
1 2 3
| if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { die("success!"); }
|
这样我们就必须运用MD5强碰撞
比如,
1 2 3
| md5("TEXTCOLLBYfGiJUETHQ4hAcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak") = md5("TEXTCOLLBYfGiJUETHQ4hEcKSMd5zYpgqf1YRDhkmxHkhPWptrkoyz28wnI9V0aHeAuaKnak")
|
当然,有时候题目或许会要求我们两个碰撞参数的前缀相同,那么此时,我们就可以定制前缀一致的MD5强碰撞(比如上面这对,前缀就是一样的)
可以有的三种方法
注意一点,post时一定要urlencode!!!
MD5爆破
有时候,还会要求根据MD5碰撞后的结果,倒推出部分字符,这时候我们就必须借助工具:
比如,
1
| hashcat -a 3 -m 0 8df2643c35506af082e7a97c813b133d flag{753?h22?h6-05?hf-441?h-b?h01-822?h5f04c?h3?h}
|
使用4060无CUDA驱动的情况下,20秒完成,爆破出flag{75382286-055f-441d-b601-82275f04c13a}
有时候甚至会直接给你一个MD5值或者双MD5值,让你爆破出原值,
这时候我们往往采用在线网站,如:https://www.cmd5.com/
md5截断爆破
代码如下:
1
| substr(md5(?),0,5)==='8ffb1'
|
一般使用脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import hashlib from multiprocessing.dummy import Pool as ThreadPool
def md5(s): return hashlib.md5(str(s).encode('utf-8')).hexdigest()
keymd5 = '8ffb1' md5start = 0 md5length = 5
def findmd5(sss): key = sss.split(':') start = int(key[0]) end = int(key[1]) result = 0 for i in range(start, end): if md5(i)[0:5] == keymd5: result = i print(result) break
list=[] for i in range(10): list.append(str(10000000*i) + ':' + str(10000000*(i+1))) pool = ThreadPool() pool.map(findmd5, list) pool.close() pool.join()
|
SHA1
常规碰撞
与MD5大差不差
以下值在sha1加密后以0E开头:
1 2 3 4 5 6
| aaroZmOk aaK1STfY aaO8zKZF aa3OFF9m 0e1290633704 10932435112
|
如果是强比较,没有转为string,可以用数组 例如 a[]=1&b[]=2来绕过,也可以用强碰撞;
如果是强比较,但转为string,用强碰撞
截断爆破
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import hashlib from multiprocessing.dummy import Pool as ThreadPool
def sha256(s): return hashlib.sha256(('TQLCTF'+str(s)).encode('utf-8')).hexdigest()
keysha256 = '5625f' sha256start = 0 sha256length = 5
def findsha256(sss): key = sss.split(':') start = int(key[0]) end = int(key[1]) result = 0 for i in range(start, end): if sha256(i)[0:5] == keysha256: result = i print(result) break
list=[] for i in range(10): list.append(str(10000000*i) + ':' + str(10000000*(i+1))) pool = ThreadPool() pool.map(findsha256, list) pool.close() pool.join()
|
至于其他的碰撞,如SHA-224、SHA-256等,我们可以查找一个hash碰撞收集库:https://github.com/spaze/hashes
这里就不再详解