Php comparison operator security issues
0x00 comparison operator
Php's comparison operators include = (equal to) loose comparison, = (completely equal to) strict comparison, which introduces many interesting questions.
In loose comparisons, php will unify their types, for exampleCharacter to number, non-bool type to bool typeTo avoid unexpected running results, use strict comparison. The following table lists the comparison operators on php manual:
Example name result $ a = $ B is equal to TRUE. If $ a is equal to $ B after type conversion. $ A ===$ B all equal to TRUE, if $ a is equal to $ B, and their types are the same. $! = $ B is not equal to TRUE. If $ a is not equal to $ B after type conversion. $ A <> $ B is not equal to TRUE. If $ a is not equal to $ B after type conversion. $! = $ B is not all TRUE, if $ a is not equal to $ B, or they are of different types. $ A <$ B Small and TRUE, if $ a is strictly less than $ B. $ A> $ B is greater than TRUE if $ a is strictly greater than $ B. $ A <= $ B is less than or equal to TRUE, if $ a is less than or equal to $ B. $ A >=$ B is greater than or equal to TRUE if $ a is greater than or equal to $ B. 0x01 security questions 1. hash comparison Defect
Php will be used to process hash strings! =, = For hash comparison. If the hash value starts with 0e and is followed by a number and then compared with a number, it is interpreted as 0*10 ^ n or 0, it will be judged to be equal and bypass the logon process.
root@kali:~/tool# php -r 'var_dump("00e0345" == "0");var_dump("0e123456789"=="0");var_dump("0e1234abc"=="0");'bool(true)bool(true)bool(false)
When all the values are numbers, the loose comparison will perform the best effort mode. For example, 0e12345678 will be interpreted as 0*10 ^ 12345678, except that e is not all numbers, this can be seen from var_dump ("0e1234abc" = "0.
2 bool Spoofing
When json_decode and unserialize exist, some structures will be interpreted as bool type and will also cause spoofing. Sample json_decode code:
$json_str = '{"user":true,"pass":true}';$data = json_decode($json_str,true);if ($data['user'] == 'admin' && $data['pass']=='secirity'){print_r('logined in as bool'."n");}
Running result:
#!bashroot@kali:/var/www# php /root/php/hash.phplogined in as bool
Unserialize sample code:
$unserialize_str = 'a:2:{s:4:"user";b:1;s:4:"pass";b:1;}';$data_unserialize = unserialize($unserialize_str);if ($data_unserialize['user'] == 'admin' && $data_unserialize['pass']=='secirity'){print_r('logined in unserialize'."n");}
The running result is as follows:
#!phproot@kali:/var/www# php /root/php/hash.phplogined in unserialize
3. Digital Conversion Spoofing
$user_id = ($_POST['user_id']);if ($user_id == "1"){$user_id = (int)($user_id);#$user_id = intval($user_id);$qry = "SELECT * FROM `users` WHERE user_id='$user_id';";}$result = mysql_query($qry) or die('<pre>' . mysql_error() . '</pre>' );print_r(mysql_fetch_row($result));
Send user_id = 0.999999999999999999999 and the result is as follows:
Array( [0] => 0 [1] => lxx' [2] => [3] => [4] => [5] => )
The data of user_id is to be queried, but the result is the data of user_id = 0. Int and intval are both low when converting numbers. The following code is used:
if ($_POST['uid'] != 1) {$res = $db->query("SELECT * FROM user WHERE uid=%d", (int)$_POST['uid']);mail(...);} else {die("Cannot reset password of admin");}
If 1.1 is input, $ _ POST ['uid'] is bypassed. The user with uid = 1 can be operated. In addition, intval also has a best effort mode, that is, to convert all numbers until a non-number is encountered, if you use:
if (intval($qq) === '123456'){ $db->query("select * from user where qq = $qq")}
Attackers pass in 123456 union select version () for attack.
4 PHP5.4.4 Special Cases
One php modification in this version causes two numeric characters to overflow, resulting in equal comparison.
$ php -r 'var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000");'bool(true)3. digress:
There are also similar problems with the php strcmp function, which is explained in manual. int strcmp (string $ str1, string $ str2), str1 is the first string, str2 is the second string. If str1 is smaller than str2, <0 is returned. If str1> str2,> 0 is returned. If the two are equal, 0 is returned. What if str2 is an array?
$_GET['key'] = array();$key = "llocdpocuzion5dcp2bindhspiccy";$flag = strcmp($key, $_GET['key']);if ($flag == 0) {print "Welcome!";} else {print "Bad key!";}
Running result:
root@kali:~/php# php strcmp.phpPHP Warning: strcmp() expects parameter 2 to be string, array given in /root/php/strcmp.php on line 13Welcome!