phpmyadmin 4.8.1 远程文件包含漏洞(CVE-2018-12613)
phpmyadmin 4.8.1 远程文件包含漏洞(CVE-2018-12613)
$target_blacklist = array (
'import.php', 'export.php'
);
// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
&& is_string($_REQUEST['target'])
&& ! preg_match('/^index/', $_REQUEST['target'])
&& ! in_array($_REQUEST['target'], $target_blacklist)
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
}
你需要:
1.$_REQUEST['target']不为空
2.$_REQUEST['target']是字符串
3.$_REQUEST['target']不以index开头
4.$_REQUEST['target']不在$target_blacklist中
‘import.php’, ‘export.php’
5.Core::checkPageValidity($_REQUEST['target'])为真
代码在libraries\classes\Core.php 443-476行
check函数本身
public static function checkPageValidity(&$page, array $whitelist = [])
{
if (empty($whitelist)) {
$whitelist = self::$goto_whitelist;
}
if (! isset($page) || !is_string($page)) {
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;
}
return false;
}
上面提到的whitelist就是白名单
$_page
是取出$page
问号前的东西,是考虑到target有参数的情况,只要$_page
在白名单中就直接return true
但还考虑了url编码的情况,所以如果这步判断未成功,下一步又进行url解码
看似能够非常完美地能够验证请求的文件是正确的,但是利用url二次编码就可以绕过了。
由于服务器会自动解码一次,所以在checkPageValidity()中,$page
的值一开始会是db_datadict.php%3f
,又一次url解码后变成了db_datadict.php?
,这次便符合了?
前内容在白名单的要求,函数返回true
但在index.php中$_REQUEST[‘target’]仍然是db_datadict.php%3f,而且会被include,通过目录穿越,就可造成任意文件包含
其实也就是说在返回true的前提下进行目录穿越就可以了,直接的?
,也是可以的