弱类型
两种判等类型
php有两种判等的类型,==
与===
。
其中,===
是强类型的判等,会先判断两边类型是否相等,之后在进行比较。
然而,==
是弱类型的判等,会发生隐式类型转换后进行比较。
NULL、0、”0”、false
首先给大家看个好玩的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php var_dump(0=="0"); var_dump(0==NULL); var_dump(0==false);
var_dump("0"==false); var_dump("0"==NULL); var_dump("0"==0);
var_dump(NULL=="0"); var_dump(NULL==0); var_dump(NULL==false);
var_dump(false=="0"); var_dump(false==NULL); var_dump(false==0); ?>
|
字符串与数字的弱类型判等
1 2 3 4 5 6 7
| <?php var_dump("admin"==0); var_dump("1admin"==1); var_dump("admin1"==1) var_dump("admin1"==0) var_dump("0e123456"=="0e4456789"); ?>
|
"1admin"==1
,"admin1"==0
说明字符串隐式转数值时只看最前面的合法可转的数值表示。
应用
MD5碰撞绕过
当我们需要判断两个字符串的MD5值是否相同,我们通常会这么做:
1 2 3
| ... if (md5($Username) != md5($Password)) {$logined = false; } ...
|
那么利用上面"0e123456"=="0e4456789"
的性质,如果存在两个字符串,它们的前两位都恰好是0e
,那么就成功绕过了这个分支。
几个MD5值以0e
开头的字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| QNKCDZO 0e830400451993494058024219903391
s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s1885207154a 0e509367213418206700842008763514
|
MD5和双MD5都是0e开头的几个值:
1 2 3
| CbDLytmyGm2xQyaLNhWn 770hQgrBOjrcqftrlaZk 7r4lGXCH2Ksu2JNT3BYM
|
md5前后都是0e开头的值:
1 2
| 0e215962017 0eRnJWi9XnKd9Z7x
|
而如果想要达成这样的条件:
1 2 3
| if ($param1 !== $param2 && md5($param1) === md5($param2)) { }
|
则可以将$param1
和$param2
定义为含有不同元素的两个数组。由于md5
函数传入数组会返回null
,两个强类型条件都得到满足。
不过如果两个参数都被强转了就没法传入数组来绕过,类似如下情况:
1 2 3
| if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) { echo `$cmd`; }
|
只能用一组特别特殊的md5碰撞值来绕过:
1 2
| a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2 b=b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
|
json绕过
1 2 3 4 5 6 7
| ... $message = json_decode($_POST['message']); $key ="*********"; if ($message->key == $key) { echo "flag"; } ...
|
虽然不知道$key
的值,但是可以赌他不以数字开头,只要他不以数字开头,一旦发生弱类型的隐式转换,只要令$message->key
为0就可以绕过了。
Reference