wonderkun's|blog

share with you!

04/20
14:54
代码控

php弱类型引发的安全问题

1.php的===和==
php的比较操作符有==(比较松散),===(完全等于,严格比较),在松散比较的时候,php会将他们的类型统一之后,再进行比较,会把字符转化为数字,非bool型转化为bool型,下面是一些例子

例子 名称 结果
$a == $b 等于 TRUE,如果类型转换后 $a 等于 $b。
$a === $b 全等 TRUE,如果 $a 等于 $b,并且它们的类型也相同。
$a != $b 不等 TRUE,如果类型转换后 $a 不等于 $b。
$a <> $b 不等 TRUE,如果类型转换后 $a 不等于 $b。
$a !== $b 不全等 TRUE,如果 $a 不等于 $b,或者它们的类型不同。
$a < $b 小与 TRUE,如果 $a 严格小于 $b。 $a > $b 大于 TRUE,如果 $a 严格大于 $b。
$a <= $b 小于等于 TRUE,如果 $a 小于或者等于 $b。 $a >= $b 大于等于 TRUE,如果 $a 大于或者等于 $b。

2.安全问题:
2.1 hash比较的缺陷:
php在处理hash字符串的时候会用到!=,==来进行hash比较,如果hash值以0e开头,后边都是数字,再与数字比较,就会被解释成010^n还是为0,就会被判断相等,绕过登录环节。看下面的例子
2015-11-28 10:57:43屏幕截图
当全是数字的时候,宽松的比较会执行尽力模式,如0e12345678会被解释成010^12345678,除了e不全是数字的时候就不会相等,这能从var_dump(“0e1234abc”==”0”)可以看出来。
下面是几个非常有用的hash值

   $ echo -n 240610708 | md5sum
    0e462097431906509019562988736854  -
    $ echo -n QNKCDZO | md5sum
    0e830400451993494058024219903391  -
    $ echo -n aabg7XSs | md5sum
    0e087386482136013740957780965295  

2.2 2.2 bool 欺骗

当存在json_decode和unserialize的时候,部分结构会被解释成bool类型,也会造成欺骗。json_decode示例代码


&amp;lt;?php
$json_str = '{"user":true,"pass":true}';  //定义一个json格式的数据   
$data = json_decode($json_str,true);  //进行json_decode  

if ($data['user'] == 'admin' &amp;amp;&amp;amp; $data['pass']=='secirity')  //会把字符串类型转化为bool型,进而相等  
{ 
print_r('logined in as bool'."n");

}
?&amp;gt;

root@kali:~/桌面# php php.php
logined in as bool

unserialize示例代码:

&amp;lt;?php
$unserialize_str = 'a:2:{s:4:"user";b:1;s:4:"pass";b:1;}';
$data_unserialize = unserialize($unserialize_str);
if ($data_unserialize['user'] == 'admin' &amp;amp;&amp;amp; $data_unserialize['pass']=='secirity')
{
print_r('logined in unserialize'."n");
}
?&amp;gt;

运行结果如下: root@kali:/var/www# php /root/php/hash.php
logined in unserialize

2.3 数字转换欺骗
看代码:

&amp;lt;?php
$id = ($_GET['id']);
if ($id == "1")
{
$id = (int)($id);
#$id = intval($id);
$qry = "SELECT * FROM `users` WHERE user_id='$id';";
}

echo $qry;

?&amp;gt;

如果我们传入 id=0.999999999999999999999999999999999999,那么我们就会绕过第一个等号的判断,因为==比较的时候会把0.9999999999999999999999999999这个浮点型转化为整型,然后等于1,但是int函数和intval函数,再转化为整数的时候,默认是转化为不大于这个数的最大整数,所以是0,这样就可能绕过判断,直接查询到管理员的信息
运行结果:
2015-11-28 11:28:34屏幕截图

再例如一下代码:

&amp;lt;?php 
//再例如这样的一个密码重置的操作  
//
if ($_POST['uid'] != 1) {  //判断是为了允许重置uid=1的密码 
    $res =' SELECT * FROM user WHERE uid='.(int)$_POST['uid'];


//do something; reset password  
//
echo  $res;  


} else {


    die("Cannot reset password of admin");

} 

运行结果:
2015-11-28 11:36:11屏幕截图
2015-11-28 11:42:45屏幕截图
传入uid=1.1就可以轻松的绕过第一个判断了

另外intval还有个尽力模式,就是转换所有数字直到遇到非数字为止,如果采用:

&amp;lt;?php
if (intval($qq) === 123456)
{
$db-&amp;gt;query("select * from user where qq = $qq")
} 
?&amp;gt;

攻击者传入123456 union select version()进行攻击。
2.4 PHP5.4.4 特殊情况
这个版本的php的一个修改导致两个数字型字符溢出导致比较相等

$ php -r 'var_dump("61529519452809720693702583126814" == "61529519452809720000000000000000");'
bool(true)

refer:http://blog.nsfocus.net/php-comparison-operators-security/
本文链接:http://xiaomange.meximas.com/?p=295
如果转载,请表明出处: