让数据变成合法的 JSON
感谢 Rina 带来的奇妙知识点!
题目情境:
1 2 3 4 5
| <?php highlight_file(__FILE__);
echo json_decode(file_get_contents($_POST["file"]));
|
json_decode 会把JSON 格式的字符串,转成 PHP 可用的数据类型。如果 JSON 不合法,json_decode 会返回 null。也就是说我们要用 json 的格式读取字符串类型的 flag。
https://github.com/ambionics/wrapwrap
wrapwrap 是一个自动生成复杂 php://filter 链的工具。当我们只能控制 file_get_contents($_POST['url']) 里面的参数,需要让文件内容符合某种格式(比如 JSON/XML),才能被程序显示出来,我们需要让在文件内容前后 加上特定的前缀和后缀,让数据变成合法的 JSON 或 XML。wrapwrap 这个脚本可以自动帮我们完成这件事。
示例命令:
./wrapwrap.py /etc/passwd '{"message":"' '"}' 1000
第一个单引号里面是前缀,第二个单引号里面是后缀,1000 是要读的参数长度。
但是我们这里直接把/etc/passwd 改成/flag 也是读不出来的,不是脚本的问题, 而是 json_decode 本身的特性:
1 2 3
| echo json_decode("{'message':'123'}"); echo json_decode('123'); echo json_decode(123);
|
可以发现只会打印后面两个 123。
json_decode 只会打印字符串,而不会打印完整的 json 对象。
所以这里把./wrapwrap.py /flag '"' '"' 50生成的 chain.txt 放到参数里面就行。
用 JSON 的 Unicode 字符绕过正则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?php error_reporting(0); if (isset($_GET['source'])) { show_source(__FILE__); exit(); } function is_valid($str) { $banword = [ '\.\.', '(php|file|glob|data|tp|zip|zlib|phar):', 'flag' ]; $regexp = '/' . implode('|', $banword) . '/i'; if (preg_match($regexp, $str)) { return false; } return true; } $body = file_get_contents('php://input'); $json = json_decode($body, true); if (is_valid($body) && isset($json) && isset($json['page'])) { $page = $json['page']; $content = file_get_contents($page); if (!$content || !is_valid($content)) { $content = "<p>not found</p>\n"; } } else { $content = '<p>invalid request</p>'; }
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{<censored>}', $content); echo json_encode(['content' => $content]);
|
\uXXXX可以在JSON中转义字符,\u后面代表的是十六进制的unicode编码。
这里过滤了 flag,我们要读 flag。正则表达式只认php这三个字符,JSON 认 unicode 编码,所以我们可以用 unicode 来绕过。
[HarekazeCTF2019]encode_and_encode JSON小技巧_ctf json-CSDN博客
json_decode函数详解_w3cschool
php裸文件包含 | Dar1in9’s Blog