前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Writeup-北邮新生赛MRCTF-Web题:套娃

Writeup-北邮新生赛MRCTF-Web题:套娃

作者头像
Y5neKO
发布2022-01-13 13:02:16
8200
发布2022-01-13 13:02:16
举报
文章被收录于专栏:Y5neKO博客Y5neKO博客

这道题名副其实,果真是套娃,一层一层把我头都绕晕了

原题地址:https://merak-ctf.site/challenges#%E5%A5%97%E5%A8%83

从题目已经看出他的套路了,打开题目地址一看,标准的开场没有什么意外

右键查看源码,发现有一段注释

可以观察出来又是一道if套娃语句,需要一层一层解

同样先将这段代码格式化

代码语言:javascript
复制
//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']的值赋给变量$query 关于$_SERVER['QUERY_STRING']获取的值:

1,http://localhost/aaa/ (打开aaa中的index.php) 结果:

$_SERVER['QUERY_STRING'] = ""; $_SERVER['REQUEST_URI'] = "/aaa/"; $_SERVER['SCRIPT_NAME'] = "/aaa/index.php"; $_SERVER['PHP_SELF'] = "/aaa/index.php";

2,http://localhost/aaa/?p=222 (附带查询)

结果: $_SERVER['QUERY_STRING'] = "p=222"; $_SERVER['REQUEST_URI'] = "/aaa/?p=222"; $_SERVER['SCRIPT_NAME'] = "/aaa/index.php"; $_SERVER['PHP_SELF'] = "/aaa/index.php";

3,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"] 获取查询 语句,实例中可知,获取的是?后面的值 $_SERVER["REQUEST_URI"] 获取 http://localhost 后面的值,包括/ $_SERVER["SCRIPT_NAME"] 获取当前脚本的路径,如:index.php $_SERVER["PHP_SELF"] 当前正在执行脚本的文件名

此段原文地址:https://www.cnblogs.com/mitang/p/3874291.html 感谢大佬的测试 然后我们再来看第一层判断条件为

代码语言:javascript
复制
if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 )

这段代码表示需要满足"或"语句 而其中的substr_count函数是用于计算子串在字符串中出现的次数 再看看第二层判断条件

代码语言:javascript
复制
if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t']))

我们需要同时满足两个条件,其中preg_match函数用于匹配正则表达式,这里需要通过get提交参数b_u_p_t,但是参照第一层提到的substr_count函数,所以get参数不能带下划线,这时我们可以用点来代替下划线,同时用%0a来进行过滤正则表达式的条件,最终get传递的参数为?b.u.p.t=23333%0a

根据提示进入secrettw.php,仍然是标准套路,提示需要本地才能访问

右键查看源码,发现一大堆注释,乍一看像乱码,实际上ctf里的注释大家也都知道是怎么回事,肯定不是毫无意义的,百度一查,发现是一种叫jother的编码,直接复制粘贴到浏览器控制台即可解码

执行后弹出了一段alert信息

根据提示用hackbar通过POST提交一个Merak参数

返回了一段代码,应该是secrettw.php的部分源码高亮

源码如下

代码语言:javascript
复制
Flag is here~But how to get it? <?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'])); }
?> 

可以简单的分析出secrettw.php的作用 首先用if(isset($_POST['Merak']))函数检测是否存在参数名为Merak的POST数据,如果不存在则执行下面的语句,如果存在则执行if中的highlight_file函数高亮显示源码

我们已经通过POST提交Merak知道了源码,后面就不用再提交POST了,不然会被highlight_file函数截断,继续看下面的语句,中间的change函数暂时不管,是转换字符用的,后面会提到 后面的$ip = getIp();应该是使用了头部的takeip.php中的函数来获取客户端ip,再将获取到的ip赋值给变量$ip 如果满足$ip!='127.0.0.1'则执行该if内的语句,但是这段语句没什么用,所以我们不用管,第二个if内的语句才是我们需要执行的 第二个if的判断条件为

代码语言:javascript
复制
if($ip === '127.0.0.1' && file_get_contents($_GET['2333']) === 'todat is a happy day' )

也就是说需要满足两个条件

第一个条件$ip === '127.0.0.1',这个很容易满足,只要让get_ip获取到的值为127.0.0.1就行了,一般只有XFF和Client-ip这两种方法,我们可以用burpsuite来提交

第二个条件file_get_contents($_GET['2333']) === 'todat is a happy day'

首先通过file_get_content函数将整个数据读入一个字符串中,但是后面的值使用的单引号,并且中间使用===来判断全等,所以,经过到百度上各种CTF技巧的查找,发现这里可以使用data:// 来进行转换,具体用法可以参考:https://www.php.cn/manual/view/285.html

格式为data://text/plain;base64,将todat is a happy day进行base64编码得到dG9kYXQgaXMgYSBoYXBweSBkYXk=,所以需要通过get提交一个名为2333的参数,值为data://text/plain;base64,dG9kYXQgaXMgYSBoYXBweSBkYXk=

第二个if内的语句

代码语言:javascript
复制
echo "Your REQUEST is:".change($_GET['file']);
echo file_get_contents(change($_GET['file']));

还用到了一个名为file的get参数,用于返回文件内容,我们需要知道flag.php的内容,所以这里需要file_get_content的文件是flag.php 但是这里要注意file_get_content函数不是直接使用的$_GET['file']的值,而是用到了上面说到的change函数来转换,我们来看一下change函数的作用

代码语言:javascript
复制
function change($v){ 
    $v = base64_decode($v); 
    $re = ''; 
    for($i=0;$i<strlen($v);$i++){ 
        $re .= chr ( ord ($v[$i]) + $i*2 ); 
    } 
    return $re; 
}

首先定义用法,然后将变量进行base64解码(这说明后面POST参数file的值必须先进行base64编码),然后通过一段for循环,这段for循环的作用是先将字符转换为ASCII码,再将ASCII码逐步+i*2,i初始值为0,然后再转回字符其中strlen函数作用是计算字符的数目,chr是把ASCII转成字符,ord是把字符转成ASCII数字经过对照ASCII码表和计算,我们需要传递到file参数的值为“fj]a&fb(flag.php经过change函数转换为fj]a&fb)”的base64值,也就是ZmpdYSZmXGI=

顺带一提,takeip.php经过change函数变换,我们需要提交的值为“t_g_af"bXp^”,不过我们用不上,有兴趣的可以自己试一试

所以,我们最终提交的两个get参数为

注意别忘了将ip改为127.0.0.1,这里get_ip用到的方法为Client-ip

burpsuite改包放行后返回页面,右键查看源码

得到flag:MRCTF{c323e009-6f72-410a-9dff-96686b411977}

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020年03月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档