深度了解md5弱类型比较和强碰撞


前言

在CTF中,md5的题目太常见了,虽然有很多这方面的文章,但相对来说比较零散,这里主要将自己学习和比赛时遇到的md5弱类型和强碰撞的题目从浅到深地梳理一下。

本文涉及知识点实操练习:浅谈md5弱类型比较和强碰撞 相关实验:Weekly CTF(本课程旨在提供一些CTF题目给对CTF感兴趣的朋友们,让大家通过这些题目学习到相关知识。)

基本知识

php中有两种比较的符号==与=====在进行比较的时候,如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行。

===在进行比较的时候,会先判断两种字符串的类型是否相等,再比较。

比较

0e开头且都是数字的字符串,弱类型比较都等于0。

数字的字符串

==比较

测试代码

 <?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

返回NULL

所以,我们可以传入两个数组

传入两个数组

解法2

可以传入两个md5加密后是0e开头的字符串,需要注意的地方是,这个以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。可以查找以0e开头md5加密相等的字符串,也可以自己编写代码,提供以下脚本。

<?php
for($a=1;$a<=1000000000;$a++){
 $md5 = md5($a);
 if(preg_match('/^0e\d+$/',$md5)){
echo $a;
echo "\n";
echo $md5;
echo "\n";
 }
}
传入两个md5加密后是0e开头的字符串
s1502113478a
0e861580163291561247404381396064

s1885207154a
0e509367213418206700842008763514

s1836677006a
0e481036490867661113260034900752

s155964671a
0e342768416822451524974117254469

s1184209335a
0e072485820392773389523109082030

flag

===比较

<?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:

也可以传入两个数组,但不再适合传入两个0e开头的字符串,因为===是md5的强碰撞,进行了严格的过滤。

传入两个数组

解法2:

使用md5加密后两个完全相等的两个字符串来绕过过滤。

如何生成两个不一样的字符串,但是MD5是一样的呢。参考如何用不同的数值构建一样的MD5后,我们可以使用快速MD5碰撞生成器来构建两个MD5一样,但内容完全不一样的字符串。

fastcoll_v1.0.0.5.exe.zip

构造

创建一个文本文件,写入任意的文件内容,命名为ywj.txt (源文件)

运行fastcoll输出以下参数。-p 是源文件,-o是输出文件

fastcoll_v1.0.0.5.exe -p ywj.txt -o 1.txt 2.txt
创建一个文本文件

测试

对生产的1.txt和2.txt文件进行测试

<?php 
functionreadmyfile($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>";
二进制md5加密 8e4ef6c69a337c0de0208455ee69a416

url编码 1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8EF%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C‍4P%C2%B7s%0F%C8t%F28%FAU%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9b4%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%9DFH%F1%25%AC%DF%FA%C4G%27uW%CFNB%E7%EF%B0



二进制md5加密 8e4ef6c69a337c0de0208455ee69a416

url编码 1%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%A3njn%FD%1A%CB%3A%29Wr%02En%CE%89%9A%E3%8E%C6%F1%BE%E9%EE3%0E%82%2A%95%23%0D%FA%CE%1C%F2%C4P%C2%B7s%0F%C8t%F28zV%AD%2C%EB%1D%D8%D2%00%8C%3B%FCN%C9%E24%DB%AC%17%A8%BF%3Fh%84i%F4%1E%B5Q%7B%FC%B9RuJ%60%B4%0D%B7%F9%F9%00%1E%C1%1B%16%C9M%2A%7D%B2%BBoW%02%7D%8F%7F%C0qT%D0%CF%3A%1DFH%F1%25%AC%DF%FA%C4G%27uW%CF%CEB%E7%EF%B0

可以看到,1.txt和2.txt文件二进制md5加密后的结果完全相同。由于1.txt和2.txt文件中含有不可见字符,所以需要将其url编码后使用。可以看到url编码后的两个字符串不完全相同,满足我们输入两个不同参数的需要。

url编码后的两个字符串不完全相同

当题目限制不能传入数组,只能传入字符串时,如下例题,就只能采用解法2.

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

HECTF ezphp

源码

<?php 
error_reporting(0);
highlight_file(__file__);
include('flag.php'); 
$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'); 
}
}

?>

首先查看一些strtr()函数的用法:

strtr() 函数转换字符串中特定的字符。

特定的字符

观察源码,要求传入四个参数,首先param1===param2,因为没有别的限制,所以我们可以传入两个数组。对于是str1和str2,首先str1只能是数字,且最后a==a==b,但md5_1 != md5_2,所以我们不能传入两个md5加密后以0e开头的字符串。

又因为会将md5加密后的str1和str2中的cxhp替换成0123,也就是说c会被替换成0,所以一个ce开头的字符串会被替换成0e开头的字符串。

可以想到只要找到两个md5加密后是ce开头的字符串,或者一个md5加密后是ce开头的字符串,一个md5加密后是0e开头的字符串就可以绕过过滤。

构造脚本

这是一开始的脚本,返回值少,且执行速度慢。

<?php
for($a=1;$a<=1000000000;$a++){
 $md5 = md5($a);
 if(preg_match('/^ce\d+$/',$md5)){
echo $a;
echo "\n";
echo $md5;
echo "\n";
 }
}
一开始的脚本

这是进一步优化的脚本

<?php
for($a = 1; $a <= 100000000; $a++) {
 $md5 = strtr(md5($a),'cxhp', '0123');
 if(preg_match('/^0e\d+$/', $md5)) {
echo $a;
echo "\n";
echo $md5;
echo "\n";
 }
}
?>
进一步优化的脚本
进一步优化的脚本

实战演练

<?php
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";
}
}

?>

观察代码,有一个rondom方法,返回的是一个随机数,在这道题中,不需要清楚返回的是什么内容,我们只要知道返回的是一串数字就可以了。传入两个参数a和b,要求传入的是字符串,b会经过md5加密。最后要让a.a.r == b。因为是弱类型比较,且只能传入字符串,想要的是两个0e开头的字符串进行比较,前面我们已经知道,以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。所以保证b。因为是弱类型比较,且只能传入字符串,想要的是两个0e开头的字符串进行比较,前面我们已经知道,以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。所以保证a以0e开头就可以了,因为r是一串数字,所以r是一串数字,所以a.r在php中还是可以被解析为0。因为r在php中还是可以被解析为0。因为b是参数b经过md5加密而来,所以我们传入md5加密后是0e开头的字符串即可。

传入md5加密

相關推薦

2023-09-13

才能触发的安全漏洞。分为无交互、弱交互和强交互三种类型。 远程:指在不安装应用或不实际接触设备的情况下利用漏洞实施攻击,包括通过网页浏览、阅读短信彩信、收发邮件、文件下载、无线网络通信(不包括通信距离

2022-05-03

enderTarget 为了让 RenderTarget 从设计上更好的扩展任意纹理类型,精简了纹理结构,其中 RenderTarget 的 colorTexture 和 depthTexture 属性类型使用 Texture  替代旧版的 RenderColorTexture 和 RenderDepthTexture。 物理更新 新增动态物理碰撞器

2023-11-24

库,可以编写接近底层的高效二进制代码。 静态和强类型:Fortran是一种静态和强类型的语言,这使得编译器能够在早期捕捉到许多编程错误。这也使得编译器能够生成高效的二进制代码。 易学易用:Fortran是一种相对简单

2023-07-09

速开发体验,也将不断提供更多丰富的项目实践经验。 了解更多有关 YMP 框架的内容,请访问官网:https://ymate.net  

2022-10-01

议,双方将就面向云原生的新一代系统软件关键技术开展深度合作和联合研发,力争在开源软件生态建设、学术论文、课程实践、推广应用等方面产出高质量的合作成果,为中国培养出更多优秀的系统软件人才。 Alluxio创始人

2023-07-08

器和推荐类型服务中。 当然,他们在 Django 基础进行了深度的定制修改,因此支持在自定义的 Python JIT 上运行,并使用 Facebook 开发的数据库(同样用于 IG 和 FB)。 这名工程师还表示,2019 年刚加入 Instagram 时,他们在生产环境

2024-09-21

面迈出了重要一步。JetBrains AI Assistant与多款JetBrains产品深度集成,能够以高度的适配性完成代码生成与重构、回答和解释代码相关问题、撰写文档和提交信息等工作,助力中国本土开发者提升效率和代码质量,实现生产力的全

2024-06-04

和技术人员投入其中。在科研人员中,大部分人的工作是深度学习算法设计,即利用开源的PyTorch或其他深度学习训练库,设计不同的深度网络结构,并在各种数据集上进行训练和评估。而在人工智能框架开发方面,例如优化计

2022-11-16

加任何功能的情况下出现体积大幅增加的情况。 Emerge 深度分析了耐克的 iOS 端应用程序,在 22.35.0 版本中,框架在 191.7MB 的安装大小中占了 163.7MB。而到了 22.36.1 版本,框架在 322.1MB 的总容量中激增到 293.8MB。注意在每个框架

2023-09-24

出一个对话框窗口,允许用户(取消)选择要显示的各种类型的数据包。 添加了“errno”程序来打印与错误代码相关的错误消息。 更新了内核的 MD5 hashing 函数以(正确)匹配更现代的 SHA1 和 SHA256 代码的用法和行为。 删除

2023-08-03

部分悬浮)。但据他所说,这颗晶体虽然存在抗磁性,但比较弱,也没有所谓的“零阻”,整体表现就像是半导体曲线。他认为,LK-99 就算具备超导相,也是微量的超导杂质,无法形成连续的超导通路。 据称,华中科技大学材

2024-08-20

区生态发展战略的深入实践,更是对技术创新与产业合作深度融合的积极探索。未来,openKylin将在更加广阔的舞台上,携手合作伙伴共绘生态发展新篇章。   展区互动:openKylin 2.0版本惊艳亮相 大会展区同样热闹非凡,openK

2023-06-12

一款简化Minio操作的开源框架。通过对原有 Minio Java SDK 的深度封装,简化 Minio API 使用复杂度,提升 Minio 使用的便捷性,降低 Minio 应用开发门槛。 MinIO 是一款高性能、分布式的对象存储系统。Minio这款开源的分布式对象存储服

2022-06-08

er::viewClasses(), 此方法使控制器能够控制可以响应的内容类型。 视图类可以定义静态方法 contentType() 来参与内容类型协商。 添加了 Query::expr() ,作为 Query::newExpr() 的替代方法。 QueryExpression::case() 构建器现在支持 then() 和 els