织梦cms前台任意用户密码修改

基本信息

漏洞编号:SSV-97074
实验版本:dedecms v5.3
下载地址:http://www.dedecms.com/upimg/soft/2008/DedecmsV53-UTF8-Final.tar.gz
参考文章:https://www.seebug.org/vuldb/ssvid-97074
https://blog.csdn.net/qq_51569535/article/details/109211295
https://blog.csdn.net/l1028386804/article/details/48771375

前置知识

1.在php中进行不同类型数据比较是有以下特点

如果数据中有bool型,则全部转化为bool型比较,且true>false。
否则,如果有int型就转化为int比较。
否则,如果两边都是string型的纯数字,转为int比较。
否则就按string型比较。

2.举个例子
<?php
var_dump(0=='0.0'); // true
var_dump(0 == 'abc'); // true 
var_dump(1 == '1abc'); // true
var_dump('1e0'=='1e2'); // false
var_dump('0.0'==0); // true
var_dump('0.0'==''); //false

//还有下面这样的
if(md5('s878926199a')==0){
    echo 'true';
}
?>

因为 md5(‘s878926199a’)=0e545993274517709034328855841020就是0的n次方,所以还是等于0

<?php
if(strcmp('1a',1)){//此处比较为'1a'>1,strcmp与==比较方式不同('1a'==1为真)
    echo 'true';
}else {
    echo 'false';
}
?>

<?php
var_dump(in_array("1a", array(1,2,3))); //true
?>

以上In_array函数和array_search函数的问题可以在in_array函数后面加一个true选项,就能解决。

"0x1e240"=="123456"//true

"0x1e240"==123456//true

"0x1e240"=="1e240"//false

还存在一种十六进制余字符串进行比较运算时的问题。当其中的一个字符串是0x开头的时候,PHP会将此字符串解析成为十进制然后再进行比较,0×1240解析成为十进制就是123456,所以与int类型和string类型的123456比较都是相等。

漏洞分析

dedecms/member/resetpassword.php //71行

else if($dopost == "safequestion")
{
    $mid = preg_replace("#[^0-9]#", "", $id);
    $sql = "SELECT safequestion,safeanswer,userid,email FROM #@__member WHERE mid = '$mid'";
    $row = $db->GetOne($sql);
    if(empty($safequestion)) $safequestion = '';
    if(empty($safeanswer)) $safeanswer = '';
    if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer)
    {
        sn($mid, $row['userid'], $row['email'], 'N');
        exit();
    }
    else
    {
        ShowMsg("对不起,您的安全问题或答案回答错误","-1");
        exit();
    }
}

未设置安全问题的用户帐号的$row['safequestion']默认是为'0'(字符串),$row['safeanswer']

如果$safequestion'0',则empty($safequestion)为真。

如果$safequestion'0.0',则empty($safequestion)为假。

如果我们传入'0.0',则会顺利执行sn()函数。

跟进函数sn

function sn($mid,$userid,$mailto, $send = 'Y')
{
    global $db;
    $tptim= (60*10);
    $dtime = time();
    $sql = "SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'";
    $row = $db->GetOne($sql);
    if(!is_array($row))
    {
        //发送新邮件;
        newmail($mid,$userid,$mailto,'INSERT',$send);
    }
    //10分钟后可以再次发送新验证码;
    elseif($dtime - $tptim > $row['mailtime'])
    {
        newmail($mid,$userid,$mailto,'UPDATE',$send);
    }
    //重新发送新的验证码确认邮件;
    else
    {
        return ShowMsg('对不起,请10分钟后再重新申请', 'login.php');
    }
}

这里从数据库取出来的值应该为空$sql = "SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'";于是进入

if(!is_array($row))
    {
        //发送新邮件;
        newmail($mid,$userid,$mailto,'INSERT',$send);
}

注意一下$sendN

我们跟进newmail函数:

function newmail($mid, $userid, $mailto, $type, $send)
{
    global $db,$cfg_adminemail,$cfg_webname,$cfg_basehost,$cfg_memberurl;
    $mailtime = time();
    $randval = random(8);
    $mailtitle = $cfg_webname.":密码修改";
    $mailto = $mailto;
    $headers = "From: ".$cfg_adminemail."\r\nReply-To: $cfg_adminemail";
    $mailbody = "亲爱的".$userid.":\r\n您好!感谢您使用".$cfg_webname."网。\r\n".$cfg_webname."应您的要求,重新设置密码:(注:如果您没有提出申请,请检查您的信息是否泄漏。)\r\n本次临时登陆密码为:".$randval." 请于三天内登陆下面网址确认修改。\r\n".$cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid;
    if($type == 'INSERT')
    {
        $key = md5($randval);
        $sql = "INSERT INTO `#@__pwd_tmp` (`mid` ,`membername` ,`pwd` ,`mailtime`)VALUES ('$mid', '$userid',  '$key', '$mailtime');";
        if($db->ExecuteNoneQuery($sql))
        {
            if($send == 'Y')
            {
                sendmail($mailto,$mailtitle,$mailbody,$headers);
                return ShowMsg('EMAIL修改验证码已经发送到原来的邮箱请查收', 'login.php','','5000');
            } else if ($send == 'N')
            {
                return ShowMsg('稍后跳转到修改页', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&amp;id=".$mid."&amp;key=".$randval);
            }
        }
        else
        {
            return ShowMsg('对不起修改失败,请联系管理员', 'login.php');
        }
}

这里直接是对dede_pwd_tmp表插入临时密码,临时密码为$randval = random(8);是8位,紧接着插入完成之后ShowMsg('稍后跳转到修改页', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);也就是说在insert完成之后跳转到了修改密码的页面,然后就可以修改密码了。

复现过程

1.配置dedecms
  1. 解压DedecmsV53-UTF8-Final并移入网站根目录。

  2. 打开首页,根据指引完成网站初始化。

    http://localhost/DedecmsV53-UTF8-Final/upload/
    
  3. 登录后台,并开启会员模块(5.3版本默认打开)。

    http://localhost/DedecmsV53-UTF8-Final/upload/dede/
    

在这里插入图片描述

2.注册会员

注册测hacker账号aaaaa,并且设置安全问题。

注册victim账号bbbbb,不设置安全问题。

在这里插入图片描述

3.找回密码

hacker用自己的账号通过安全问题找回密码

在这里插入图片描述

4.burpsuite抓包

开启代理,然后提交

用burpsuite抓包,并send to repeater

在这里插入图片描述

在这里插入图片描述

5.修改数据并发包

将id改为受害者id

userid不用管,这个参数并没有什么用

将safequestion设置成0.0

GO

查看返回数据,打开那个特别显眼链接

在这里插入图片描述

6.打开链接

这是怎么回事?

在这里插入图片描述

7.检查错误

参数中出现了奇怪的&amp;

其实这是&的url编码,直接提交会把&amp;再次编码

故将&amp;改成&即可

在这里插入图片描述

8.修改密码

在这里插入图片描述

漏洞复现完毕,感谢各位师傅阅读。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rpsate

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值