打开页面只有一个滑稽的小表情
就需要去查看该页面的源代码(ctrl+u)发现是source.php
通过source.php(即将source.php添加到后边,删除前边的view-source:http://)得到PHP代码
PHP代码
https://blog.csdn.net/a370793934/article/details/103287013(代码分析较好理解)
<?php
highlight_file(__FILE__);//对文件进行 PHP 语法高亮显示
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];//白名单,只包含
source.php和hint.php
if (! isset($page) || !is_string($page))//isset函数是检测变量是否设置
{
echo "you can't see it";//echo:输出一个或多个字符串
return false;
}
if (in_array($page, $whitelist))//in_array():函数搜索数组中是否存在指定的值;
$page:规定要在数组搜索的值;
$whitelist:规定要搜索的数组。
{
return true;
}
$_page = mb_substr//mb_substr() 函数是返回字符串的一部分,substr() 函数只针对英
文字符,如果要分割的中文文字则需要使用 mb_substr()。
(
$page,//$page是一个普通的用户自定义的变量,一般指页码数,即上一页下一页.
0,
mb_strpos($page . '?', '?')//mb_strpos():返回要查找的字符串在别一个字符串中
首次出现的位置;$page . '?':要被检查的字串;'?':
要搜索的字符串。
);
if (in_array($_page, $whitelist))
{
return true;
}
$_page = urldecode($page);//urldecode:对字符串进行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'])// is_string:检测变量是否是字符串
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
根据PHP源代码 可以发现,能够访问source.php和hint.php文件 进入hint.php,得到一句话,猜测flag在ffffllllaaaagg
通过PHP代码可以发现这一段代码是最主要的 这里REQUEST接收一个file参数,如果file参数非空还是字符串并且checkFile()函数返回true 那么就利用include(),包含传入的file参数。
mb_substr(a,0,3)就是在a字符串里的第一位开始数3位,返回这3个字符形成的字符串。mb_strpos(a,b) 就是返回b在a中的第一个位置,没则false。
为什么要过滤这个?呢?因为到时要访问的是source.php后的目录的文件,所以形式为file=source.php?..(文件名),这个问号会过滤掉,所以可以用url编码。?=%3f。用url是因为后面有url解码函数urldecode()。
因为flag在ffffllllaaaagggg中
为了读到ffffllllaaaagggg
可以加?file=source.php?/ffffllllaaaagggg因为不知道ffffllllaaaagggg在哪个目录下
所以要在ffffllllaaaagggg前面一直加…/进行尝试
?file=source.php%253f…/ffffllllaaaagggg
为什么要构造两次编码?
因为服务器每次解析时会自带一次url解码,所以一次url编码是对付服务器的(?file=source.php%3f/ffffllllaaaagggg),而另一次编码就是对付checkFile()函数中的urldecode()的(?file=source.php%253f/ffffllllaaaagggg)。
?file=source.php%3f../../../../../ffffllllaaaagggg
?file=source.php%253f../../../../../ffffllllaaaagggg
其中%3f就是?,/…/…/…/…/(两个点),是目录穿越。简单意思就是能直接到达文件,中间目录可以不用知道。ffffllllaaaagggg是在hint.php里面的
为什么上述两种都可以得到flag?
URL对?的编码是%3f,对%3f的编码是%253f 所以结果就一样了
$在php语言里是变量定义的标志符号,所有的变量前面都要加$符号。