PHP弱类型安全

PHP 弱类型安全主要是由两部分组成: - 变量是弱类型,比较时会自动转换 - PHP 内置函数对于传入参数的松散处理

比较时的自动转换

PHP 中在使用 == 比较不同类型变量时会存在变量转换。如:

$a = null, $b = false; # true
$a = '', $b = null;    # true

# 数字比较时,会提取字符串中的第一个数字及其相邻数字
intval('abcd') == 0;
intval('8uo89j') == 8;

# 十六进制转换
"0x1e240"=="123456"     # true
"0x1e240"==123456       # true
"0x1e240"=="1e240"      # false

# hash 比较时, 出现0e\d+ 字符串转换为科学计数法后相同
"0e132456789" == "0e7124511451155" # true
"0e123456abc" == "0e1dddada"       # false
"0e1abc" == "0"                    # true

代码中应该避免类似如下情况:

if(intval($a) > 1000) {
    mysql_query("select * from news where id=".$a)
}
# 如果 a = 1001 union select...

内置函数的参数的松散性

内置函数的松散性说的是: 调用函数时传递给函数的参数是函数不接受的数据类型。

md5()

md5() 函数的定义是:string md5 (string $str [, bool $raw_output = false ] ) md5() 函数 中的需要是一个string类型的参数。但是当传递一个 array 时,md5() 函数不会报错,但会无法正确地求出 array 的 md5 值,这样就会导致任意2个 array 的 md5 值都会相等。也可以使得求出的md5 值为0e\d+ 形式

md5(array('a', 'b', c)) == null         # true
md5(array('a', 'b') == md5(array(1,2,3) # true
md5('240610708') == md5('QNKCDZO')      # true 

strcmp()

strcmp() 函数的定义是 int strcmp ( string $str1 , string $str2 ),如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。但当传入非字符串类型的数据的时,函数将发生错误并返回0

<?php
    $password = "***************";
    if(isset($_GET['password'])){
        if (strcmp($_POST['password'], $password) == 0) {
            echo "Right!!!login success";
        } else {
            echo "Wrong password..";
        }
    }
?>

# 传入 password[]= 即可

注:仅适用于 5.3 之前 PHP 版本

switch()

如果 switch 是数字类型的 case 的判断时,switch 将会其中的参数转换为 int 类型。如:

$i ="2abc";
switch ($i) {
case 0:
case 1:
case 2:
    echo "i is less than 3 but not negative";
    break;
case 3:
    echo "i is 3";
}

# 会输出 i is less than 3 but not negative

in_array()

in_array() 的定义是 bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] ),如果strict参数没有提供,那么in_array就会使用松散比较来判断 $needle 是否在 $haystack 中。当 $strict 的值为 true 时,in_array() 会比较 $needls 的类型和 $haystack 中的类型是否相同。如下:

$array = [0, 1, 2, '3'];
in_array('abc', $array); # true
in_array('1bc', $array); # true

array_search 函数有类似问题。

实战题

# SKCTF
<?php
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];
    $v3 = $_GET['v3'];
    if($v1 != $v2 && md5($v1) == md5($v2)){
        if(!strcmp($v3, $flag)){
            echo $flag;
        }
    }
}
?>

有两种思路,解决 md5($v1) == md5($v2):

  • $v1$v2 md5 操作之后是 0e\d+ 形式
  • $v1$v2 是数组。

因此 payload:

  • ?v1=s878926199a&v2=s155964671a&v3[]=
  • ?v1[]=1&v2[]=2&v3[]=

参考:

PHP弱类型&&md5碰撞总结

PHP弱类型安全问题总结

    标签:

发表评论

评论已关闭!
Comments are closed!

评论列表,共 0 条评论

    暂无评论