每天学习一点点,成功增加一大步

如何绕开discuz的登录验证

PHP zhanghui 2351℃

最近,我接手一个研究性的任务,就是通过钉钉的企业应用能直接登录公司的论坛,公司的论坛系统用的是 discuz 。discuz 是我很久以前还是在校生把玩的东西,自从离校就业后就几乎没有关注 discuz 了,都是在围绕着公司的所需开发独立的项目。虽然这次的研究没有完全性的解决,但还是让我有点小成果就是【如何绕开discuz的登录验证】。

我测验的 我测验的 discuz 的版本是 X3.x,通过网搜到参考信息和自己的探索得出了以下的解决途径。

通过了解 discuz 的目录框架知道了menber 是处理用户信息的入口,然后顺藤摸瓜确定class_member.php的on_login()函数是用来处理登录的函数。利用showmessage()函数来作为断点判断它运行到哪一步,这样就能很好地了解它的运行逻辑了。代码如下:自己对比源代码(discuzX3.x)找亮点

function on_login() {
		global $_G;
		if($_G['uid']) {
			$referer = dreferer();
			$ucsynlogin = $this->setting['allowsynlogin'] ? uc_user_synlogin($_G['uid']) : '';
			$param = array('username' => $_G['member']['username'], 'usergroup' => $_G['group']['grouptitle'], 'uid' => $_G['member']['uid']);
			showmessage('login_succeed', $referer ? $referer : './', $param, array('showdialog' => 1, 'locationtime' => true, 'extrajs' => $ucsynlogin));
		}

		list($seccodecheck) = seccheck('login');
		if(!empty($_GET['auth'])) {
			$dauth = authcode($_GET['auth'], 'DECODE', $_G['config']['security']['authkey']);
			list(,,,$secchecklogin2) = explode("\t", $dauth);
			if($secchecklogin2) {
				$seccodecheck = true;
			}
		}
		$seccodestatus = !empty($_GET['lssubmit']) ? false : $seccodecheck;
		$invite = getinvite();

		if(!submitcheck('loginsubmit', 1, $seccodestatus) && $_GET['app'] != "ding") {
//            showmessage("loginsubmit");

			$auth = '';
			$username = !empty($_G['cookie']['loginuser']) ? dhtmlspecialchars($_G['cookie']['loginuser']) : '';

			if(!empty($_GET['auth'])) {
				list($username, $password, $questionexist) = explode("\t", authcode($_GET['auth'], 'DECODE', $_G['config']['security']['authkey']));
				$username = dhtmlspecialchars($username);
				$auth = dhtmlspecialchars($_GET['auth']);
			}

			$cookietimecheck = !empty($_G['cookie']['cookietime']) || !empty($_GET['cookietime']) ? 'checked="checked"' : '';

			if($seccodecheck) {
				$seccode = random(6, 1) + $seccode{0} * 1000000;
			}

			if($this->extrafile && file_exists($this->extrafile)) {
				require_once $this->extrafile;
			}

			$navtitle = lang('core', 'title_login');
			include template($this->template);

		} else {
//            showmessage("22");

            //钉钉登录的处理函数在这里----------------------------------------------
            if ($_GET['app'] == "ding" && $_GET['ding_uid'] > 0) {
//                showmessage("into1");
                //--------------------------------------------
                $result = userlogin1($_GET['ding_uid']);
            } elseif ($_GET['app'] == "ding" && !empty($_GET['ding_username'])) {
//                showmessage('username');
                $result = userlogin2($_GET['ding_username']);
//                print_r($result); exit();
            } else {
                showmessage("33");
                // 如果不是
                if(!empty($_GET['auth'])) {
                    list($_GET['username'], $_GET['password']) = daddslashes(explode("\t", authcode($_GET['auth'], 'DECODE', $_G['config']['security']['authkey'])));
                }

                $loginhash = !empty($_GET['loginhash']) && preg_match('/^\w+$/', $_GET['loginhash']) ? $_GET['loginhash'] : '';

                if(!($_G['member_loginperm'] = logincheck($_GET['username']))) {
                    captcha::report($_G['clientip']);
                    showmessage('login_strike');
                }
                if($_GET['fastloginfield']) {
                    $_GET['loginfield'] = $_GET['fastloginfield'];
                }
                $_G['uid'] = $_G['member']['uid'] = 0;
                $_G['username'] = $_G['member']['username'] = $_G['member']['password'] = '';
                if(!$_GET['password'] || $_GET['password'] != addslashes($_GET['password'])) {
                    showmessage('profile_passwd_illegal');
                }
                $result = userlogin($_GET['username'], $_GET['password'], $_GET['questionid'], $_GET['answer'], $this->setting['autoidselect'] ? 'auto' : $_GET['loginfield'], $_G['clientip']);
            }
            $uid = $result['ucresult']['uid'];

            if(!empty($_GET['lssubmit']) && ($result['ucresult']['uid'] == -3 || $seccodecheck)) {
				$_GET['username'] = $result['ucresult']['username'];
				$this->logging_more($result['ucresult']['uid'] == -3);
			}

			if($result['status'] == -1) {
				if(!$this->setting['fastactivation']) {
					$auth = authcode($result['ucresult']['username']."\t".FORMHASH, 'ENCODE');
					showmessage('location_activation', 'member.php?mod='.$this->setting['regname'].'&action=activation&auth='.rawurlencode($auth).'&referer='.rawurlencode(dreferer()), array(), array('location' => true));
				} else {
					$init_arr = explode(',', $this->setting['initcredits']);
					$groupid = $this->setting['regverify'] ? 8 : $this->setting['newusergroupid'];

					C::t('common_member')->insert($uid, $result['ucresult']['username'], md5(random(10)), $result['ucresult']['email'], $_G['clientip'], $groupid, $init_arr);
					$result['member'] = getuserbyuid($uid);
					$result['status'] = 1;
				}
			}

			if($result['status'] > 0) {

				if($this->extrafile && file_exists($this->extrafile)) {
					require_once $this->extrafile;
				}

				setloginstatus($result['member'], $_GET['cookietime'] ? 2592000 : 0);
				checkfollowfeed();
				if($_G['group']['forcelogin']) {
					if($_G['group']['forcelogin'] == 1) {
						clearcookies();
						showmessage('location_login_force_qq');
					} elseif($_G['group']['forcelogin'] == 2 && $_GET['loginfield'] != 'email') {
						clearcookies();
						showmessage('location_login_force_mail');
					}
				}

				if($_G['member']['lastip'] && $_G['member']['lastvisit']) {
					dsetcookie('lip', $_G['member']['lastip'].','.$_G['member']['lastvisit']);
				}
				C::t('common_member_status')->update($_G['uid'], array('lastip' => $_G['clientip'], 'port' => $_G['remoteport'], 'lastvisit' =>TIMESTAMP, 'lastactivity' => TIMESTAMP));
				$ucsynlogin = $this->setting['allowsynlogin'] ? uc_user_synlogin($_G['uid']) : '';

				$pwold = false;
				if($this->setting['strongpw'] && !$this->setting['pwdsafety']) {
					if(in_array(1, $this->setting['strongpw']) && !preg_match("/\d+/", $_GET['password'])) {
						$pwold = true;
					}
					if(in_array(2, $this->setting['strongpw']) && !preg_match("/[a-z]+/", $_GET['password'])) {
						$pwold = true;
					}
					if(in_array(3, $this->setting['strongpw']) && !preg_match("/[A-Z]+/", $_GET['password'])) {
						$pwold = true;
					}
					if(in_array(4, $this->setting['strongpw']) && !preg_match("/[^a-zA-z0-9]+/", $_GET['password'])) {
						$pwold = true;
					}
				}

				if($_G['member']['adminid'] != 1) {
					if($this->setting['accountguard']['loginoutofdate'] && $_G['member']['lastvisit'] && TIMESTAMP - $_G['member']['lastvisit'] > 90 * 86400) {
						C::t('common_member')->update($_G['uid'], array('freeze' => 2));
						C::t('common_member_validate')->insert(array(
							'uid' => $_G['uid'],
							'submitdate' => TIMESTAMP,
							'moddate' => 0,
							'admin' => '',
							'submittimes' => 1,
							'status' => 0,
							'message' => '',
							'remark' => '',
						), false, true);
						manage_addnotify('verifyuser');
						showmessage('location_login_outofdate', 'home.php?mod=spacecp&ac=profile&op=password&resend=1', array('type' => 1), array('showdialog' => true, 'striptags' => false, 'locationtime' => true));
					}

					if($this->setting['accountguard']['loginpwcheck'] && $pwold) {
						$freeze = $pwold;
						if($this->setting['accountguard']['loginpwcheck'] == 2 && $freeze) {
							C::t('common_member')->update($_G['uid'], array('freeze' => 1));
						}
					}
				}

				$seccheckrule = & $_G['setting']['seccodedata']['rule']['login'];
				if($seccheckrule['allow'] == 2) {
					if($seccheckrule['nolocal']) {
						require_once libfile('function/misc');
						$lastipConvert = process_ipnotice(convertip($_G['member']['lastip']));
						$nowipConvert = process_ipnotice(convertip($_G['clientip']));
						if($lastipConvert != $nowipConvert && stripos($lastipConvert, $nowipConvert) == false && stripos($nowipConvert, $lastipConvert) == false) {
							$seccodecheck = true;
						}
					}
					if(!$seccodecheck && $seccheckrule['pwsimple'] && $pwold) {
						$seccodecheck = true;
					}
					if(!$seccodecheck && $seccheckrule['outofday'] && $_G['member']['lastvisit'] && TIMESTAMP - $_G['member']['lastvisit'] > $seccheckrule['outofday'] * 86400) {
						$seccodecheck = true;
					}
					if(!$seccodecheck && $_G['member_loginperm'] < 4) {
						$seccodecheck = true;
					}
					if(!$seccodecheck && $seccheckrule['numiptry']) {
						$seccodecheck = failedipcheck($seccheckrule['numiptry'], $seccheckrule['timeiptry']);
					}
					if($seccodecheck && !$secchecklogin2) {
						clearcookies();
						$auth = authcode($_GET['username']."\t".$_GET['password']."\t".($_GET['questionid'] ? 1 : 0)."\t1", 'ENCODE', $_G['config']['security']['authkey']);
						$location = 'member.php?mod=logging&action=login&auth='.rawurlencode($auth).'&referer='.rawurlencode(dreferer()).(!empty($_GET['cookietime']) ? '&cookietime=1' : '');
						if(defined('IN_MOBILE')) {
							showmessage('login_seccheck2', $location);
						} else {
							$js = '<script type="text/javascript">location.href=\''.$location.'\'</script>';
							showmessage('login_seccheck2', '', array('type' => 1), array('extrajs' => $js));
						}
					}
				}

				if($invite['id']) {
					$result = C::t('common_invite')->count_by_uid_fuid($invite['uid'], $uid);
					if(!$result) {
						C::t('common_invite')->update($invite['id'], array('fuid'=>$uid, 'fusername'=>$_G['username']));
						updatestat('invite');
					} else {
						$invite = array();
					}
				}
				if($invite['uid']) {
					require_once libfile('function/friend');
					friend_make($invite['uid'], $invite['username'], false);
					dsetcookie('invite_auth', '');
					if($invite['appid']) {
						updatestat('appinvite');
					}
				}

				$param = array(
					'username' => $result['ucresult']['username'],
					'usergroup' => $_G['group']['grouptitle'],
					'uid' => $_G['member']['uid'],
					'groupid' => $_G['groupid'],
					'syn' => $ucsynlogin ? 1 : 0
				);

				$extra = array(
					'showdialog' => true,
					'locationtime' => true,
					'extrajs' => $ucsynlogin
				);

				if(!$freeze || !$this->setting['accountguard']['loginpwcheck']) {
					$loginmessage = $_G['groupid'] == 8 ? 'login_succeed_inactive_member' : 'login_succeed';
					$location = $invite || $_G['groupid'] == 8 ? 'home.php?mod=space&do=home' : dreferer();
				} else {
					$loginmessage = 'login_succeed_password_change';
					$location = 'home.php?mod=spacecp&ac=profile&op=password';
					$_GET['lssubmit'] = 0;
				}
				if(empty($_GET['handlekey']) || !empty($_GET['lssubmit'])) {
					if(defined('IN_MOBILE')) {
						showmessage($loginmessage, $location, $param, array('location' => true));
					} else {
						if(!empty($_GET['lssubmit'])) {
							if(!$ucsynlogin) {
								$extra['location'] = true;
							}
							showmessage($loginmessage, $location, $param, $extra);
						} else {
							$href = str_replace("'", "\'", $location);
							showmessage('location_login_succeed', $location, array(),
								array(
									'showid' => 'succeedmessage',
									'extrajs' => '<script type="text/javascript">'.
										'setTimeout("window.location.href =\''.$href.'\';", 3000);'.
										'$(\'succeedmessage_href\').href = \''.$href.'\';'.
										'$(\'main_message\').style.display = \'none\';'.
										'$(\'main_succeed\').style.display = \'\';'.
										'$(\'succeedlocation\').innerHTML = \''.lang('message', $loginmessage, $param).'\';</script>'.$ucsynlogin,
									'striptags' => false,
									'showdialog' => true
								)
							);
						}
					}
				} else {
					showmessage($loginmessage, $location, $param, $extra);
				}
			} else {
				$password = preg_replace("/^(.{".round(strlen($_GET['password']) / 4)."})(.+?)(.{".round(strlen($_GET['password']) / 6)."})$/s", "\\1***\\3", $_GET['password']);
				$errorlog = dhtmlspecialchars(
					TIMESTAMP."\t".
					($result['ucresult']['username'] ? $result['ucresult']['username'] : $_GET['username'])."\t".
					$password."\t".
					"Ques #".intval($_GET['questionid'])."\t".
					$_G['clientip']);
				writelog('illegallog', $errorlog);
				loginfailed($_GET['username']);
				failedip();
				$fmsg = $result['ucresult']['uid'] == '-3' ? (empty($_GET['questionid']) || $answer == '' ? 'login_question_empty' : 'login_question_invalid') : 'login_invalid';
				if($_G['member_loginperm'] > 1) {
					showmessage($fmsg, '', array('loginperm' => $_G['member_loginperm'] - 1));
				} elseif($_G['member_loginperm'] == -1) {
					showmessage('login_password_invalid');
				} else {
					showmessage('login_strike');
				}
			}

		}

	}

加上代码后,就可以用url访问:http://localhost/member.php?mod=logging&action=login&app=ding&ding_uid=1

ok!在浏览器直接输入url,成功登陆,退出再登录,成功!(注意:每次都要退出后再登录)

通过以上的例子,成功的绕开discuz的登录验证。那么用 username 或者 email 绕开好像也不难(前提是你熟悉discuz的数据库操作机制)。因为钉钉的接口获取的是userid的值(有可能是用户名或者是邮箱)。于是去找getuserbyusername()或者是getuserbyuseremail()的函数,你会发觉找不到,而在做上个例子时发现 getuserbyuid() 这个函数是通过 function_core.php 中加载的,在这里中却没有 getuserbyusername 和 getuserbyuseremail 这两个函数,于是乎想自己写,然后通过唯一有线索的 getuserbyuid 函数知道了 C::t(‘common_member_archive’)>fetch($uid);意思是从/source/class/table文件夹内的table_common_member_archive.php里面提取fetch的函数。通过它根据表来找,要获取用户的数据,那么就应该通过table_common_member.php,很惊奇地就会发现里面有fetch_by_username()函数,这下一切都迎刃而解!!


线索:

1.C::t(‘common_member_archive’)>fetch($uid);意思是从/source/class/table文件夹内的table_common_member_archive.php里面提取fetch的函数

 2.区table_common_member.php这个函数找相关函数

3.自己组合代码。

。。。。。。(继续折腾)

转载请注明:隨習筆記 » 如何绕开discuz的登录验证