知识点实操概要

CTF多种类型题目一应俱全

链接指路:

phpmd5不一样浅谈md5弱类型比拟和强碰撞 Java

https://www.hetianlab.com/cour.do?w=1&c=CCID2d51-5e95-4c58-8fc9-13b1659c1356&pk_campaign=toutiao-wemedia

复制上方链接立时体验

序言

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

基本知识

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

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

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

==比较

测试代码

<?phpif(isset($_POST['a'])andisset($_POST['b'])){if($_POST['a']!=$_POST['b']){if(md5($_POST['a'])==md5($_POST['b']))echo'flag';elseecho'youarewrong';}elseecho"请输入不同的a,b值";}

解法1

由于md5不能加密数组,在加密数组的时候会返回NULL

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

解放2

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

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

s1502113478a0e861580163291561247404381396064s1885207154a0e509367213418206700842008763514s1836677006a0e481036490867661113260034900752s155964671a0e342768416822451524974117254469s1184209335a0e072485820392773389523109082030

===比较

<?phpif(isset($_POST['a'])andisset($_POST['b'])){if($_POST['a']!=$_POST['b']){if(md5($_POST['a'])===md5($_POST['b']))echo'flag';elseecho'youarewrong';}elseecho"请输入不同的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-pywj.txt-o1.txt2.txt

测试

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

<?phpfunctionreadmyfile($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加密8e4ef6c69a337c0de0208455ee69a416url编码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%C4P%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加密8e4ef6c69a337c0de0208455ee69a416url编码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编码后的两个字符串不完备相同,知足我们输入两个不同参数的须要。

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

<?phpif((string)$_GET['a']!==(string)$_GET['b']&&md5($_GET['a'])===md5($_GET['b'])){echo"youareright";}else{echo"youarewrong";}

HECTF ezphp

源码

<?phperror_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("md5iswrong");}}else{die('str1notnumber');}}?>

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

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

不雅观察源码,哀求传入四个参数,首先param1===param2,由于没有别的限定,以是我们可以传入两个数组。
对付是str1和str2,首先str1只能是数字,且末了b,但md5_1 != md5_2,以是我们不能传入两个md5加密后以0e开头的字符串。

又由于会将md5加密后的str1和str2中的cxhp更换成0123,也便是说c会被更换成0,以是一个ce开头的字符串会被更换成0e开头的字符串。

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

布局脚本

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

<?phpfor($a=1;$a<=1000000000;$a++){$md5=md5($a);if(preg_match('/^ce\d+$/',$md5)){echo$a;echo"\n";echo$md5;echo"\n";}}

这是进一步优化的脚本

<?phpfor($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";}}?>

实战演习训练

<?phpfunctionrandom(){$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,youareright";}else{print"youarewrong";}}?>

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

快复制“https://www.hetianlab.com/cour.do?w=1&c=CCID2d51-5e95-4c58-8fc9-13b1659c1356&pk_campaign=toutiao-wemedia ”做靶场练习