[HCTF 2018] WarmUp
源码看到 source.php 看一下源码,看到 hint.php 提示如下
<?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist = ["source"=>"source.php","hint"=>"hint.php"];if (! isset($page) || !is_string($page)) {echo "you can't see it";return false;}// 第一次直接匹配if (in_array($page, $whitelist)) {return true;}// 第二次去掉 ? 后的内容再匹配$_page = mb_substr($page, 0, mb_strpos($page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}// 第三次 urldecode 后再处理$_page = urldecode($page);$_page = mb_substr($_page, 0, mb_strpos($_page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}echo "you can't see it";return false;}}if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])) {include $_REQUEST['file'];exit;} else {echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";}
?> flag not here, and flag in ffffllllaaaagggg
这里的三次验证只是方便检测通过的,也就是说只要有一种可以过检测就行
include函数有这么一个神奇的功能:以字符 ‘/’ 分隔(而且不计个数),若是在前面的字符串所代表的文件无法被PHP找到,则PHP会自动包含‘/’后面的文件——注意是最后一个‘/’。
解释一下验证代码部分
mb_strpos($_page . '?', '?')
- $_page . '?':将 $_page 字符串末尾强行加上一个 ?,确保无论如何都能找到一个 ?。
- mb_strpos(..., '?'):使用 mb_strpos 查找第一个 ? 出现的位置(多字节安全函数,适用于 UTF-8 等编码)。
mb_substr($_page, 0, ...)
- 使用 mb_substr 从 $_page 的开头截取到第一个 ? 出现的位置(不包括 ? 本身)。
也就是说对于链接 http://xxx/source.php?file=hint%2Ephp?../../../../../../etc/passwd
在 $_REUEST['file'] 后链接变为 hint%2Ephp?../../../../../../etc/passwd
然后通过 checkfile 最终 in_array 判断为 hint.php
在Checkfile中 mb_strpos 查到的第一个 ? 为 hint.php? 后的问号,因此截取到的内容是 hint.php
在通过验证后,如果服务器配置不当(比如旧版 PHP),它可能最终加载为:
include "../../../../etc/passwd";
拿到flag flag{2a36cacb-9186-46bf-b85b-308555bf62a3}