查看页面源代码
发现source.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\" />";
}
?>
分析如下:
首先明确是文件包含
明确whitelist:
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
之后:
if (! empty($_REQUEST['file']) //$_REQUEST['file']值非空
&& is_string($_REQUEST['file']) //$_REQUEST['file']值为字符串
&& emmm::checkFile($_REQUEST['file']) //能够通过checkFile函数校验
) {
include $_REQUEST['file']; //包含$_REQUEST['file']文件
exit;
} else {
echo "
";
//打印滑稽表情
}
总结下,对于file
要求:
checkFile()
函数的校验之后分析checkFile()
函数
highlight_file(__FILE__); //打印代码
class emmm //定义emmm类
{
public static function checkFile(&$page)//将传入的参数赋给$page
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];//声明$whitelist(白名单)数组
if (! isset($page) || !is_string($page)) {//若$page变量不存在或非字符串
echo "you can't see it";//打印"you can't see it"
return false;//返回false
}
if (in_array($page, $whitelist)) {//若$page变量存在于$whitelist数组中
return true;//返回true
}
$_page = mb_substr(//该代码表示截取$page中'?'前部分,若无则截取整个$page
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);//url解码$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 (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
即对$page
判断为字符串,否则返回flase,显示:you can’t see it
if (in_array($page, $whitelist)) {
return true;
}
即对$page
判断是否是在白名单中($whitelist
数组),存在,则返回ture
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
即判断截取后的$page
是否存在于$whitelist
数组中,截取$page
中?
前部分,存在则返回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;
}
即判断url解码并截取后的$page
是否存在于$whitelist
中,存在则返回true
若以上四个if语句均未返回值,则返回false
注意:第三个语句截取?
前部分,由于?
被后部分被解析为get方式提交的参数,也不可利用;第四个if语句中,先进行url解码再截取,因此我们可以将?
经过两次url编码,在服务器端提取参数时解码一次,checkFile函数中解码一次,仍会解码为?
,仍可通过第四个if语句校验。(?
两次编码值为%253f
)
另外,我们发现hint.php
查看发现:
flag在ffffllllaaaagggg中
于是,我们构造payload:
?file=source.php%253f/../../../../ffffllllaaaagggg
得到flag~
mb_substr() 函数返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。
mb_strpos — 查找字符串在另一个字符串中首次出现的位置
基于字符数执行一个多字节安全的 strpos() 操作。
第一个字符的位置是 0,第二个字符的位置是 1,以此类推。