看到有一个很有意思的测试,代码大概是下面的感觉:
1 2 3 4 5 6 7 8 |
global $flag; if(isset($_GET['pass'])) if($_GET['pass']!='240610708' && md5($_GET['pass'])==md5('240610708')) echo $flag; else echo 'Wrong'; else echo 'Nothing'; |
如何得到 $flag 的值???
这个东西是我在搜 MD5 碰撞的时候搜出来的,但实际上这个东西和 MD5 碰撞毛子关系都没有,这个纯粹是PHP的毛病。
做个测试就好。上面代码的DEMO放在这里
看起来似乎除了 MD5 碰撞没有其它办法,但是,如果我们提交?pass=QNKCDZO
,我们就会惊奇的发现居然通过验证了!!!(可以去自己试试,DEMO在上面
很显然,
md5( ‘QNKCDZO’ ) = 0e830400451993494058024219903391
md5( ‘240610708’ ) = 0e462097431906509019562988736854
这两除了开头是 0e 后面基本上都不一样,PHP怎么会判断它们相等???
找到官方文档,一切水落石出
http://php.net/manual/zh/language.operators.comparison.php
因为PHP是弱语言,会自动把 xe 开头的字符串当科学计数法转成数字再进行比较,那自然 0e 后面不管跟什么东西转成数字都是0,自然判断是会相等。
修复方法: 换用 === (强制判断类型相等
这些结果都是 (bool)true
[code lang=”php”]
var_dump(md5(‘240610708’) == md5(‘QNKCDZO’));
var_dump(md5(‘aabg7XSs’) == md5(‘aabC9RqS’));
var_dump(sha1(‘aaroZmOk’) == sha1(‘aaK1STfY’));
var_dump(sha1(‘aaO8zKZF’) == sha1(‘aa3OFF9m’));
var_dump(‘0010e2’ == ‘1e3’);
var_dump(‘0x1234Ab’ == ‘1193131’);
var_dump(‘0xABCdef’ == ‘ 0xABCdef’);
[/code]
这些都由 0e 开头
s878926199a
s155964671a
s214587387a
s214587387a
sha1(‘aaroZmOk’)
sha1(‘aaK1STfY’)
sha1(‘aaO8zKZF’)
sha1(‘aa3OFF9m’)