浅谈md5弱类型比较和强碰撞
字数 1015 2025-08-15 21:33:44

MD5弱类型比较与强碰撞技术详解

一、PHP比较运算符基础

在PHP中,存在两种比较运算符:

  1. ==(弱类型比较)

    • 比较时会进行类型转换
    • 数字和字符串比较时,字符串会被转换为数值
    • 0e开头且都是数字的字符串,弱类型比较等于0
  2. ===(强类型比较)

    • 先比较类型是否相同
    • 类型不同直接返回false
    • 类型相同再比较值

二、MD5弱类型比较漏洞

漏洞原理

当使用==比较两个MD5哈希值时,PHP会进行类型转换,导致特定格式的哈希值会被视为相等。

利用方法

测试代码示例

if (isset($_POST['a']) and isset($_POST['b'])) {
    if ($_POST['a'] != $_POST['b']) {
        if (md5($_POST['a']) == md5($_POST['b'])) 
            echo 'flag';
        else 
            echo 'you are wrong';
    } else 
        echo "请输入不同的a,b值";
}

解法1:利用数组特性

  • MD5无法加密数组,加密数组会返回NULL
  • 可以传入两个不同的数组参数:
    a[]=1&b[]=2
    

解法2:利用0e开头的哈希值

  • 寻找两个不同字符串,其MD5值都以0e开头且后面全是数字
  • 这类哈希值在弱比较时会被视为科学计数法的0

已知0e开头的MD5值示例

s1502113478a -> 0e861580163291561247404381396064
s1885207154a -> 0e509367213418206700842008763514
s1836677006a -> 0e481036490867661113260034900752
s155964671a -> 0e342768416822451524974117254469
s1184209335a -> 0e072485820392773389523109082030

生成脚本

for($a=1; $a<=1000000000; $a++) {
    $md5 = md5($a);
    if(preg_match('/^0e\d+$/', $md5)) {
        echo $a . "\n" . $md5 . "\n";
    }
}

三、MD5强碰撞技术

漏洞原理

当使用===严格比较时,需要找到两个不同的输入,产生完全相同的MD5哈希值。

利用方法

测试代码示例

if (isset($_POST['a']) and isset($_POST['b'])) {
    if ($_POST['a'] != $_POST['b']) {
        if (md5($_POST['a']) === md5($_POST['b'])) 
            echo 'flag';
        else 
            echo 'you are wrong';
    } else 
        echo "请输入不同的a,b值";
}

解法1:利用数组特性(同上)

解法2:使用MD5碰撞生成器

  1. 使用工具fastcoll生成碰撞:

    fastcoll_v1.0.0.5.exe -p source.txt -o 1.txt 2.txt
    
  2. 验证碰撞:

function readmyfile($path) {
    $fh = fopen($path, "rb");
    $data = fread($fh, filesize($path));
    fclose($fh);
    return $data;
}

echo '二进制md5加密 '. md5((readmyfile("1.txt")));
echo "</br>";
echo 'url编码 '. urlencode(readmyfile("1.txt"));
echo "</br>";
echo '二进制md5加密 '.md5((readmyfile("2.txt")));
echo "</br>";
echo 'url编码 '. urlencode(readmyfile("2.txt"));
echo "</br>";
  1. 由于生成的二进制文件包含不可见字符,需进行URL编码后使用

四、进阶挑战与解决方案

案例1:限制只能传入字符串

题目代码

if((string)$_GET['a'] !== (string)$_GET['b'] && md5($_GET['a'])===md5($_GET['b'])) {
    echo "you are right";
} else {
    echo "you are wrong";
}

解决方案
必须使用MD5碰撞生成器生成的两个不同但MD5相同的字符串

案例2:HECTF ezphp

题目代码

$string_1 = $_GET['str1'];
$string_2 = $_GET['str2'];

if($_GET['param1']!==$_GET['param2'] && md5($_GET['param1'])===md5($_GET['param2'])) {
    if(is_numeric($string_1)) {
        $md5_1 = md5($string_1);
        $md5_2 = md5($string_2);
        if($md5_1 != $md5_2) {
            $a = strtr($md5_1, 'cxhp', '0123');
            $b = strtr($md5_2, 'cxhp', '0123');
            if($a == $b) {
                echo $flag;
            }
        } else {
            die("md5 is wrong");
        }
    } else {
        die('str1 not number');
    }
}

解决方案

  1. param1和param2传入两个数组
  2. str1必须是数字
  3. 需要找到两个字符串,其MD5值:
    • 不相等
    • 经过strtr转换后(c→0, x→1, h→2, p→3)变为以0e开头的数字字符串

优化查找脚本

for($a = 1; $a <= 100000000; $a++) {
    $md5 = strtr(md5($a), 'cxhp', '0123');
    if(preg_match('/^0e\d+$/', $md5)) {
        echo $a . "\n" . $md5 . "\n";
    }
}

案例3:随机数参与的弱比较

题目代码

function random() {
    $a = rand(133,600)*78;
    $b = rand(18,195);
    return $a+$b;
}
$r = random();

if((string)$_GET['a'] == (string)md5($_GET['b'])) {
    if($a.$r == $b) {
        print "Yes,you are right";
    } else {
        print "you are wrong";
    }
}

解决方案

  1. 使$_GET['a']0e开头
  2. $_GET['b']的MD5值也以0e开头
  3. 由于$r是数字,$a.$r仍会被解析为0

五、防御措施

  1. 始终使用===进行严格比较
  2. 避免直接比较哈希值,可比较原始数据
  3. 对用户输入进行严格过滤和类型检查
  4. 考虑使用更安全的哈希算法如SHA-256

六、工具与资源

  1. MD5碰撞生成器:fastcoll
  2. 在线MD5碰撞数据库
  3. 哈希值生成与验证工具

通过掌握这些技术,可以更好地理解MD5哈希函数的安全特性,并在CTF比赛和安全测试中有效应用。

MD5弱类型比较与强碰撞技术详解 一、PHP比较运算符基础 在PHP中,存在两种比较运算符: ==(弱类型比较) : 比较时会进行类型转换 数字和字符串比较时,字符串会被转换为数值 0e 开头且都是数字的字符串,弱类型比较等于0 ===(强类型比较) : 先比较类型是否相同 类型不同直接返回false 类型相同再比较值 二、MD5弱类型比较漏洞 漏洞原理 当使用 == 比较两个MD5哈希值时,PHP会进行类型转换,导致特定格式的哈希值会被视为相等。 利用方法 测试代码示例 : 解法1:利用数组特性 MD5无法加密数组,加密数组会返回NULL 可以传入两个不同的数组参数: 解法2:利用0e开头的哈希值 寻找两个不同字符串,其MD5值都以 0e 开头且后面全是数字 这类哈希值在弱比较时会被视为科学计数法的0 已知0e开头的MD5值示例 : 生成脚本 : 三、MD5强碰撞技术 漏洞原理 当使用 === 严格比较时,需要找到两个不同的输入,产生完全相同的MD5哈希值。 利用方法 测试代码示例 : 解法1:利用数组特性(同上) 解法2:使用MD5碰撞生成器 使用工具 fastcoll 生成碰撞: 验证碰撞: 由于生成的二进制文件包含不可见字符,需进行URL编码后使用 四、进阶挑战与解决方案 案例1:限制只能传入字符串 题目代码 : 解决方案 : 必须使用MD5碰撞生成器生成的两个不同但MD5相同的字符串 案例2:HECTF ezphp 题目代码 : 解决方案 : param1和param2传入两个数组 str1必须是数字 需要找到两个字符串,其MD5值: 不相等 经过strtr转换后(c→0, x→1, h→2, p→3)变为以0e开头的数字字符串 优化查找脚本 : 案例3:随机数参与的弱比较 题目代码 : 解决方案 : 使 $_GET['a'] 以 0e 开头 $_GET['b'] 的MD5值也以 0e 开头 由于 $r 是数字, $a.$r 仍会被解析为0 五、防御措施 始终使用 === 进行严格比较 避免直接比较哈希值,可比较原始数据 对用户输入进行严格过滤和类型检查 考虑使用更安全的哈希算法如SHA-256 六、工具与资源 MD5碰撞生成器:fastcoll 在线MD5碰撞数据库 哈希值生成与验证工具 通过掌握这些技术,可以更好地理解MD5哈希函数的安全特性,并在CTF比赛和安全测试中有效应用。