dedecms v5.7 sp2前台任意用户登录(包括管理员)

时间:2022-07-22
本文章向大家介绍dedecms v5.7 sp2前台任意用户登录(包括管理员),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

dedecms v5.7 sp2前台任意用户登录(包括管理员)

前言

我们继续来说一下dedecms最新的几个漏洞,今天是一个前台任意用户登录的漏洞,该漏洞结合上一次提到的前台任意密码修改漏洞可以直接修改管理员的密码,剩下的就是找后台了,废话不多说,我们开始吧

漏洞版本

还是2018-1-09发行的最新版本

mark

漏洞影响

前台用户可以登录其他任意用户,包括管理员

漏洞利用条件

  1. 攻击者必须注册一个账户
  2. 开启了会员模块功能

漏洞复现

  1. 我们先注册一个用户,用户名为000001,密码为123(同样的,dedecms新建账户是需要审核的,我在本地搭建的,所以直接在数据库里做了一下修改)
  2. 登录我们的账户

mark

  1. /member/index.php?uid=000001,获取cookie中的last_vid__ckMd5

mark

  1. /member/index.php ,用burp替换DedeUserIDDedeUserID__ckMd5的值 ,分别为我们的用户名000001和last_vid__ckMd5

mark

  1. 成功登陆管理员账号

mark

代码分析

用户登录后会跳转到/member/index.php这个页面,所以我们第一步就是要分析访问/member/index.php的条件,我们直接看源码,从第24行起

mark

我标出来的那一句就是关键,只要IsLogin()函数返回true,那么我们就还可以确认某个用户登录了,然后就是根据M_ID的值来获取该页面的各种信息,例如用户名、短消息等,如下图:

mark

所以,我们可以初步确定,M_ID决定了我们登录的用户,IsLogin函数的返回值决定了是否能够登录成功。沿着这个思路,我们追踪一下IsLogin函数(includememberlogin.class.php中)

/**
    *  验证用户是否已经登录
    *
    * @return    bool
    */
   function IsLogin()
   {
       if($this->M_ID > 0) return TRUE;
       else return FALSE;
   }

可见这个函数还是对M_ID进行了判断,我们继续追踪M_ID,在同一个文件的170行处:

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

分别看一下这两个函数:

GetCookie(includehelperscookie.helper.php):

mark

这个函数作用大概就是更具输入的key值,获取cookie中相应的值(我标记出来的地方是重点)

GetNum(includememberlogin.class.php):

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

该函数的作用就是获取整数值,没什么特别的地方。我们把目光聚焦在getcookie函数我标出来的部分,那个判断本意是想要防止别人直接通过更改DedeUserID登录别人的账号(希望没人说错),加了刚刚那个判断语句,我们不仅仅需要DedeUserID的值,还要知道这个用户对应的DedeUserID__ckMd 值。

那可不可以我们自己注册一个用户,使它绕过if判断,并且它的M_ID的值与其他用户M_ID值相等,这样我们就可以登录到别人的账户上了。但是自己注册的账户的M_ID是来自cookie中的DedeUserID,而DedeUserID又是后台按序生成的,比如管理员的M_ID为1,第二个注册的人的M_ID为2。这么一来好像我们就不可能使两个账户的M_ID相等了。

但是includememberlogin.class.php的178行有这么一段代码:

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

这里对M_ID施加了intval,而intval在进行转换时会把000001转换为1,或者把1+字母的形式转换为1

var_dump(intval(000001));
var_dump(intval('1wwww'));
//D:wamp64wwwsome_practicetest3.php:2:int 1
//D:wamp64wwwsome_practicetest3.php:3:int 1

现在我们解决了伪造M_ID的问题,那么怎么使上面那个if语句成立呢?我们还是以000001这个账户为例,我们可以把DedeUserID更改为000001,然后就是需要再找一个substr(md5($cfg_cookie_encode.'000001'),0,16))的值,然后把这个值替换到DedeUserID__ckMd,就可以成功绕过登录。那哪里可以找到刚刚那个东西呢?

index.php中有一个功能就是会记录最后一个访客的数据,并存在cookie中的last_vid_ckMd5中

mark

我们来看一下这个值是怎么计算的,可能会是个惊喜!

我们从index.php的141行开始,有这么一段代码

mark

上面的代码中的last_id就是最后一个访问你的用户的id,来源如下:

$last_vid = GetCookie('last_vid');

上面的代码逻辑就是,如果你的空间还没有访客,那么last_vid就等于你url中传过去的uid,否则就直接取cookie中的那个last_vid。然后这个last_vid会被写入cookie,我们接着看PutCookie的处理方式

mark

可以看到last_vid_ckMd5的值其实就是我们前面需要的substr(md5($cfg_cookie_encode.'000001'),0,16)),所以我们只需要把这里的last_vid_ckMd5替换掉DedeUserID__ckMd,并把DedeUserID修改为000001就可以从前台登录到管理员账户,当然想登录其他账户也是同样的道理,就是注册用户的时候更改一下用户名。

总结

总的来说这个漏洞的可利用性比上一次好很多,上一次的任意用户密码修改漏洞的利用条件较为苛刻,而且这两个漏洞结合起来就可以达到修改管理员用户密码的目的,我也将在下一篇文章里复现