PHP弱类型比较漏洞

PHP弱类型比较漏洞

一、弱类型比较

<?php

var_dump("admin" == 0);  //true
var_dump("1admin" == 1);  //true
var_dump("admin1" == 1);  //false
var_dump("admin1" == 0);  //true
var_dump("0e123456" == "0e445567");  //true

?>

二、Hash比较

<?php
    
//var_dump("0e123456789012345678901234567890" === "0");  //false 
//var_dump("0e123456789012345678901234567890" == "0");  //true

$pass = $_GET['password'];
$password = "0e342768416822451524974117254469";

if (md5($pass) == $password) {
    echo "flag{xxx--xxx--xxx}";
}
else{
    echo "error";
}

?>

这种情况,基于上面的 0e 开头的弱类型hash值比较,那么此时我们只需要传入一个值使得md5处理之后的值可以以 0e 开头即可

image-20240907152250726

MD5加密后为 0e 开头的字符串

image-20240907152158049

三、布尔比较

<?php
$str = '{"user":true,"pass":true}';
$data = json_decode($str,true);

if($data["user"] == 'root' && $data['pass'] == 'myypass') {
    echo "登录成功 获得flag{xxx--xxx--xxx}";
}
else{
    echo "登录失败";
}
?>

image-20240907153250342

这里说明,true == "root" && true == "mypass" 是成立的

四、反序列化比较

$str = 'a:2:{s:4:"user";b:1;s:4:"pass";b:1;}';
$data = unserialize($str);

if($data["user"] == 'root' && $data['pass'] == 'myypass') {
    echo "登录成功 获得flag{xxx--xxx--xxx}";
}
else{
    echo "登录失败";
}

image-20240907154319950

说明完全可以通过反序列化构造布尔值来绕过字符串的判断

五、极值比较

<?php
$a = 987654321987654321123456789;
$b = 987654321987654321000000000;
var_dump($a == $b);

?>

image-20240907154749317

说明对于极值比较来说,PHP的比较是由范围限制的,超过一定范围后面的数字就无法比较了

六、switch比较

<?php
$num = '2woniu';
switch($num) {
    case 0:
        echo "0000";
        break;
    case 1:
        echo "1111";
        break;
    case 2:
        echo "2222";
        break;
    case 3:
        echo "3333";
        break;
    case 4:
        echo "4444";
        break;
    case 5:
        echo "5555";
        break;
    default:
    echo "error";
}


//数字型防SQL注入的简单方法
$source = '123456 and 1=1';
var_dump((int)$source);
?>

image-20240907160357902

说明 "2woniu" == 2 被判定成功了,而且SQL语法中对于字符串转整数

七、数组比较

当使用 in_array() 或 array_search() 函数时,如果 strict 参数没有设置为 true,则 in_array() 或 array_search() 将使用宽松比较

<?php
//数组比较
$array = ['a',0,1,2,'3'];
var_dump(in_array('abc',$array));
var_dump(array_search('abc',$array));
?>

image-20240907161125841

根据此结果可以判定 'abc' 存在于 $array 中,而且下标还是 1 ,这是为什么

原因分析

PHP 的 in_array 函数有一个可选的第三个参数 strict,它用于指定是否严格比较(即,比较时是否考虑类型)。默认为 false,即宽松比较(只比较值,不考虑类型)。而 array_search 在进行搜索时,如果找到匹配的值,会返回对应的键。

检查弱类型比较

如果在使用 in_array 时没有使用严格比较,它会将 'abc'$array 中的元素进行宽松比较。宽松比较时,PHP 可能会将 'abc' 转换为一个与 $array 中某个值匹配的类型,从而得到不符合预期的结果。

在你的数组 $array = ['a', 0, 1, 2, '3']; 中,我们可以注意到:

  • 'a' 是字符串。
  • 01 是整数。
  • '3' 是字符串 '3'

PHP 在宽松比较时会尝试将 'abc' 和数组中的每个值进行比较。由于 'abc' 不符合任何值的类型转换,理论上它不应该匹配任何值。

问题排查步骤

  1. 确认 PHP 配置:检查是否在 PHP 的配置中(如 php.ini)有其他的设置或自定义函数影响了比较行为。
  2. 代码完整性:确保没有其他代码或文件影响当前代码的输出。
  3. 更新 PHP 版本:尝试在不同版本的 PHP 中运行代码,以确定是否是版本特定的问题。

代码修正

如果你想确保严格比较,可以使用 in_array 的第三个参数 true

var_dump(in_array('abc', $array, true));

这样,它将进行严格比较,并且只会在值和类型都匹配时才返回 true

总结

在你提供的代码和输出结果中,'abc' 不应该匹配任何数组元素。请确认你的代码是否与输出一致,或检查其他潜在的干扰因素。如果依然有疑问,尝试在干净的 PHP 环境中重新运行代码以验证行为。

八、代码演练

<?php
//代码演练
$flag-"flag{xxxx-2020}";
if(empty($_GET['id'])){
    show_source(__FILE__);
    die();
}
else{
    $a ="www.woniuxy.com";
    $id = $_GET['id'];
    @parse_str($id);
    if($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
        echo $flag;
    }
    else{
        exit("no no");
    }
}
?>

我们知道 QNKCDZO 经过 md5 处理后的值为 0e830400451993494058024219903391 就是0e 开头的字符串

所以我们只需要传值时传入md5处理后可以以 0e 开头的值就可以,上面列出了很多

image-20240907164418023

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值