野生大熊猫

记录一篇因客户操作失误导致后台无法登陆的bug
引:这边客户反映网站后台无法登陆,前端正常登录一、最初解决办法办法一凭借多年的经验,第一时间会想到的就是discu...
扫描右侧二维码阅读全文
03
2019/12

记录一篇因客户操作失误导致后台无法登陆的bug

引:这边客户反映网站后台无法登陆,前端正常登录

一、最初解决办法

办法一

凭借多年的经验,第一时间会想到的就是discuz默认的安全配置问题,于是去修改config_global.php文件中$_config['admincp']['checkip'] = 1;这个值,将其修改为0,这样discuz登录管理后台时就不会进行IP验证。

办法二

修改$_config'admincp' = 0;后发现还是未生效,登录依然失败,那么能想到的就是禁用了这个IP导致无法登陆,那么这个问题的解决方法其实更加简单,首先就是进入数据库之后,在 pre_common_setting 表中搜索 skey adminipaccess ,然后删除svalue中的值就搞定了。

办法三

这边两个法子都用了,还是没有任何反应,想想是不是管理密码记错了,于是登录前台测试,正常登录,提示新手上路欢迎您(这里留个坑),发现账号密码没有任何问题,可以进行登录。

TIM截图20191203225058.png

这里账号其实为admin,这边尽量为了把当时的情况反映出来。

二、分析其他原因

1.浏览器问题

可能是浏览器缓存或者是浏览器问题,于是清除缓存和更换浏览器无解。

2.服务器问题

服务器问题,设想一下,可能是php版本或者是Nginx服务器问题,于是这边检查一下同服务器的其他dz站点,没有任何问题,重启php和Nginx也无法得到解决

3.木马或者防火墙等安全软件

没办法,只能看看是不是当前程序被木马了,篡改了文件什么的。于是这边查看了一下文件夹和文件的时间没有问题。或者是服务器有安全软件防火墙,都检查了一遍,没有任何相关文件。

三、最终解决办法

能搜索的都查询了一遍,千篇一律,都是转载和抄袭,还有就是很古老的答案。于是我这边就想,dz后台究竟是怎么样一个登陆机制在里面?

1.admin.php入口

discuz是多入口mvc架构的程序,后台登录使用的就是admin.php作为入口然后根据不同的action进入不同的source/admincp/admincp_$action.php

TIM截图20191203230306.png

这边主要涉及登录进入的是admincp_login.php文件,其中登录提交参数的地址为admin.php,并且参数中用户名为admin_username,这个也可以直接在浏览器审查元素得到。

TIM截图20191203230656.png

2.函数check_user_login

得到这个参数有什么用?
我们全局搜索一下,发现这个在一个函数中发现了提交验证。
TIM截图20191203230823.png

跟踪一下代码

function check_user_login() {
    global $_G;
    $admin_username = isset($_POST['admin_username']) ? trim($_POST['admin_username']) : '';
    if($admin_username != '') {

        require_once libfile('function/member');
        if(logincheck($_POST['admin_username'])) {
            if((empty($_POST['admin_questionid']) || empty($_POST['admin_answer'])) && ($_G['config']['admincp']['forcesecques'] || $_G['group']['forcesecques'])) {
                $this->do_user_login();
            }
            $result = userlogin($_POST['admin_username'], $_POST['admin_password'], $_POST['admin_questionid'], $_POST['admin_answer'], 'username', $this->core->var['clientip']);
            if($result['status'] == 1) {
                $cpgroupid = C::t('common_admincp_member')->fetch($result['member']['uid']);
                $cpgroupid = $cpgroupid['uid'];
//这里是验证最重要的一步
//$result这个变量可以打印出来自己看看

                if($cpgroupid || $this->checkfounder($result['member'])) {
                    C::t('common_admincp_session')->insert(array(
                        'uid' =>$result['member']['uid'],
                        'adminid' =>$result['member']['adminid'],
                        'panel' =>$this->panel,
                        'dateline' => TIMESTAMP,
                        'ip' => $this->core->var['clientip'],
                        'errorcount' => -1), false, true);

                    setloginstatus($result['member'], 0);
                    dheader('Location: '.ADMINSCRIPT.'?'.cpurl('url', array('sid')));
                } else {
                    $this->cpaccess = -2;
                }
//验证结束
            } else {
                loginfailed($_POST['admin_username']);
            }
        } else {
            $this->cpaccess = -4;
        }
    }
}

3.函数checkfounder

当前函数中,最重要的其实是这一步。
这里发现还有一个函数,来进行验证是否写入session,这一步打印了一下,发现居然是false这就很奇怪了,怎么会这样呢?
于是继续跟踪代码,找到函数

function checkfounder($user) {

    $founders = str_replace(' ', '', $this->cpsetting['founder']);
var_dump($user);//打印$user
    if(!$user['uid'] || $user['groupid'] != 1 || $user['adminid'] != 1) {
        return false;
    } elseif(empty($founders)) {
        return true;
    } elseif(strexists(",$founders,", ",$user[uid],")) {
        return true;
    } elseif(!is_numeric($user['username']) && strexists(",$founders,", ",$user[username],")) {
        return true;
    } else {
        return FALSE;
    }
}

估计看到这个函数的小伙伴就发现了端倪。我们打印了一下$user,发现$user有几个重要的参数,uid、groupid、adminid,这三个值其中groupid并不等于1,它等于10,于是导致这个三个或判断一个为true整体为true

四、解决

知道原因以后要解决这个问题,于是找到数据库,pre_common_member,修改admin 的 groupid为1,1代表为管理员。
尝试登陆
完美解决~~

Last modification:December 3rd, 2019 at 11:20 pm
If you think my article is useful to you, please feel free to appreciate

One comment

  1. 今日新鲜事

    文章不错支持一下吧

Leave a Comment