查看发现有一个source.php
文件
这里有一个hint.php
文件,访问一下看看
flag not here, and flag in ffffllllaaaagggg
那没事了,老老实实看代码吧
源码如下:
<?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\" />";
}
?>
if (! empty($_REQUEST['file']) //$_REQUEST['file']的值非空
&& is_string($_REQUEST['file']) //$_REQUEST['file']是字符串类型
&& emmm::checkFile($_REQUEST['file']) //将$_REQUEST['file']的值传到emmm类中的checkFile函数中进行校验(checkFile函数就是用来检查某一文件是否存在)
) {
include $_REQUEST['file']; //包含$_REQUEST['file']文件 (就是要进行文件包含)
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />"; //否则打印输出滑稽表情
}
也就是说:
这个if语句要求传入的file变量:
• 非空
• 类型为字符串
• 能够通过checkFile()函数校验
同时满足以上三个要求即可包含file中的文件,否则打印滑稽表情
highlight_file(__FILE__); //输出文件高亮显示
class emmm //定义一个emmm类
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //声明$whitelist变量(白名单)"source"=>"source.php","hint"=>"hint.php"是 $whitelist数组的键值对,source和hint是键名,source.php和hint.php是键值
if (! isset($page) || !is_string($page)) { //$page的值非空或者不是字符串
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {//这里是用于检测$page是否存在与$whitelist数组中
return true;
}
in_array() 函数搜索数组中是否存在指定的值
语法:in_array(search,array,type)
参数及描述
search 必需。规定要在数组搜索的值。
array 必需。规定要搜索的数组。
type 可选。如果设置该参数为 true,则检查搜索的数据与数组的值的类型是否相同。
mb_substr ( string $str ,
int $start
[, int $length = NULL
[, string $encoding = mb_internal_encoding() ]]
) : string
$_page = mb_substr( //mb_substr() 函数返回字符串的一部分
$page,0,mb_strpos($page . '?', '?') //mb_strpos():返回要查找的字符串在别一个字符串中首次出现的位置
//这里是找见$page中?第一次出现的位置
);
//这里整体的意思是返回$page字符串中从第一个字符开始到?的字符
mb_strpos():返回要查找的字符串在别一个字符串中首次出现的位
语法:mb_strpos (haystack ,needle)
参数:
haystack:要被检查的字符串。
needle:要搜索的字符串。
也就是从haystack中查找needle第一次出现的位置
注:第一个字符的位置是0,如果没有找到则返回false
mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] ) : string 函数返回字符串的一部分
参数及描述
str 必需。从该 string 中提取子字符串
start 必需。规定在字符串的何处开始
• 正数 - 在字符串的指定位置开始
• 负数 - 在从字符串结尾的指定位置开始
• 0 - 在字符串中的第一个字符处开始
length 可选。规定要返回的字符串长度。默认是直到字符串的结尾
• 正数 - 从 start 参数所在的位置返回
• 负数 - 从字符串末端返回
encoding 可选。字符编码。如果省略,则使用内部字符编码
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)) { //$_page中的值在是否存在于$whitekist中
return true;
}
echo "you can't see it";
return false;
}
}
三个函数的总结:
mb_strpos():返回要查找的字符串在别一个字符串中首次出现的位置(数字) mb_strpos (haystack ,needle )
haystack:要被检查的字符串。
needle:要搜索的字符串
mb_substr() 函数返回字符串的一部分 str 必需。从该 string 中提取子字符串。
start必需。规定在字符串的何处开始。
length 可选。规定要返回的字符串长度。默认是直到字符串的结尾。
in_array() 函数搜索数组中是否存在指定的值 in_array(search,array,type) 参数 描述
search 必需。规定要在数组搜索的值。
array 必需。规定要搜索的数组。
type 可选。如果设置该参数为true,则检查搜索的数据与数组的值的类型是否相同。
四个if语句
• 第一个if语句对变量进行检验,要求$page为字符串,否则返回false
• 第二个if语句判断$page是否存在于 $whitelist数组中,存在则返回true
• 第三个if语句判断截取后的$page是否存在于 $whitelist数组中,截取 $page中’?'前部分,存在则返回true
• 第四个if语句判断url解码并截取后的$page是否存在于 $whitelist中,存在则返回true
若以上四个if语句均未返回值,则返回false
有三个if语句可以返回true,第二个语句直接判断$page,不可用
第三个语句截取’?‘前部分,由于?被后部分被解析为get方式提交的参数,也不可利用
第四个if语句中,先进行url解码再截取,因此我们可以将?经过两次url编码,在服务器端提取参数时解码一次,checkFile函数中解码一次,仍会解码为’?’,仍可通过第四个if语句校验。(’?‘两次编码值为’%253f’),构造url:
source.php?file=source.php%253f../ffffllllaaaagggg
不行
尝试source.php?file=source.php%253f../../../../../ffffllllaaaagggg