日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Dedecms 最新版漏洞收集并复现学习

發布時間:2025/3/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Dedecms 最新版漏洞收集并复现学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Dedecms 最新版漏洞收集并復現學習

以下漏洞復現均處于最新版dedecms即V5.7 SP2(當然從18年開始就已經沒有更新了,應該是沒有人維護了)。下載可以直接在官網下載。

1. 前臺任意用戶密碼修改

漏洞信息

無CVE, SSV-97074,提交時間:20180110

漏洞成因

在用戶密碼重置功能處,php存在弱類型比較,導致如果用戶沒有設置密保問題的情況下可以繞過驗證密保問題,直接修改密碼(管理員賬戶默認不設置密保問題)。值得注意的是修改的密碼是member表中的密碼,即使修改了管理員密碼也是member表中的管理員密碼,仍是無法進入管理

漏洞代碼分析

php弱類型比較問題很常見,在不同類型比較時,如果使用的是==,php會將其中一個數據進行強制轉換為另一個,比如'123a'就會被強制轉換成123。這樣就出現了弱類型比較問題,當然如果使用===判斷比較就不會出現問題了。常見比較如下

'' == 0 == false '123' == 123 //'123'強制轉換為123 'abc' == 0  //intval('abc')==0 '123a' == 123 //intval('123a')==123 '0x01' == 1 //被識別為十六進制 '0e123456789' == '0e987654321'  //被識別為科學計數法 [false] == [0] == [NULL] == [''] NULL == false == 0 true == 1

dedecms的/member/resetpassword.php就是用來處理用戶密碼重置的問題,問題出在75行開始處理驗證密保問題處。

else if($dopost == "safequestion") {$mid = preg_replace("#[^0-9]#", "", $id);$sql = "SELECT safequestion,safeanswer,userid,email FROM #@__member WHERE mid = '$mid'";$row = $db->GetOne($sql);if(empty($safequestion)) $safequestion = '';if(empty($safeanswer)) $safeanswer = '';if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer){sn($mid, $row['userid'], $row['email'], 'N');exit();}else{ShowMsg("對不起,您的安全問題或答案回答錯誤","-1");exit();}}

可以看到,這段代碼先是從數據庫取出相關用戶的密保問題及密保答案,在對用戶輸入做了一些處理后,進行了關鍵性的判斷if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer)?,就在這里用了弱類型判斷==。

首先我們知道,如果沒有設置密保的話safequestion從數據庫取出默認為'0',safeanswer為空。根據empty函數特性,'0'會被判斷為空,會進入重新將$safequestion賦值為''。而'0' != ''?,所以我們需要一個輸入即不使empty為空,且弱類型等于'0'的字符串。'00'、'000'、'0.0'以上這些都是可以的。

接下來safeanswer既然本來就為空,那么不輸入正好也就相等了。跟蹤sn函數

function sn($mid,$userid,$mailto, $send = 'Y') {global $db;$tptim= (60*10);$dtime = time();$sql = "SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'";$row = $db->GetOne($sql);if(!is_array($row)){//發送新郵件;newmail($mid,$userid,$mailto,'INSERT',$send);}//10分鐘后可以再次發送新驗證碼;elseif($dtime - $tptim > $row['mailtime']){newmail($mid,$userid,$mailto,'UPDATE',$send);}//重新發送新的驗證碼確認郵件;else{return ShowMsg('對不起,請10分鐘后再重新申請', 'login.php');} }

跟蹤newmail。

function newmail($mid, $userid, $mailto, $type, $send) {global $db,$cfg_adminemail,$cfg_webname,$cfg_basehost,$cfg_memberurl;$mailtime = time();$randval = random(8);$mailtitle = $cfg_webname.":密碼修改";$mailto = $mailto;$headers = "From: ".$cfg_adminemail."\r\nReply-To: $cfg_adminemail";$mailbody = "親愛的".$userid.":\r\n您好!感謝您使用".$cfg_webname."網。\r\n".$cfg_webname."應您的要求,重新設置密碼:(注:如果您沒有提出申請,請檢查您的信息是否泄漏。)\r\n本次臨時登陸密碼為:".$randval." 請于三天內登陸下面網址確認修改。\r\n".$cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid;if($type == 'INSERT'){$key = md5($randval);$sql = "INSERT INTO `#@__pwd_tmp` (`mid` ,`membername` ,`pwd` ,`mailtime`)VALUES ('$mid', '$userid', '$key', '$mailtime');";if($db->ExecuteNoneQuery($sql)){if($send == 'Y'){sendmail($mailto,$mailtitle,$mailbody,$headers);return ShowMsg('EMAIL修改驗證碼已經發送到原來的郵箱請查收', 'login.php','','5000');} else if ($send == 'N'){return ShowMsg('稍后跳轉到修改頁', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);}}else{return ShowMsg('對不起修改失敗,請聯系管理員', 'login.php');}}

可見在sn函數中將send參數設置了'N',其實就是生成了暫時密碼并插入了數據庫中,并進行跳轉:

else if ($send == 'N') {return ShowMsg('稍后跳轉到修改頁', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);}

跳轉鏈接就是修改密碼的鏈接了。

復現

在找回密碼處,點擊通過安全問題取回。

填寫信息并抓包,修改id和userid為想要重置密碼的對象,再加上以上分析內容,發包即可得到修改密碼url

進入該url,修改密碼。

修復意見

改為強類型比較===

2. 前臺文件上傳漏洞

漏洞信息

CVE-2018-20129, 提交時間:20181221

漏洞成因

管理員用戶前臺可以繞過限制上傳shell

漏洞代碼分析

漏洞在于用戶發布文章上傳圖片處。處理文件在/include/dialog/select_images_post.php

而上傳文件存在全局過濾/include/uploadsafe.inc.php

#/include/uploadsafe.inc.php $cfg_not_allowall = "php|pl|cgi|asp|aspx|jsp|php3|shtm|shtml"; if(!empty(${$_key.'_name'}) && (preg_match("#\.(".$cfg_not_allowall.")$#i",${$_key.'_name'}) || !preg_match("#\.#", ${$_key.'_name'})) ) {if(!defined('DEDEADMIN')){exit('Not Admin Upload filetype not allow !');} } $imtypes = array("image/pjpeg", "image/jpeg", "image/gif", "image/png", "image/xpng", "image/wbmp", "image/bmp" );if(in_array(strtolower(trim(${$_key.'_type'})), $imtypes)) {$image_dd = @getimagesize($$_key);if (!is_array($image_dd)){exit('Upload filetype not allow !');} }

可以看到名字中不得有上述字符,且限制了content-type。按道理說直接限制不得存在的字符,似乎沒有問題了,可在發布文章文件上傳的處理文件select_images_post.php中存在如下代碼:

$imgfile_name = trim(preg_replace("#[ \r\n\t\*\%\\\/\?><\|\":]{1,}#", '', $imgfile_name));if(!preg_match("#\.(".$cfg_imgtype.")#i", $imgfile_name)) #$cfg_imgtype = 'jpg|gif|png'; {ShowMsg("你所上傳的圖片類型不在許可列表,請更改系統對擴展名限定的配置!", "-1");exit(); }

再次過濾了圖片名,并且再次判斷如上三種文件類型是否存在其中。這么一次過濾,直接粗暴的將一些特殊字符替換為空,那么我們就可以通過特殊字符繞過上面的全局文件名不能包含php字符的限制,比如文件名為1.jpg.p*hp。

復現

登錄并進入member/article_add.php發布文章,選擇下面的富文本編輯器插入圖片

選擇好shell并上傳抓包

向如上分析修改文件名與content-type,即可返回shell地址

修復意見

在最后拼接文件名時再判斷一次。

3. DeDecms 任意用戶登錄

漏洞信息

漏洞編號:SSV-97087,提交時間:20180118

漏洞成因

dedecms的會員模塊的身份認證使用的是客戶端session,在Cookie中寫入用戶ID并且附上ID__ckMd5,用做簽名。主頁存在邏輯漏洞,導致可以返回指定uid的ID的Md5散列值。原理上可以偽造任意用戶登錄。

漏洞代碼分析

在/member/index.php中會接收uid和action參數。uid為用戶名,進入index.php后會驗證Cookie中的用戶ID與uid(用戶名)并確定用戶權限。

if($action == ''){include_once(DEDEINC."/channelunit.func.php");$dpl = new DedeTemplate();$tplfile = DEDEMEMBER."/space/{$_vars['spacestyle']}/index.htm";//更新最近訪客記錄及站點統計記錄$vtime = time();$last_vtime = GetCookie('last_vtime');$last_vid = GetCookie('last_vid');if(empty($last_vtime)){$last_vtime = 0;}if($vtime - $last_vtime > 3600 || !preg_match('#,'.$uid.',#i', ','.$last_vid.',')){if($last_vid!=''){$last_vids = explode(',',$last_vid);$i = 0;$last_vid = $uid;foreach($last_vids as $lsid){if($i>10){break;}else if($lsid != $uid){$i++;$last_vid .= ','.$last_vid;}}}else{$last_vid = $uid;}PutCookie('last_vtime', $vtime, 3600*24, '/');PutCookie('last_vid', $last_vid, 3600*24, '/');

我們可以看到當uid存在值時就會進入我們現在的代碼中,當cookie中的last_vid中不存在值為空時,就會將uid值賦予過去,$last_vid = $uid;,然后PutCookie。

那么這么說,我們控制了$uid就相當于可以返回任意值經過服務器處理的md5值。

而在接下來會驗證用戶是否登錄。

現在我們來看看,dedecms會員認證系統是怎么實現的:/include/memberlogin.class.php

//php5構造函數function __construct($kptime = -1, $cache=FALSE){global $dsql;if($kptime==-1){$this->M_KeepTime = 3600 * 24 * 7;}else{$this->M_KeepTime = $kptime;}$formcache = FALSE;$this->M_ID = $this->GetNum(GetCookie("DedeUserID"));$this->M_LoginTime = GetCookie("DedeLoginTime");$this->fields = array();$this->isAdmin = FALSE;if(empty($this->M_ID)){$this->ResetUser();}else{$this->M_ID = intval($this->M_ID);if ($cache){$this->fields = GetCache($this->memberCache, $this->M_ID);if( empty($this->fields) ){$this->fields = $dsql->GetOne("Select * From `#@__member` where mid='{$this->M_ID}' ");} else {$formcache = TRUE;}} else {$this->fields = $dsql->GetOne("Select * From `#@__member` where mid='{$this->M_ID}' ");}if(is_array($this->fields)){#api{{if(defined('UC_API') && @include_once DEDEROOT.'/uc_client/client.php'){if($data = uc_get_user($this->fields['userid'])){if(uc_check_avatar($data[0]) && !strstr($this->fields['face'],UC_API)){$this->fields['face'] = UC_API.'/avatar.php?uid='.$data[0].'&size=middle';$dsql->ExecuteNoneQuery("UPDATE `#@__member` SET `face`='".$this->fields['face']."' WHERE `mid`='{$this->M_ID}'");}}}#/aip}}//間隔一小時更新一次用戶登錄時間if(time() - $this->M_LoginTime > 3600){$dsql->ExecuteNoneQuery("update `#@__member` set logintime='".time()."',loginip='".GetIP()."' where mid='".$this->fields['mid']."';");PutCookie("DedeLoginTime",time(),$this->M_KeepTime);}$this->M_LoginID = $this->fields['userid'];$this->M_MbType = $this->fields['mtype'];$this->M_Money = $this->fields['money'];$this->M_UserName = FormatUsername($this->fields['uname']);$this->M_Scores = $this->fields['scores'];$this->M_Face = $this->fields['face'];$this->M_Rank = $this->fields['rank'];$this->M_Spacesta = $this->fields['spacesta'];$sql = "Select titles From #@__scores where integral<={$this->fields['scores']} order by integral desc";$scrow = $dsql->GetOne($sql);$this->fields['honor'] = $scrow['titles'];$this->M_Honor = $this->fields['honor'];if($this->fields['matt']==10) $this->isAdmin = TRUE;$this->M_UpTime = $this->fields['uptime'];$this->M_ExpTime = $this->fields['exptime'];$this->M_JoinTime = MyDate('Y-m-d',$this->fields['jointime']);if($this->M_Rank>10 && $this->M_UpTime>0){$this->M_HasDay = $this->Judgemember();}if( !$formcache ){SetCache($this->memberCache, $this->M_ID, $this->fields, 1800);}}else{$this->ResetUser();}}}

$this->M_ID等于Cookie中的DedUserID,我們繼續看看GetCookie函數

if ( ! function_exists('GetCookie')) {function GetCookie($key){global $cfg_cookie_encode;if( !isset($_COOKIE[$key]) || !isset($_COOKIE[$key.'__ckMd5']) ){return '';}else{if($_COOKIE[$key.'__ckMd5']!=substr(md5($cfg_cookie_encode.$_COOKIE[$key]),0,16)){return '';}else{return $_COOKIE[$key];}}} }

它不但讀了cookie還驗證了md5值。

這樣,由于index.php中我們可以控制返回一個輸入值和這個輸入值經過服務器處理后的md5值。那么如果我們偽造DedUserID和它對應的MD5就行了。

最后一個問題,因為我們上面是通過用戶名偽造ID的,用戶名為字符串而ID為整數,但好在在構造用戶類中將M_ID intval了一下$this->M_ID = intval($this->M_ID);?那么這么說,如果我們想偽造ID為1的用戶的Md5,我們只要在上面設置uid(用戶名)為'000001'即可。

復現

現在我們的思路就是

  • 先從member/index.php中獲取偽造的DedeUserID和它對于的md5
  • 使用它登錄
  • 訪問member/index.php?uid=0000001并抓包(注意cookie中last_vid值應該為空)。

    可以看到已經獲取到了,拿去當做DeDeUserID

    可以看到,登陸了admin用戶。

    修復意見

    M_ID被intval后還要判斷是否與未intval之前相同。

    4. Dedecms V5.7后臺的兩處getshell

    漏洞信息

    CVE-2018-9175,提交時間:20180401

    漏洞成因

    后臺寫配置文件過濾不足導致寫shell。

    漏洞代碼分析

    第一個

    在/dede/sys_verifies.php中的第152行處

    else if ($action == 'getfiles') {if(!isset($refiles)){ShowMsg("你沒進行任何操作!","sys_verifies.php");exit();}$cacheFiles = DEDEDATA.'/modifytmp.inc';$fp = fopen($cacheFiles, 'w');fwrite($fp, '<'.'?php'."\r\n");fwrite($fp, '$tmpdir = "'.$tmpdir.'";'."\r\n");$dirs = array();$i = -1;$adminDir = preg_replace("#(.*)[\/\\\\]#", "", dirname(__FILE__));foreach($refiles as $filename){$filename = substr($filename,3,strlen($filename)-3);if(preg_match("#^dede/#i", $filename)) {$curdir = GetDirName( preg_replace("#^dede/#i", $adminDir.'/', $filename) );} else {$curdir = GetDirName($filename);}if( !isset($dirs[$curdir]) ) {$dirs[$curdir] = TestIsFileDir($curdir);}$i++;fwrite($fp, '$files['.$i.'] = "'.$filename.'";'."\r\n");}fwrite($fp, '$fileConut = '.$i.';'."\r\n");fwrite($fp, '?'.'>');fclose($fp);

    可以看到,這里會將$refiles數組中的內容寫入配置文件modifytmp.inc中。

    dedecms對于輸入是全局過濾的,在/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{if( strlen($svar)>0 && preg_match('#^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_SESSION)#',$svar) ){exit('Request var not allow!');}$svar = addslashes($svar);}}return $svar; }if (!defined('DEDEREQUEST')) {//檢查和注冊外部提交的變量 (2011.8.10 修改登錄時相關過濾)function CheckRequest(&$val) {if (is_array($val)) {foreach ($val as $_k=>$_v) {if($_k == 'nvarname') continue;CheckRequest($_k);CheckRequest($val[$_k]);}} else{if( strlen($val)>0 && preg_match('#^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_SESSION)#',$val) ){exit('Request var not allow!');}}}//var_dump($_REQUEST);exit;CheckRequest($_REQUEST);CheckRequest($_COOKIE);foreach(Array('_GET','_POST','_COOKIE') as $_request){foreach($$_request as $_k => $_v){if($_k == 'nvarname') ${$_k} = $_v;else ${$_k} = _RunMagicQuotes($_v);}} }

    上面的$refiles就是注冊的外部變量,可見已經addlashes了而我們還是需要繞過fwrite($fp, '$files['.$i.'] = "'.$filename.'";'."\r\n");?實現注入shell,首先需要注入就必須閉合雙引號,在這里有個詭異的操作

    $filename = substr($filename,3,strlen($filename)-3);

    去掉了輸入的前三個字符,這樣就為我們寫shell制造了機會,當我們輸入\"?時經過addlashes會變成\\\",再去掉前三個字符就只剩下雙引號實現閉合。

    此時寫入shell后只要再找一個包含modifytmp.inc文件的文件就好了,全局搜索一下可以發現就在本文件/dede/sys_verifies.php

    第二個

    同樣是寫配置文件,位于/dede/sys_cache_up.php

    else if($step == 2) {include_once(DEDEINC."/enums.func.php");WriteEnumsCache();//WriteAreaCache(); 已過期ShowMsg("成功更新枚舉緩存,準備更新調用緩存...", "sys_cache_up.php?dopost=ok&step=3&uparc=$uparc");exit(); }

    跟進WriteEnumsCache()

    function WriteEnumsCache($egroup='') {global $dsql;$egroups = array();if($egroup=='') {$dsql->SetQuery("SELECT egroup FROM `#@__sys_enum` GROUP BY egroup ");}else {$dsql->SetQuery("SELECT egroup FROM `#@__sys_enum` WHERE egroup='$egroup' GROUP BY egroup ");}$dsql->Execute('enum');while($nrow = $dsql->GetArray('enum')) {$egroups[] = $nrow['egroup'];}foreach($egroups as $egroup){$cachefile = DEDEDATA.'/enums/'.$egroup.'.php';$fp = fopen($cachefile,'w');fwrite($fp,'<'."?php\r\nglobal \$em_{$egroup}s;\r\n\$em_{$egroup}s = array();\r\n");$dsql->SetQuery("SELECT ename,evalue,issign FROM `#@__sys_enum` WHERE egroup='$egroup' ORDER BY disorder ASC, evalue ASC ");$dsql->Execute('enum');$issign = -1;$tenum = false; //三級聯動標識while($nrow = $dsql->GetArray('enum')){fwrite($fp,"\$em_{$egroup}s['{$nrow['evalue']}'] = '{$nrow['ename']}';\r\n");if($issign==-1) $issign = $nrow['issign'];if($nrow['issign']==2) $tenum = true;}if ($tenum) $dsql->ExecuteNoneQuery("UPDATE `#@__stepselect` SET `issign`=2 WHERE egroup='$egroup'; ");fwrite($fp,'?'.'>');fclose($fp);if(empty($issign)) WriteEnumsJs($egroup);}return '成功更新所有枚舉緩存!'; }

    可以看到,直接從數據庫中讀取并寫入php文件中,從數據庫中取出后并沒有經過過濾。

    將shell寫進數據庫中https://172.16.180.130/dedecms/uploads/dede/stepselect_main.php?action=addenum_save&ename=123&egroup=;phpinfo();//&islogin=1

    復現

    因為包含是在同一個文件,所以直接輸入dede/sys_verifies.php?action=getfiles&refiles[]=123&refiles[]=\%22;phpinfo();die();//?就可以。

    修復意見

    更改前面的過濾條件

    5. 某cms v5.7 sp2 后臺文件上傳 getshell

    漏洞信息

    CVE-2019-8362,提交時間 20190216

    漏洞成因

    上傳zip文件解壓縮對于文件名過濾不周,導致getshell

    漏洞代碼分析

    /dede/album_add.php 175行驗證后綴

    $fm->GetMatchFiles($tmpzipdir,"jpg|png|gif",$imgs);

    進入函數:

    function GetMatchFiles($indir, $fileexp, &$filearr){$dh = dir($indir);while($filename = $dh->read()){$truefile = $indir.'/'.$filename;if($filename == "." || $filename == ".."){continue;}else if(is_dir($truefile)){$this->GetMatchFiles($truefile, $fileexp, $filearr);}else if(preg_match("/\.(".$fileexp.")/i",$filename)){$filearr[] = $truefile;}}$dh->close();}

    可以確定preg_match("/\.(".$fileexp.")/i",$filename)只是判斷了文件名中是否存在.jpg、.png、.gif中的一個,只要構造1.jpg.php就可以繞過。

    復現

    管理員用戶上傳壓縮了1.jpg.php這個shell的zip文件再解壓縮即可。這里

    修復意見

    加強過濾正則的書寫。

    同和上面,后臺dedecms后臺getshell真的很雞肋。

    總結

    以上是生活随笔為你收集整理的Dedecms 最新版漏洞收集并复现学习的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。