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碰撞总结 <http://0sec.com.cn/2018-04-26/>
PHP弱类型安全问题总结 <https://blog.spoock.com/2016/06/25/weakly-typed-security/>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信