知识点实操概要
CTF多种类型题目一应俱全
链接指路:
https://www.hetianlab.com/cour.do?w=1&c=CCID2d51-5e95-4c58-8fc9-13b1659c1356&pk_campaign=csdn-wemedia
复制上方链接马上体验
前言
在CTF中,md5的题目太常见了,虽然有很多这方面的文章,但相对来说比较零散,这里主要将自己学习和比赛时遇到的md5弱类型和强碰撞的题目从浅到深地梳理一下。
基本知识
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
所以,我们可以传入两个数组
解放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";
-
}
-
}
-
s1502113478a
-
0e861580163291561247404381396064
-
-
s1885207154a
-
0e509367213418206700842008763514
-
-
s1836677006a
-
0e481036490867661113260034900752
-
-
s155964671a
-
0e342768416822451524974117254469
-
-
s1184209335a
-
0e072485820392773389523109082030
-
===比较
-
<?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
-
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>";
-
-
二进制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%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加密
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编码后的两个字符串不完全相同,满足我们输入两个不同参数的需要。
当题目限制不能传入数组,只能传入字符串时,如下例题,就只能采用解法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只能是数字,且最后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.$r == $b。因为是弱类型比较,且只能传入字符串,想要的是两个0e开头的字符串进行比较,前面我们已经知道,以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。所以保证$a以0e开头就可以了,因为$r是一串数字,所以$a.$r在php中还是可以被解析为0。因为$b是参数b经过md5加密而来,所以我们传入md5加密后是0e开头的字符串即可。
转载:https://blog.csdn.net/qq_38154820/article/details/113750318