DedeCMS最新版前台任意用户登录漏洞分析

DedeCMS最近又有一个缺陷被爆出来,可以绕过一些判断条件从而导致前台任意用户登录,配合上一个重置密码漏洞,可以达到从前台登录管理员账户并修改dede_admin表里的密码,也就是真正修改了管理员密码。下面来简单分析一下。

0x01 概述

前几天爆出的DedeCMS最新版(20180109)任意用户密码修改漏洞存在有一定局限性,一是只能影响没有设置密保问题的用户,二是不能重置管理员admin的密码,原因当时也说了,管理员信息存在另一个表dede_admin中,而且管理员默认不允许从前台登录,所以就算更改了dede_memberadmin的密码也没法登录。但是最近又有一个缺陷被爆出来,可以绕过一些判断条件从而导致前台任意用户登录,配合上一个重置密码漏洞,可以达到从前台登录管理员账户并修改dede_admin表里的密码,也就是真正修改了管理员密码。

下面来简单分析一下

0x02 漏洞分析

先来看一下DedeCMS判断登录用户的逻辑
include/memberlogin.class.php:292

function IsLogin()
{
    if($this->M_ID > 0) return TRUE;
    else return FALSE;
}

跟进$this->M_ID看一下,170行

$this->M_ID = $this->GetNum(GetCookie("DedeUserID"));

GetNum()include/memberlogin.class.php:398

/**
*  获取整数值
*
* @access    public
* @param     string  $fnum  处理的数值
* @return    string
*/
function GetNum($fnum){
    $fnum = preg_replace("/[^0-9\.]/", '', $fnum);
    return $fnum;
}

正则匹配,去除了数字以外的字符,这里就可以构造一个利用点,一会儿再看

看一下GetCookie()
include/helpers/cookie.helper.php:54

关键点在这个判断条件

if($_COOKIE[$key.'__ckMd5'] != substr(md5($cfg_cookie_encode.$_COOKIE[$key]),0,16))

就是说从cookie中取到DedeUserID__ckMd5值,与md5($cfg_cookie_encode.$_COOKIE[$key])取前16位比较,相等才能进行下一步

我们知道admin的DedeUserID为1,现在需要知道DedeUserID__ckMd5的值

其实再思考一下,就算我们不知道admin的DedeUserID__ckMd5值,只要能过这个if条件就能绕过接着往下走了,那我们可不可以利用其他用户来绕过if条件呢?

在本程序中从数据库取用户的过程其实很简单,就是简单的查询语句Select * From #@__member where mid='$mid'。当我们利用其他用户的cookie通过了上面的if判断,然后修改mid为admin的id(1),就可以从前台登录到admin账户。
那么如何在请求过程中修改DedeUserID的值让它能和admin的id相等呢?

利用点一

我们使进入GetNum方法的参数为数字1+字母的形式,经过正则替换就会变成1,也就是$this->M_ID的值,然后带入数据库查询


$fnum1qqqq的情况,经过正则替换后值成为了1

利用点二

include/memberlogin.class.php:178有这么一行代码

$this->M_ID = intval($this->M_ID);

$this->M_ID进行了整数类型转换,假设注册一个用户名,经过intval转换后为1就能使查询条件变成Select * From #@__member where mid='1',也就取出了管理员在dede_member表里的密码,此时配合上一个漏洞,我们已经修改了dede_member中管理员的密码,只要在前台再进行一次修改密码操作,就能真正修改admin的密码。


这是调试的时候注册用户名为0000001的情况,经过intval转换后M_ID的值变成了1

下面看一下如何从前台登录admin账户

index.php里有一个最近访客记录的功能,

else
{
    require_once(DEDEMEMBER.'/inc/config_space.php');
    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, '/');

else条件是当访问页面http://127.0.0.1/dedecms/uploads/member/index.php?uid=1111传入的uid不为空时进入

当我们传入的last_vid为空的时候,$last_vid = $uid;uid是我们能控制的,所以我们就能控制传给PutCookie的参数,进入PutCookie方法

if ( ! function_exists('PutCookie'))
{
    function PutCookie($key, $value, $kptime=0, $pa="/")
    {
        global $cfg_cookie_encode,$cfg_domain_cookie;
        setcookie($key, $value, time()+$kptime, $pa,$cfg_domain_cookie);
        setcookie($key.'__ckMd5', substr(md5($cfg_cookie_encode.$value),0,16), time()+$kptime, $pa,$cfg_domain_cookie);
    }
}

在这里设置了last_vid__ckMd5的值

所以攻击流程已经明确了

  • 注册一个普通用户,用户名满足数字1+字母的形式,或者经过intval()后值为1
  • 访问用户主页,记录cookie中last_vid__ckMd5的值
  • 访问index页面,替换cookie中DedeUserIDDedeUserID__ckMd5的值,替换成我们注册的用户名和last_vid__ckMd5,就能登录到前台admin

0x03 漏洞利用

  1. 前台注册普通用户,这里注册一个1qqqq
  2. 访问/member/index.php?uid=1qqqq,获取last_vid__ckMd5的值
  3. 访问/member/index.php,替换DedeUserIDDedeUserID__ckMd5的值

    可以发现以admin身份成功登录到了前台
  4. 同样的,修改密码访问member/edit_baseinfo.php,还是要修改cookie值

    原登录密码就是我们利用上一个漏洞修改的密码,也就是dede_member表中的admin密码,这样就达到了真正修改admin的密码

    更新数据库的时候判断如果是管理员,就更新admin表中的数据

0x04 总结

这回有两处可导致判断条件的绕过,有时候一个漏洞影响力有限的时候也不能轻视,往往配合另一处缺陷就可以造成很大的危害

0x05 防护

暂时关闭会员注册功能,管理员设置安全问题,关注官方更新补丁及时升级

Spread the word. Share this post!

Meet The Author

Leave Comment