本文记录于笔者在CTF中接触的有关哈希比较题目的一些总结
哈希算法(Hash Algorithm)又称散列算法、散列函数、哈希函数,哈希算法主要有
MD4
、MD5
、SHA
在了解PHP中处理hash的缺陷之前,先来了解下科学计数法
再看看科学计数法在PHP中如何表示
PS:
INF
是无穷大
PHP中处理Hash时的缺陷
PHP中的hash缺陷
即指哈希算法加密之后的一种特殊组合,即以0e
开头+纯数字
的组合,比如: 0e708279691820928818722257405159
然后在PHP中这种特殊的hash
(也就是所谓的Magic Hash
),会被认为是科学计数法
,因为这是科学计数法的表示格式,而在科学计数法当中零的N次方(0 x 10^N)
都是0
这种缺陷其实和PHP的强弱类型比较
没有直接关系,只是强类型会导致利用条件受很大限制,弱类型没有什么限制更容易导致程序被绕过
==
弱类型比较中,字符'0e123'
和字符'0e456'
虽然是字符类型,但是因为==
比较不比较数据类型,只比较值,而值就是科学计数法的表示格式,结果都是0
,所以相等,返回true
===
强类型比较中,字符'0e123'
和字符'0e456'
在比较数据类型的时候就被当作字符类型,而字符'0e123'
和字符'0e456'
当然不相等,所以返回false
这种缺陷在PHP程序中使用哈希算法加密(如md5、md4、SHA1等)
进行有关强弱类型比较
的地方很容易被用来进行绕过,在CTF题目中算是比较常见的
Magic Hashes
Plaintext | MD5 Hash |
---|---|
240610708 | 0e462097431906509019562988736854 |
QLTHNDT | 0e405967825401955372549139051580 |
QNKCDZO | 0e830400451993494058024219903391 |
PJNPDWY | 0e291529052894702774557631701704 |
NWWKITQ | 0e763082070976038347657360817689 |
NOOPCJF | 0e818888003657176127862245791911 |
MMHUWUV | 0e701732711630150438129209816536 |
MAUXXQC | 0e478478466848439040434801845361 |
IHKFRNS | 0e256160682445802696926137988570 |
GZECLQZ | 0e537612333747236407713628225676 |
GGHMVOE | 0e362766013028313274586933780773 |
GEGHBXL | 0e248776895502908863709684713578 |
EEIZDOI | 0e782601363539291779881938479162 |
DYAXWCA | 0e424759758842488633464374063001 |
DQWRASX | 0e742373665639232907775599582643 |
BRTKUJZ | 00e57640477961333848717747276704 |
ABJIHVY | 0e755264355178451322893275696586 |
aaaXXAYW | 0e540853622400160407992788832284 |
aabg7XSs | 0e087386482136013740957780965295 |
aabC9RqS | 0e041022518165728065344349536299 |
0e215962017 | 0e291242476940776845150308577824 |
Plaintext | SHA1 Hash |
---|---|
aaroZmOk | 0e66507019969427134894567494305185566735 |
aaK1STfY | 0e76658526655756207688271159624026011393 |
aaO8zKZF | 0e89257456677279068558073954252716165668 |
aa3OFF9m | 0e36977786278517984959260394024281014729 |
Plaintext | MD4 Hash |
---|---|
bhhkktQZ | 0e949030067204812898914975918567 |
0e001233333333333334557778889 | 0e434041524824285414215559233446 |
0e00000111222333333666788888889 | 0e641853458593358523155449768529 |
0001235666666688888888888 | 0e832225036643258141969031181899 |
更多Magic Hashes请参考:https://github.com/spaze/hashes
这种其实也是利用hash缺陷来进行绕过的,只是这种Magic hash
看起来更加稀少
Magic Hashes
Plaintext | MD5 Hash |
---|---|
0e215962017 | 0e291242476940776845150308577824 |
0e1284838308 | 0e708279691820928818722257405159 |
0e1137126905 | 0e291659922323405260514745084877 |
0e807097110 | 0e318093639164485566453180786895 |
0e730083352 | 0e870635875304277170259950255928 |
Plaintext | MD4 Hash |
---|---|
0e001233333333333334557778889 | 0e434041524824285414215559233446 |
0e00000111222333333666788888889 | 0e641853458593358523155449768529 |
0001235666666688888888888 | 0e832225036643258141969031181899 |
Plaintext | SHA1 Hash |
---|---|
0e00000000000000000000081614617300000000 | 0e65307525940999632287492285468259219070 |
0e00000000000000000000721902017120000000 | 0e94981159498252295418182453841140483274 |
0e01011001101011010001101110101100101000 | 0e48906523151976751117677463787111106598 |
0e11001000001010011000100000010001101000 | 0e63407184960930419027062777705081379452 |
0e01000001100000001010011011001000000100 | 0e55962072388397083814346733718698213796 |
0e10011110000101101000011101011010100100 | 0e31188585417285828785355336774237712792 |
0e01010111000111111010101011010111010100 | 0e45906344569616659428808892091261969181 |
0e00100001110000001111010000010011101100 | 0e14860258669052332549568607710438132953 |
0e11110000111010001001101111111110010010 | 0e12174258436385758552874426941686538483 |
0e10111110011100101100010101111010000110 | 0e99774398282593376043462038572281385389 |
0e11001111110111110010111010000011110110 | 0e63185221301034624940345471074357888797 |
0e00001010010101100100101011101110001110 | 0e90943988772171749054413593888105986782 |
0e01011101110010111011110010010010101110 | 0e01608800192659803576771346607441737826 |
0e10111110101111001000000100011101101110 | 0e49094541458479495263034294421025186938 |
0e11100111101110011010111001010101111110 | 0e55770706149948760086200713505841887543 |
0e11111001010101100110011001010001110001 | 0e91120687121163809515824135435029958137 |
0e01000111101111110010010010000001001001 | 0e78071797328546369301825420848872451849 |
0e00100110100010100110001101110110110101 | 0e06077380408260614659219920561082767632 |
0e11111100001011000011110100100010111101 | 0e12149120354415335220758399492713921588 |
0e00111100110101101001000101011011111101 | 0e38661126569790555598431905065403870516 |
0e10100011100101000001110010100110100011 | 0e55745078154640212511596259055910278070 |
0e10011110011111001001100100000111011011 | 0e20319731123101477913295720812414482217 |
更多Magic Hashes请参考:https://github.com/spaze/hashes
还有一个关于PHP的这些
哈希函数md5()、md4()、sha1()等
一种绕过方法,但是和上文的哈希缺陷无关,这里也提一下吧
利用的是md5()、md4()、sha1()等
在处理非字符数据的时候异常返回,如这里传入数组,返回的是NULL
PS:这里无论===
或者==
,两边都是NULL
以下补充于2021/4/27
关于MD5强碰撞问题
当php对传参进行了类型控制,那么强比较就不能和上面一样一个数组传参就能解决
这就需要真正的满足条件了,需要寻找md5
完全相等,本身却不一样的字符,可是真的有存在这样的字符吗?
参考:https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value
file1
的十六进制字节流数据
d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70
file2
的十六进制字节流数据
d131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70
将字节流写入成文件
from binascii import *
with open('file1.txt','r') as f:
f = f.read()
with open('file1','wb') as i:
i.write(unhexlify(f))
print('[+]file1 write complete')
with open('file2.txt','r') as f:
f = f.read()
with open('file2','wb') as i:
i.write(unhexlify(f))
print('[+]file2 write complete')
可以看到两个不相同的文件它们的md5
值完全相等
将十六进制数据解码然后url编码一遍
from binascii import *
from urllib.parse import *
str1md5 = 'd131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70'
str2md5 = 'd131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70'
param1 = quote(unhexlify(str1md5))
param2 = quote(unhexlify(str2md5))
print(param1)
print(param2)
%D11%DD%02%C5%E6%EE%C4i%3D%9A%06%98%AF%F9%5C/%CA%B5%87%12F~%AB%40%04X%3E%B8%FB%7F%89U%AD4%06%09%F4%B3%02%83%E4%88%83%25qAZ%08Q%25%E8%F7%CD%C9%9F%D9%1D%BD%F2%807%3C%5B%D8%82%3E1V4%8F%5B%AEm%AC%D46%C9%19%C6%DDS%E2%B4%87%DA%03%FD%029c%06%D2H%CD%A0%E9%9F3B%0FW~%E8%CET%B6p%80%A8%0D%1E%C6%98%21%BC%B6%A8%83%93%96%F9e%2Bo%F7%2Ap
%D11%DD%02%C5%E6%EE%C4i%3D%9A%06%98%AF%F9%5C/%CA%B5%07%12F~%AB%40%04X%3E%B8%FB%7F%89U%AD4%06%09%F4%B3%02%83%E4%88%83%25%F1AZ%08Q%25%E8%F7%CD%C9%9F%D9%1D%BDr%807%3C%5B%D8%82%3E1V4%8F%5B%AEm%AC%D46%C9%19%C6%DDS%E24%87%DA%03%FD%029c%06%D2H%CD%A0%E9%9F3B%0FW~%E8%CET%B6p%80%28%0D%1E%C6%98%21%BC%B6%A8%83%93%96%F9e%ABo%F7%2Ap
成功满足要求
能够达到这种条件的数据还有
from binascii import *
from urllib.parse import *
str1md5 = '4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2'
str2md5 = '4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2'
param1 = quote(unhexlify(str1md5))
param2 = quote(unhexlify(str2md5))
print(param1)
print(param2)
M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2
还有
from binascii import *
from urllib.parse import *
str1md5 = '0e306561559aa787d00bc6f70bbdfe3404cf03659e704f8534c00ffb659c4c8740cc942feb2da115a3f4155cbb8607497386656d7d1f34a42059d78f5a8dd1ef'
str2md5 = '0e306561559aa787d00bc6f70bbdfe3404cf03659e744f8534c00ffb659c4c8740cc942feb2da115a3f415dcbb8607497386656d7d1f34a42059d78f5a8dd1ef'
param1 = quote(unhexlify(str1md5))
param2 = quote(unhexlify(str2md5))
print(param1)
print(param2)
%0E0eaU%9A%A7%87%D0%0B%C6%F7%0B%BD%FE4%04%CF%03e%9EpO%854%C0%0F%FBe%9CL%87%40%CC%94/%EB-%A1%15%A3%F4%15%5C%BB%86%07Is%86em%7D%1F4%A4%20Y%D7%8FZ%8D%D1%EF
%0E0eaU%9A%A7%87%D0%0B%C6%F7%0B%BD%FE4%04%CF%03e%9EtO%854%C0%0F%FBe%9CL%87%40%CC%94/%EB-%A1%15%A3%F4%15%DC%BB%86%07Is%86em%7D%1F4%A4%20Y%D7%8FZ%8D%D1%EF
总结以上md5强比较
相等字符
%D11%DD%02%C5%E6%EE%C4i%3D%9A%06%98%AF%F9%5C/%CA%B5%87%12F~%AB%40%04X%3E%B8%FB%7F%89U%AD4%06%09%F4%B3%02%83%E4%88%83%25qAZ%08Q%25%E8%F7%CD%C9%9F%D9%1D%BD%F2%807%3C%5B%D8%82%3E1V4%8F%5B%AEm%AC%D46%C9%19%C6%DDS%E2%B4%87%DA%03%FD%029c%06%D2H%CD%A0%E9%9F3B%0FW~%E8%CET%B6p%80%A8%0D%1E%C6%98%21%BC%B6%A8%83%93%96%F9e%2Bo%F7%2Ap
%D11%DD%02%C5%E6%EE%C4i%3D%9A%06%98%AF%F9%5C/%CA%B5%07%12F~%AB%40%04X%3E%B8%FB%7F%89U%AD4%06%09%F4%B3%02%83%E4%88%83%25%F1AZ%08Q%25%E8%F7%CD%C9%9F%D9%1D%BDr%807%3C%5B%D8%82%3E1V4%8F%5B%AEm%AC%D46%C9%19%C6%DDS%E24%87%DA%03%FD%029c%06%D2H%CD%A0%E9%9F3B%0FW~%E8%CET%B6p%80%28%0D%1E%C6%98%21%BC%B6%A8%83%93%96%F9e%ABo%F7%2Ap
以上两串字符的md5值都为:79054025255fb1a26e4bc422aef54eb4
M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2
以上两串字符的md5值都为:008ee33a9d58b51cfeb425b0959121c9
%0E0eaU%9A%A7%87%D0%0B%C6%F7%0B%BD%FE4%04%CF%03e%9EpO%854%C0%0F%FBe%9CL%87%40%CC%94/%EB-%A1%15%A3%F4%15%5C%BB%86%07Is%86em%7D%1F4%A4%20Y%D7%8FZ%8D%D1%EF
%0E0eaU%9A%A7%87%D0%0B%C6%F7%0B%BD%FE4%04%CF%03e%9EtO%854%C0%0F%FBe%9CL%87%40%CC%94/%EB-%A1%15%A3%F4%15%DC%BB%86%07Is%86em%7D%1F4%A4%20Y%D7%8FZ%8D%D1%EF
以上两串字符的md5值都为:cee9a457e790cf20d4bdaa6d69f01e41
以下补充于2021/5/17
跟本文没什么关系,但是也算是和md5有关的一个小知识,就记在这里了
ffifdyop
129581926211651571912466741651878684928
用于登录框密码存在md5
加密后存入数据的万能密码绕过登录
PS C:\Users\Administrator> php -r "var_dump(md5('129581926211651571912466741651878684928',true));"
Command line code:1:
string(16) "�T0D��o#��'or'8"
PS C:\Users\Administrator> php -r "var_dump(md5('ffifdyop',true));"
Command line code:1:
string(16) "'or'6�]��!r,��b"
PS C:\Users\Administrator>