DedeCMS代碼注入漏洞(CVE-2022-36216)
1. 簡述
漏洞涉及文件:
/uploads/dede/member_toadmin.php
/uploads/include/common.inc.php
整體流程簡述:
參數傳入流程
/uploads/include/common.inc.php
1. `_RunMagicQuotes()`
2. `addslashes($svar)`
下面的$id 值是通過參數傳入流程傳入進來的。
/uploads/dede/member_toadmin.php
1. `$arr_password[$id] = "{$timestamp}";`
2. `$content = "json_encode($arr_password);`
3. `$fp = fopen($filename, 'w')`
1. `$filename = DEDEDATA.'/password.data.php';`
5. `fwrite($fp, $content);`
漏洞代碼節選:
// /uploads/include/common.inc.php 文件處代碼
if (!defined('DEDEREQUEST'))
{
foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
foreach($$_request as $_k => $_v)
{
if($_k == 'nvarname') ${$_k} = $_v;
else ${$_k} = _RunMagicQuotes($_v);
}
}
}
// /uploads/include/common.inc.php 文件處代碼
function _RunMagicQuotes(&$svar)
{
if(!get_magic_quotes_gpc())
{
if( is_array($svar) )
{
foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v);
}
else
{
...
$svar = addslashes($svar);
}
}
return $svar;
}
// /uploads/dede/member_toadmin.php
if($dopost == "toadmin")
{
...
$filename = DEDEDATA.'/password.data.php';
if (file_exists($filename)) {
require_once(DEDEDATA . '/password.data.php');
$arr_password = json_decode($str_password, true);
}
...
$arr_password[$id] = "{$timestamp}";
$content = "<?phprn$str_password='".json_encode($arr_password)."';";
$fp = fopen($filename, 'w') or die("寫入文件 $filename 失敗,請檢查權限!");
fwrite($fp, $content);
fclose($fp);
}
2. 分析
漏洞成因:
在DedeCMS中, 首先會用_RunMagicQuotes()函數,把 $_GET, $_POST, $_COOKIE 這三種方式獲取到的用戶輸入過濾一遍。
然后在_RunMagicQuotes()函數中, 調用了PHP內置的addslashes()函數將獲取到的所有輸入進行轉義。
然后 json_encode() 函數會將反斜杠進行轉義, 這時候單引號就逃逸了 addslashes()函數的過濾, 逃逸了過濾的單引號, 和最開頭的單引號實現了閉合。如下圖所示
閉合掉單引號之后, 利用php拼接的性質, 就能傳入惡意函數了, 當 $id 的值為 '.phpinfo()?>時, 如下圖所示
3. 復現
1.首先打開注冊會員功能
找到本地文件
uploads/install/config.cache.inc.php, 將里面的$cfg_mb_open = 'N'; 改為 $cfg_mb_open = 'Y';。
2.然后注冊一個會員(就在主頁上)
3.前往后臺頁面, 找到會員 -> 注冊會員列表 -> 提升。點擊提升按鈕, 按照提示填寫表格。填寫完畢之后, 暫時先不要點擊確定提升按鈕。
4.配置好瀏覽器代理, 打開BurpSuit或者類似的其它工具, 開啟Proxy模塊中的Intercept is on。然后再點擊上一步的確定提升按鈕, 這時候能夠捕獲到HTTP請求包, 請求體部分如下所示。
請注意這里的id參數, 這里就是漏洞觸發點, 將其修改為 3'.phpinfo()?>, 然后將數據包Forward 放回去
可以看到, 惡意代碼已經成功注入到
/uploads/data/password.data.php 文件中
訪問
/uploads/data/password.data.php 文件, 可以看到成功執行了注入進去的代碼。
4. 雞肋
讓我們回到最開始的那段漏洞代碼片段中, 里面有一段代碼是這樣寫的。
<?php
$filename = DEDEDATA.'/password.data.php';
if (file_exists($filename)) {
require_once(DEDEDATA . '/password.data.php');
$arr_password = json_decode($str_password, true);
}
這段代碼, 檢測了是否存在 password.data.php 這個文件, 如果存在的話, 則直接對password.data.php 文件的內容進行解碼。也就是說我們沒有辦法再往里面注入惡意代碼了。
那么問題來了,如果遇到網站已經有一個正常內容的password.data.php文件,這個漏洞就沒有任何意義了,畢竟這個漏洞只能在沒有這個文件的情況下才能觸發。食之無味,棄之可惜。
DedeCMS任意文件刪除漏洞(CVE-2022-30508)
1. 簡述
漏洞涉及文件: /uploads/dede/upload.php
漏洞具體代碼:
$delete = preg_replace("#^([.]*[/]*)*#", "", $delete);
...
if ($dopost === 'delete') {
$uploadTmp = DEDEDATA . '/uploadtmp';
if (unlink($uploadTmp . '/' . $delete)) {
echo 'success';
exit();
}
echo 'fail';
}
2. 分析
漏洞成因: preg_replace()對過濾不嚴格,導致依然能夠路徑穿越。然后通過代碼中的unlink()函數實現任意文件刪除。
3. 復現
首先在根目錄下新建一個test.txt文件
由于該漏洞涉及的代碼片段比較簡單,直接使用內置的參數輸入方式輸入參數,這里選擇的是$_GET傳參
/uploads/dede/upload.php?dopost=delete&delete=/Rebmal/../../../test.txt
可以看到已經成功刪除了test.txt文件。
4. 建議
請升級到最新版本。