弱类型比较¶
== 与 ===¶
在PHP中比较符号有 == 与 === 两种,== 为松散比较,另一种 === 则为严格比较,我们通过官方手册的表格可以了解到类型转换以及比较, PHP手册 == 与 === 表格
当使用松散比较 == 时,PHP会首先将类型转化为统一类型后再进行比较,比如一个数字和一个字符串进行比较,PHP会把字符串转换成数字再进行比较。PHP转换的规则的是:若字符串以数字开头,则取开头数字作为转换结果,如下图
值得注意的是,在PHP 8.0 版本中对 == 字符与数字对比做出了优化, 例如:var_dump('a' == 0);
在新版本中则返回False
md5()¶
md5() 函数常见用于源码中的用户密码输入加密,与数据库中的 md5加密密码对比,由于PHP弱类型的特性,当代码不够严谨时,将导致例如登录等的绕过,我们看下面的一段代码
<?php
if($_GET['a'] != $_GET['b']){
if(md5($_GET['a']) == md5($_GET['b'])){
echo 'Success';
}
}
?>
代码中首先判断 a 与 b 传入的参数不允许相同,但后半段则要求 md5加密值相同,按逻辑看来似乎是不可能的。但由于PHP中,0e开头的字符串
会被判定为科学计数法
,而0的 x次方均为0,所以绕过就可以通过传参开头均为 0e 的字符赋值给 a 与 b 来进行绕过
字符串 | md5值 |
---|---|
QNKCDZO | 0e830400451993494058024219903391 |
240610708 | 0e462097431906509019562988736854 |
s878926199a | 0e545993274517709034328855841020 |
s155964671a | 0e342768416822451524974117254469 |
s214587387a | 0e848240448830537924465865611904 |
s214587387a | 0e848240448830537924465865611904 |
s878926199a | 0e545993274517709034328855841020 |
s878926199a | 0e545993274517709034328855841020 |
s1665632922a | 0e731198061491163073197128363787 |
s1836677006a | 0e481036490867661113260034900752 |
由于弱类型导致了松散比较 == 的绕过,于是大部分源码中对使用的则为 === ,而强比较 在md5()函数
中的应用上也存在代码逻辑不严谨导致的漏洞 , 如下面一段代码
<?php
if($_GET['a'] != $_GET['b']){
if(md5($_GET['a']) === md5($_GET['b'])){
echo 'Success';
}
}
?>
这一段代码中将 == 转为 ===,使用刚刚的方法则无法通过if语句,但由于 md5() 函数
是无法处理数组
的,当变量为数组传入 md5 中时,不会立刻停止
运行php程序,而是抛出warning
,得到的结果为 False 或 Null
同样,类似的函数例如 sha1()
, 同样也会出现相似的问题
strcmp()¶
strcmp函数用于两个字符串之间的比较,当函数使用不当将会导致绕过
在手册下我们可以看到曾经的相关留言
<?php
if (strcmp($_POST['password'], 'sekret') == 0) {
echo "Welcome, authorized user!\n";
} else {
echo "Go away, imposter.\n";
}
?>
可以看到当 strcmp函数
传入数组时,达到绕过的效果,这是由于 strcmp函数无法处理数组导致的(与md5函数类似,返回Null)
,当传入数组时无论与任何字符做比较都会得到 Null
在 PHP <= 5.3 版本时,显示了报错的警告信息后,将return 0
,在 PHP >= 5.3 版本时,修复为返回为 Null
。同样,类似的还有 strpos() 等无法处理数组
的函数