Dedecms5.7修改前台登陆密码漏洞复现

准备工作

1.搭建dedecms5.7

从网上下载dedecms5.7源码,找到了里面uploads文件夹,改名成dedecms5.7

image-20211222201340553利用phpstudy在win10本地搭建dedecms网站,将dedecms5.7文件夹置于WWW文件夹下

123

在浏览器输入localhost/dedecms5.7/install/index.php进行安装

image-20211223110008129

image-20211222201626628

一路按默认继续,直到遇到数据库设定页面:

image-20211222194129901

按照你phpstudy的mysql数据库密码修改后,按继续

image-20211222194055695

到这里先进网站后台

image-20211222194332914

利用默认账号密码admin admin登入

image-20211222194531863

然后在系统选项中找到系统基本参数,再选择会员设置,最后将是否开启会员功能选项改成

image-20211222195528960

最后不要忘了点 确定 保存更改,

image-20211222195834734

到此基本的搭建已经完成。

复现过程

先注册一个账号,

image-20211122221145876

随意填写信息,但是注意不要设置安全问题

image-20211122221514069

image-20211223112433324

image-20211223112459986

然后打开url:http://127.0.0.1/dedecms5.7/member/resetpassword.php

image-20211122221626957输入你想要修改的账号的密码,邮箱随便填写,用burpsuite抓包,:

image-20211223120433697

抓到的包:

image-20211223120615054

将post内容改为:

dopost=safequestion&id=1&userid=test&safequestion=0.0&safeanswer=&&vdcode=6t1w

为什么这么改?在之后的漏洞分析我会具体解释,在这里只要知道 safequestion是密保问题,safeanswer是密保问题答案,还有id = 1 意思是第一个注册的用户也就是我们刚刚注册的用户 test。

然后重发包,得到:

image-20211223120840362

image-20211223120929211

http://localhost/DedeCMS5.7/member/resetpassword.php?dopost=getpasswd&id=1&key=WeK8N6k0

在burpsuite上放包,然后再上面将这个url复制到浏览器打开,发现我们进入了修改密码界面,

image-20211223122253808

修改后,成功登入,

image-20211223122321372

漏洞成因分析

漏洞成因

在用户密码重置模块,存在php弱类型比较,导致了如果用户没有设置密保问题的情况下可以绕过验证密保问题,直接修改密码(管理员账户默认不设置密保问题)。但是这里修改的密码是member表中的密码,即使修改了管理员密码也是member表中的管理员密码,仍是无法进入后台管理页面。

问题代码分析

dedecms的/member/resetpassword.php就是用来处理用户密码重置的问题的代码,问题出在75行开始处理验证密保问题处。

image-20211223110742960

我们可以发现,这段代码主要是从数据库中查询该用户的密保问题和密保答案,然后与用户输入的密保答案比较,但是在比较的时候使用了弱类型比较 **==**。

if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer)

我们查看empty函数可以知道,”0”(字符串0)被认为是空的,但是“0.0”(字符串0.0)不被认为为空,

image-20211223110537336

查询数据库用户数据可以知道,我们设置的test用户,safequestion从数据库取出默认为’0’(没有设置密保),safeanswer为空。

image-20211223113333076

结合上面分析的empty函数特性,如果我们输入 safequestion=‘0’ 会被判断为空,即会进入if内重新将$safequestion赋值为’’。而’从数据取出来的$row[safequestion]为’0’, 而’0’ != ‘’,这样就会打印”对不起,您的安全问题或答案回答错误”,故我们需要输入一个不会被empty判为空,且弱类型等于’0’的字符串。’00’、’000’、’0.0’以上这些都是可以的。因此我们要构造这样的POST数据:

dopost=safequestion&id=1&userid=test&safequestion=0.0&safeanswer=&&vdcode=6t1w

这样我们就会调用sn函数,这里注意成功调用sn的函数里将 $send设置成了’N’:

sn($mid, $row['userid'], $row['email'], 'N');

接着查看sn函数源码,它在member/inc/inc_pwd_functions.php的155行,

image-20211223114441163

image-20211223114425143

再跟踪newmail,它与sn在同一个php里,

image-20211223114651381

在newmail,我们分析代码可以知道,在sn函数中将 $send设置成了’N,其实就是生成了暂时密码并插入了数据库中,并跳转到修改密码页面

else if ($send == 'N')
{
return ShowMsg('稍后跳转到修改页', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);
}

这里打印出来的跳转链接就是修改密码页面的链接了,有了它我们就能修改该用户的密码了。