跳转至

弱类型比较

== 与 ===

在PHP中比较符号有 == 与 === 两种,== 为松散比较,另一种 === 则为严格比较,我们通过官方手册的表格可以了解到类型转换以及比较, PHP手册 == 与 === 表格

image-20220419110458809

image-20220419111207949

当使用松散比较 == 时,PHP会首先将类型转化为统一类型后再进行比较,比如一个数字和一个字符串进行比较,PHP会把字符串转换成数字再进行比较。PHP转换的规则的是:若字符串以数字开头,则取开头数字作为转换结果,如下图

image-20220419114656501

值得注意的是,在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 来进行绕过

image-20220419132755373

字符串 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 或 Nullimage-20220419141238510

同样,类似的函数例如 sha1(), 同样也会出现相似的问题

image-20220419142332847

strcmp()

strcmp函数用于两个字符串之间的比较,当函数使用不当将会导致绕过

image-20220419143618278

在手册下我们可以看到曾经的相关留言

image-20220419143656833

<?php
if (strcmp($_POST['password'], 'sekret') == 0) {
    echo "Welcome, authorized user!\n";
} else {
    echo "Go away, imposter.\n";
}
?>

可以看到当 strcmp函数 传入数组时,达到绕过的效果,这是由于 strcmp函数无法处理数组导致的(与md5函数类似,返回Null),当传入数组时无论与任何字符做比较都会得到 Null

image-20220419143918067

在 PHP <= 5.3 版本时,显示了报错的警告信息后,将return 0,在 PHP >= 5.3 版本时,修复为返回为 Null。同样,类似的还有 strpos() 等无法处理数组的函数