php代码审计(一)phpBug#69892

phpbug #69892

Description:
------------
var_dump([0 => 0] === [0x100000000 => 0]); // bool(true)

题目代码:

# Challenge


$users = array(
        "0:9b5c3d2b64b8f74e56edec71462bd97a" ,
        "1:4eb5fb1501102508a86971773849d266",
        "2:facabd94d57fc9f1e655ef9ce891e86e",
        "3:ce3924f011fe323df3a6a95222b0c909",
        "4:7f6618422e6a7ca2e939bd83abde402c",
        "5:06e2b745f3124f7d670f78eabaa94809",
        "6:8e39a6e40900bb0824a8e150c0d0d59f",
        "7:d035e1a80bbb377ce1edce42728849f2",
        "8:0927d64a71a9d0078c274fc5f4f10821",
        "9:e2e23d64a642ee82c7a270c6c76df142",
        "10:70298593dd7ada576aff61b6750b9118"
);

$valid_user = false;

$input = $_COOKIE['user'];
$input[1] = md5($input[1]);

foreach ($users as $user)
{
        $user = explode(":", $user);
        if ($input === $user) {
                $uid = $input[0] + 0;
                $valid_user = true;
        }
}

if (!$valid_user) {
        die("not a valid user\n");
}

if ($uid == 0) {

        echo "Hello Admin How can I serve you today?\n";
        echo "SECRETS ....\n";

} else {
        echo "Welcome back user\n";
}
  • 首先分析一下题目的逻辑

  • 第一部分


$users = array(
        "0:9b5c3d2b64b8f74e56edec71462bd97a" ,
       ······
);

$valid_user = false;

有一个users数组,这是一个定义了MD5哈希值的用户密码列表,并将valid_user初始化为false

  • 第二部分
$input = $_COOKIE['user'];
$input[1] = md5($input[1]);

以cookie的方式接受一个输入,并将接受的输入转换为数组进行检查,将数组第二项也就是密码项转换为md5

  • 第三部分
foreach ($users as $user)
{
        $user = explode(":", $user);
        if ($input === $user) {
                $uid = $input[0] + 0;
                $valid_user = true;
        }
}

在数组中遍历检查所用传入的用户和密码,如果匹配,把传入的账号赋值给uid,并添加值0以强制转换为数值数据类型,除此之外,标志$valid_user 设置为 true,这个部分就是一个验证登录的部分。

  • 第四部分
if (!$valid_user) {
        die("not a valid user\n");
}

if ($uid == 0) {

        echo "Hello Admin How can I serve you today?\n";
        echo "SECRETS ....\n";

} else {
        echo "Welcome back user\n";
}

这一部分的主要作用就是在根据uid来判断是否为管理员,如果uid为0,那么就是确认为管理员登录,否则就是user登录。

解题思路

我习惯于第一步泛读代码理清思路后采用逆推的方法解决问题
首先以管理员身份登陆成功要使uid==0(注意此处为弱等于),uid如何才能变成0,要到代码第三部分uid账号等于实际传入的账号(只有验证通过的传入的账号才能赋值传递给uid),那么只要使用账号0登录并且验证通过就可以了,接下来解决如何才能验证通过。传入的账号密码要与users数组中相匹配,解密一下数组中的md5值,发现只有用户5可以解密。
06e2b745f3124f7d670f78eabaa94809解密后为hund。
现在虽然使用用户0无法登录,但是我们使用用户5可以登录。

cookie:user[0]=5;user[1]=hund;

接下来的问题就变成了如何把user[0]=5变成user[0]=0
这就用到了phpbug#69892
简单来说,就是漏洞的利用就是键名user[4294967296]效果上等于user[0],但是要注意user[0]=5,它的值是5,使用user[4294967296]=5,他的值其实已经变成了空的。但是在后边

$uid = $input[0] + 0;

本来此处input[0]的值是空的,后边+0强制转换为int类型,uid就变成了0。
在比较的时候,input和user这两个数组时用的"=="在比较,那么我们可以不设置input[0]的值,而是用input[4294967296]来代替,然后比较的时候时用的input[4294967296]和input[1]来和列表中的用户比较,而uid又是通过input[0]+0来得到的,这样就完美绕过了它的限制。
关于phpBug#69892详细的信息还是参考相关资料,这里只给出了一种利用方法。

你可能感兴趣的:(PHP代码审计)