浅谈PHP中哈希比较缺陷问题及哈希强比较相关问题

本文记录于笔者在CTF中接触的有关哈希比较题目的一些总结

哈希算法(Hash Algorithm)又称散列算法、散列函数、哈希函数,哈希算法主要有MD4MD5SHA

在了解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

PlaintextMD5 Hash
2406107080e462097431906509019562988736854
QLTHNDT0e405967825401955372549139051580
QNKCDZO0e830400451993494058024219903391
PJNPDWY0e291529052894702774557631701704
NWWKITQ0e763082070976038347657360817689
NOOPCJF0e818888003657176127862245791911
MMHUWUV0e701732711630150438129209816536
MAUXXQC0e478478466848439040434801845361
IHKFRNS0e256160682445802696926137988570
GZECLQZ0e537612333747236407713628225676
GGHMVOE0e362766013028313274586933780773
GEGHBXL0e248776895502908863709684713578
EEIZDOI0e782601363539291779881938479162
DYAXWCA0e424759758842488633464374063001
DQWRASX0e742373665639232907775599582643
BRTKUJZ00e57640477961333848717747276704
ABJIHVY0e755264355178451322893275696586
aaaXXAYW0e540853622400160407992788832284
aabg7XSs0e087386482136013740957780965295
aabC9RqS0e041022518165728065344349536299
0e2159620170e291242476940776845150308577824
PlaintextSHA1 Hash
aaroZmOk0e66507019969427134894567494305185566735
aaK1STfY0e76658526655756207688271159624026011393
aaO8zKZF0e89257456677279068558073954252716165668
aa3OFF9m0e36977786278517984959260394024281014729
PlaintextMD4 Hash
bhhkktQZ0e949030067204812898914975918567
0e0012333333333333345577788890e434041524824285414215559233446
0e000001112223333336667888888890e641853458593358523155449768529
00012356666666888888888880e832225036643258141969031181899

更多Magic Hashes请参考:https://github.com/spaze/hashes
在这里插入图片描述
在这里插入图片描述
这种其实也是利用hash缺陷来进行绕过的,只是这种Magic hash看起来更加稀少

Magic Hashes

PlaintextMD5 Hash
0e2159620170e291242476940776845150308577824
0e12848383080e708279691820928818722257405159
0e11371269050e291659922323405260514745084877
0e8070971100e318093639164485566453180786895
0e7300833520e870635875304277170259950255928
PlaintextMD4 Hash
0e0012333333333333345577788890e434041524824285414215559233446
0e000001112223333336667888888890e641853458593358523155449768529
00012356666666888888888880e832225036643258141969031181899
PlaintextSHA1 Hash
0e000000000000000000000816146173000000000e65307525940999632287492285468259219070
0e000000000000000000007219020171200000000e94981159498252295418182453841140483274
0e010110011010110100011011101011001010000e48906523151976751117677463787111106598
0e110010000010100110001000000100011010000e63407184960930419027062777705081379452
0e010000011000000010100110110010000001000e55962072388397083814346733718698213796
0e100111100001011010000111010110101001000e31188585417285828785355336774237712792
0e010101110001111110101010110101110101000e45906344569616659428808892091261969181
0e001000011100000011110100000100111011000e14860258669052332549568607710438132953
0e111100001110100010011011111111100100100e12174258436385758552874426941686538483
0e101111100111001011000101011110100001100e99774398282593376043462038572281385389
0e110011111101111100101110100000111101100e63185221301034624940345471074357888797
0e000010100101011001001010111011100011100e90943988772171749054413593888105986782
0e010111011100101110111100100100101011100e01608800192659803576771346607441737826
0e101111101011110010000001000111011011100e49094541458479495263034294421025186938
0e111001111011100110101110010101011111100e55770706149948760086200713505841887543
0e111110010101011001100110010100011100010e91120687121163809515824135435029958137
0e010001111011111100100100100000010010010e78071797328546369301825420848872451849
0e001001101000101001100011011101101101010e06077380408260614659219920561082767632
0e111111000010110000111101001000101111010e12149120354415335220758399492713921588
0e001111001101011010010001010110111111010e38661126569790555598431905065403870516
0e101000111001010000011100101001101000110e55745078154640212511596259055910278070
0e100111100111110010011001000001110110110e20319731123101477913295720812414482217

更多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>
  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

末 初

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值