安全矩阵

 找回密码
 立即注册
搜索
查看: 898|回复: 0

渗透培训笔记:Hash比较缺陷

[复制链接]

179

主题

179

帖子

630

积分

高级会员

Rank: 4

积分
630
发表于 2023-11-19 19:18:25 | 显示全部楼层 |阅读模式
渗透培训笔记:Hash比较缺陷
开发人员在对比Hash字符串的时候常用到等于(==)、不等于(!=)进行比较。如果Hash值以0e开头,后面都是数字,当与数字进行比较时,就会被解析成0 × 10n,会被判断与0相等,使攻击者可以绕过某些系统逻辑。

    Hash一般翻译成“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射,pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。

var_dump('0e123456789'== 0);    //bool(true)
var_dump('0e123456789'== '0');  //bool(true)
var_dump('0e1234abcde'== '0');  //bool(false)

当密码经过散列计算后可能会以0e开头。下面代码在进行密码判断时可以绕过登录逻辑。

<?php
  $username = $_POST['username'];
  $password = $_POST['password'];
  $userInfo = getUserPass($username);
  //当userInfo中的密码以0e开头时,随意构造password即可登录系统。
  if($userInfo['password']==md5($password)){ //Hash比较缺陷
       echo '登录成功';
  }else{
       echo '登录失败';
  }

使用hash_equals()函数比较Hash值,可以避免对比被恶意绕过。hash_equals()函数要求提供的两个参数必须是相同长度的字符串,如果所提供的字符串长度不同,会立即返回false。上面的代码应修改如下。

<?php
  $username = $_POST['username'];
  $password = $_POST['password'];
  $userInfo = getUserPass($username);
  //当userInfo中的密码以0e开头时,随意构造password即可登录系统。
  if(hash_equals($userInfo['password']),md5($password))){ //Hash比较缺陷
       echo '登录成功';
  }else{
       echo '登录失败';
  }

hash_equals()函数在PHP5.6中得到支持,如果PHP版本号低于5.6,自己写个这样的函数就可以了,代码如下:

if(!function_exists('hash_equals')){
    function hash_equals($a,$b){
        if(!is_string($a)||!is_string($b)){
            return false;
        }
        $len = strlen($a);
        if($len !== strlen($b)){
            return false;
        }
        $status = 0;
        for($i = 0; $i<$len; $i++){
            $status |= ord($a) ^ ord($b[$i]);
        }
        return $status === 0;
    }
}


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-28 03:30 , Processed in 0.011900 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表