题目:
<?php
highlight_file(__FILE__);
error_reporting(0);
$val1 = @$_GET['val1'];
$val2 = @$_GET['val2'];
$val3 = @$_GET['val3'];
$val4 = @$_GET['val4'];
$val5 = (string)@$_POST['val5'];
$val6 = (string)@$_POST['val6'];
$val7 = (string)@$_POST['val7'];
if( $val1 == $val2 ){die('val1 OR val2 no no no');
}
if( md5($val1) != md5($val2) ){die('step 1 fail');
}
if( $val3 == $val4 ){die('val3 OR val4 no no no');
}
if ( md5($val3) !== md5($val4)){die('step 2 fail');
}
if( $val5 == $val6 || $val5 == $val7 || $val6 == $val7 ){die('val5 OR val6 OR val7 no no no');
}
if (md5($val5) !== md5($val6) || md5($val6) !== md5($val7) || md5($val5) !== md5($val7)){die('step 3 fail');
}if(!($_POST['a']) and !($_POST['b']))
{echo "come on!";die();
}
$a = $_POST['a'];
$b = $_POST['b'];
$m = $_GET['m'];
$n = $_GET['n'];if (!(ctype_alnum($a)) || (strlen($a) > 5) || !(ctype_alnum($b)) || (strlen($b) > 6))
{echo "a OR b fail!";die();
}if ((strlen($m) > 1) || (strlen($n) > 1))
{echo "m OR n fail";die();
}$val8 = md5($a);
$val9 = strtr(md5($b), $m, $n);echo PHP_EOL;
echo "<p>val8 : $val8</p>";
echo PHP_EOL;
echo "<p>val9 : $val9</p>";
echo PHP_EOL;
if (($val8 == $val9) && !($a === $b) && (strlen($b) === 5))
{echo "nice,good job,give you flag:";echo file_get_contents('/var/www/html/flag.php');
} step 3 fail
题目类型:WEB
题目名称:easy-hash
目的和要求:
1.了解hash碰撞
2.了解three way md5 collision
3.了解绕过md5校验
解题步骤:
1.打开浏览器,访问目标主机,查看源码
2.审计代码,判断需要的绕过
3.前四个md5效验直接使用赋值数组就可以绕过
4.后面是一个三向md5判断,使用https://natmchugh.blogspot.com/2014/11/three-way-md5-collision.html里面的方法,三张图片的md5相等
代码解释:
<?php
highlight_file(__FILE__);
error_reporting(0);
$val1 = @$_GET['val1']; //通过GET接收参数
$val2 = @$_GET['val2'];
$val3 = @$_GET['val3'];
$val4 = @$_GET['val4'];
$val5 = (string)@$_POST['val5']; //通过POST接收参数
$val6 = (string)@$_POST['val6'];
$val7 = (string)@$_POST['val7'];
if( $val1 == $val2 ){ //弱比较判断die('val1 OR val2 no no no');
}
if( md5($val1) != md5($val2) ){ //判断是否相等,若判断die('step 1 fail');
}
if( $val3 == $val4 ){ //若比较判断die('val3 OR val4 no no no');
}
if ( md5($val3) !== md5($val4)){ //弱比较判断die('step 2 fail');
}
if( $val5 == $val6 || $val5 == $val7 || $val6 == $val7 ){ //三项md5判断,die('val5 OR val6 OR val7 no no no');
}
if (md5($val5) !== md5($val6) || md5($val6) !== md5($val7) || md5($val5) !== md5($val7)){die('step 3 fail');
}if(!($_POST['a']) and !($_POST['b'])) //判断a和b的值是否为空
{echo "come on!";die();
}
$a = $_POST['a'];
$b = $_POST['b'];
$m = $_GET['m'];
$n = $_GET['n'];if (!(ctype_alnum($a)) || (strlen($a) > 5) || !(ctype_alnum($b)) || (strlen($b) > 6)) //ctype_alnum判断变量是否都是数字和字符,这里判断是否都不是数字和字符。大于5也会进入if条件
{echo "a OR b fail!";die();
}if ((strlen($m) > 1) || (strlen($n) > 1)) //m和n的长度需要大于1就会进入if,所以可以等于1或者更小
{echo "m OR n fail";die();
}$val8 = md5($a); //对$a进行md5加密
$val9 = strtr(md5($b), $m, $n); //对变量b进行md5加密,然后strtr对加密后$m的值对应的加密后$b中的内容,会被替换为$necho PHP_EOL;
echo "<p>val8 : $val8</p>";
echo PHP_EOL;
echo "<p>val9 : $val9</p>";
echo PHP_EOL;
if (($val8 == $val9) && !($a === $b) && (strlen($b) === 5)) //这条件是若比较val8和val9前两位都是0e,且a===b是true,a不等与b,所以有一个!,然后b的长度限制为了5
{echo "nice,good job,give you flag:";echo file_get_contents('/var/www/html/flag.php');
} step 3 fail
1.绕过第一个http://xxx/?val1[]=1&val2[]=2&val3[]=3&val4[]=5&m=b&n=0 //使$b加密后的b替换为0
2.绕过第二个要用三个图片中的二进制字节
3.使用md5碰撞出加密后两个值相等的md5加密前的5个字符,其中$b在md5加密后使用strtr函数进行了替换,b被替换为了0,所以$b在碰撞的时候只需要第二个字符为e就可以了,脚本如下
$a的碰撞脚本
import hashlib
import re
import string
list=string.digits+string.ascii_letters
for a in list:for b in list:for c in list:for d in list:for e in list:str1=a+b+c+d+evalue=hashlib.md5(str(str1).encode()).hexdigest()result=re.search(r"^[0][e][0-9]+$",value)if result:print(str1+'-----',result)
结果如下:
byGcY------ <re.Match object; span=(0, 32), match='0e591948146966052067035298880982'>$b的碰撞脚本
import hashlib
import re
import string
list=string.digits+string.ascii_letters
for a in list:for b in list:for c in list:for d in list:for e in list:str1=a+b+c+d+evalue=hashlib.md5(str(str1).encode()).hexdigest()result=re.search(r"^\w[e][0-9]+$",value)if result:print(str1+'------',result)
结果如下:
1RKnJ------ <re.Match object; span=(0, 32), match='be629474301316105422602603643091'>
最终的payload为:
import request
import re
url='http://xxxx/?val1[]=1&val2[]=2&val3[]=3&val4[]=4&m=b&n=0'
#因为是val5-7是POST传参,所以要顶一个data存放要传入的数据,然后用post方法传入
with open('./upload/three_md5_1.jpg','rb') as f:val5=f.read() //val5就是读取所有的图片中二进制的内容
with open('./upload/three_md5_2.jpg','rb') as f:val6=f.read()
with open('.upload/three_md5_3.jpg','rb') as f:val6=f.read()
data={'val5':val5, #这里的val5是对应了with中的val5'val6':val6,'val7':val7,'a':'byGcY','b':'1RKnJ'
}
result=request.post(url=url,data=data)
flag=re.search(r'(flag{.*})',r.text) #点是除了空字符以外所有,*是多次匹配,多个,这里用了一个捕获组
if flag:print(flag.group(1)) //括号里面是一个捕获组,这里可以不用不用捕获组会获取完整的字符串